From ba451ab7b2361dc65b18a85b7e50673e46603360 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 16 Jan 2021 12:55:47 +0100 Subject: [PATCH 01/86] improve failure messages of the CrawlerSelectorTextContains constraint --- .../Tests/Test/WebTestCaseTest.php | 4 ++-- .../Bundle/FrameworkBundle/composer.json | 2 +- .../Constraint/CrawlerSelectorTextContains.php | 17 ++++++++++++++--- .../CrawlerSelectorTextContainsTest.php | 15 +++++++++++---- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php index 50744192a9dfe..ff88b34007069 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php @@ -183,7 +183,7 @@ public function testAssertSelectorTextNotContains() { $this->getCrawlerTester(new Crawler('

Foo'))->assertSelectorTextNotContains('body > h1', 'Bar'); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('matches selector "body > h1" and does not have a node matching selector "body > h1" with content containing "Foo".'); + $this->expectExceptionMessage('matches selector "body > h1" and the text "Foo" of the node matching selector "body > h1" does not contain "Foo".'); $this->getCrawlerTester(new Crawler('

Foo'))->assertSelectorTextNotContains('body > h1', 'Foo'); } @@ -199,7 +199,7 @@ public function testAssertPageTitleContains() { $this->getCrawlerTester(new Crawler('Foobar'))->assertPageTitleContains('Foo'); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('matches selector "title" and has a node matching selector "title" with content containing "Bar".'); + $this->expectExceptionMessage('matches selector "title" and the text "Foo" of the node matching selector "title" contains "Bar".'); $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleContains('Bar'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index f592065b28cd7..d64e8e0390d62 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -38,7 +38,7 @@ "symfony/browser-kit": "^4.3|^5.0", "symfony/console": "^4.3.4|^5.0", "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/dom-crawler": "^4.3|^5.0", + "symfony/dom-crawler": "^4.4.20|^5.2.4", "symfony/dotenv": "^4.3.6|^5.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/form": "^4.3.5|^5.0", diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php index ffc6f5677cc5d..c4697ecf75376 100644 --- a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php @@ -18,6 +18,8 @@ final class CrawlerSelectorTextContains extends Constraint { private $selector; private $expectedText; + private $hasNode = false; + private $nodeText; public function __construct(string $selector, string $expectedText) { @@ -30,7 +32,11 @@ public function __construct(string $selector, string $expectedText) */ public function toString(): string { - return sprintf('has a node matching selector "%s" with content containing "%s"', $this->selector, $this->expectedText); + if ($this->hasNode) { + return sprintf('the text "%s" of the node matching selector "%s" contains "%s"', $this->nodeText, $this->selector, $this->expectedText); + } + + return sprintf('the Crawler has a node matching selector "%s"', $this->selector); } /** @@ -42,10 +48,15 @@ protected function matches($crawler): bool { $crawler = $crawler->filter($this->selector); if (!\count($crawler)) { + $this->hasNode = false; + return false; } - return false !== mb_strpos($crawler->text(null, true), $this->expectedText); + $this->hasNode = true; + $this->nodeText = $crawler->text(null, true); + + return false !== mb_strpos($this->nodeText, $this->expectedText); } /** @@ -55,6 +66,6 @@ protected function matches($crawler): bool */ protected function failureDescription($crawler): string { - return 'the Crawler '.$this->toString(); + return $this->toString(); } } diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php index b92a13187bd5f..0d7656e589b49 100644 --- a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php @@ -24,15 +24,22 @@ public function testConstraint() $constraint = new CrawlerSelectorTextContains('title', 'Foo'); $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>Foobar'), '', true)); $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head></head><body>Bar'), '', true)); try { $constraint->evaluate(new Crawler('<html><head><title>Bar')); - } catch (ExpectationFailedException $e) { - $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"title\" with content containing \"Foo\".\n", TestFailure::exceptionToString($e)); - return; + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the text \"Bar\" of the node matching selector \"title\" contains \"Foo\".\n", TestFailure::exceptionToString($e)); } - $this->fail(); + try { + $constraint->evaluate(new Crawler('<html><head></head><body>Bar')); + + $this->fail(); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"title\".\n", TestFailure::exceptionToString($e)); + } } } From 6fd21ce5aa8679f900e1ad059c78967cd83e79c9 Mon Sep 17 00:00:00 2001 From: Simon Heimberg <simon.heimberg@heimberg-ea.ch> Date: Fri, 9 Apr 2021 13:10:44 +0300 Subject: [PATCH 02/86] allow null for framework.translator.default_path Allow to configure framework.translator.default_path to null, as it was until symfony 3.4.x (fix BC compatibility). fixes #37111 --- .../DependencyInjection/FrameworkExtension.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 972c8f255f2d6..814e54042cd6e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1213,7 +1213,9 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths); } - if ($container->fileExists($defaultDir)) { + if (null === $defaultDir) { + // allow null + } elseif ($container->fileExists($defaultDir)) { $dirs[] = $defaultDir; } else { $nonExistingDirs[] = $defaultDir; From a1eb24bef2a773ca4fbaf135dae8fa33180d836a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Tue, 27 Jul 2021 20:45:36 +0200 Subject: [PATCH 03/86] Add test for non-callable arrays as controllers Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../Routing/Loader/Configurator/Traits/RouteTrait.php | 2 +- src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php | 4 +++- .../Component/Routing/Tests/Fixtures/php_object_dsl.php | 4 +++- .../Component/Routing/Tests/Loader/PhpFileLoaderTest.php | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php b/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php index 04009cd16d3a8..22df1af05469b 100644 --- a/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php +++ b/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php @@ -126,7 +126,7 @@ final public function methods(array $methods): self /** * Adds the "_controller" entry to defaults. * - * @param callable|string $controller a callable or parseable pseudo-callable + * @param callable|string|array $controller a callable or parseable pseudo-callable * * @return $this */ diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php b/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php index 86caa99696149..4208579476f68 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php @@ -9,7 +9,9 @@ ->condition('abc') ->options(['utf8' => true]) ->add('buz', 'zub') - ->controller('foo:act'); + ->controller('foo:act') + ->add('controller_class', '/controller') + ->controller(['Acme\MyApp\MyController', 'myAction']); $routes->import('php_dsl_sub.php') ->prefix('/sub') diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php b/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php index 9b9183a1b9427..6036dfd29ac08 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php @@ -11,7 +11,9 @@ public function __invoke(RoutingConfigurator $routes) ->condition('abc') ->options(['utf8' => true]) ->add('buz', 'zub') - ->controller('foo:act'); + ->controller('foo:act') + ->add('controller_class', '/controller') + ->controller(['Acme\MyApp\MyController', 'myAction']); $routes->import('php_dsl_sub.php') ->prefix('/sub') diff --git a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php index 70d45fc2383e8..f5f3a638e8067 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php @@ -174,6 +174,9 @@ public function testRoutingConfigurator() $expectedCollection->add('buz', (new Route('/zub')) ->setDefaults(['_controller' => 'foo:act']) ); + $expectedCollection->add('controller_class', (new Route('/controller')) + ->setDefaults(['_controller' => ['Acme\MyApp\MyController', 'myAction']]) + ); $expectedCollection->add('c_root', (new Route('/sub/pub/')) ->setRequirements(['id' => '\d+']) ); From 7388148f7df5e6cc270e5d7cfd07496344fef88b Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 08:44:49 +0200 Subject: [PATCH 04/86] Update CHANGELOG for 4.4.29 --- CHANGELOG-4.4.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index b1baa0f18dd9f..40d08340ad617 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,12 @@ in 4.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.4.0...v4.4.1 +* 4.4.29 (2021-07-29) + + * bug #42307 [Mailer] Fixed decode exception when sendgrid response is 202 (rubanooo) + * bug #42296 [Dotenv][Yaml] Remove PHP 8.0 polyfill (derrabus) + * bug #42289 [HttpFoundation] Fixed type mismatch (Toflar) + * 4.4.28 (2021-07-27) * bug #42270 [WebProfilerBundle] [WebProfiler] "empty" filter bugfix. Filter with name "empty" is not … (luzrain) From 5897a3ee4c93fe6c53b394ff29c2ece1dcb1cb92 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 08:44:58 +0200 Subject: [PATCH 05/86] Update CONTRIBUTORS for 4.4.29 --- CONTRIBUTORS.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8e58e8b338eb2..5c9b27862671f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -139,6 +139,7 @@ The Symfony Connect username in parenthesis allows to get more information - Włodzimierz Gajda (gajdaw) - Christian Scheb - Adrien Brault (adrienbrault) + - Yanick Witschi (toflar) - Julien Falque (julienfalque) - Jacob Dreesen (jdreesen) - Malte Schlüter (maltemaltesich) @@ -148,13 +149,12 @@ The Symfony Connect username in parenthesis allows to get more information - Colin Frei - Javier Spagnoletti (phansys) - Joshua Thijssen - - Yanick Witschi (toflar) + - HypeMC (hypemc) - Daniel Wehner (dawehner) - Tugdual Saunier (tucksaun) - excelwebzone - Gordon Franke (gimler) - Saif Eddin Gmati (azjezz) - - HypeMC (hypemc) - Jesse Rushlow (geeshoe) - Fabien Pennequin (fabienpennequin) - Théo FIDRY (theofidry) @@ -163,10 +163,12 @@ The Symfony Connect username in parenthesis allows to get more information - Eric GELOEN (gelo) - Matthieu Napoli (mnapoli) - Jannik Zschiesche (apfelbox) + - Mathieu Santostefano (welcomattic) - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) - Richard van Laak (rvanlaak) - Tigran Azatyan (tigranazatyan) + - YaFou - Gary PEGEOT (gary-p) - Gabriel Caruso (carusogabriel) - Stefano Sala (stefano.sala) @@ -184,12 +186,10 @@ The Symfony Connect username in parenthesis allows to get more information - Albert Casademont (acasademont) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) - - Mathieu Santostefano (welcomattic) - Smaine Milianni (ismail1432) - SpacePossum - Pablo Godel (pgodel) - Andreas Braun - - YaFou - Jérémie Augustin (jaugustin) - François-Xavier de Guillebon (de-gui_f) - Oleg Voronkovich @@ -291,6 +291,7 @@ The Symfony Connect username in parenthesis allows to get more information - sun (sun) - Larry Garfield (crell) - Edi Modrić (emodric) + - Roman Martinuk (a2a4) - Leo Feyer (leofeyer) - Nikolay Labinskiy (e-moe) - Martin Schuhfuß (usefulthink) @@ -330,7 +331,6 @@ The Symfony Connect username in parenthesis allows to get more information - Pascal Montoya - Julien Brochet (mewt) - Gocha Ossinkine (ossinkine) - - Roman Martinuk (a2a4) - Tristan Darricau (nicofuma) - Victor Bocharsky (bocharsky_bw) - Bozhidar Hristov (warxcell) @@ -453,6 +453,7 @@ The Symfony Connect username in parenthesis allows to get more information - Serkan Yildiz (srknyldz) - Andrew Moore (finewolf) - Bertrand Zuchuat (garfield-fr) + - Sébastien Alfaiate (seb33300) - Gabor Toth (tgabi333) - realmfoo - Thomas Tourlourat (armetiz) @@ -556,7 +557,6 @@ The Symfony Connect username in parenthesis allows to get more information - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) - Vyacheslav Salakhutdinov (megazoll) - - Sébastien Alfaiate (seb33300) - Phil Taylor (prazgod) - Hassan Amouhzi - Tamas Szijarto @@ -632,6 +632,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gunnstein Lye (glye) - Matthias Krauser (mkrauser) - Erkhembayar Gantulga (erheme318) + - Lorenzo Millucci (lmillucci) - Jérôme Tamarelle (jtamarelle-prismamedia) - Andrii Popov (andrii-popov) - Islam93 @@ -887,7 +888,6 @@ The Symfony Connect username in parenthesis allows to get more information - Julien Turby - Marvin Butkereit - Eduard Bulava (nonanerz) - - Lorenzo Millucci (lmillucci) - Renan - Ricky Su (ricky) - Igor Timoshenko (igor.timoshenko) @@ -1418,6 +1418,7 @@ The Symfony Connect username in parenthesis allows to get more information - Valérian Galliat - d-ph - Renan Taranto (renan-taranto) + - Adrien Chinour - Rikijs Murgs - Uladzimir Tsykun - Amaury Leroux de Lens (amo__) @@ -1710,6 +1711,7 @@ The Symfony Connect username in parenthesis allows to get more information - Nicolas Fabre (nfabre) - Raul Rodriguez (raul782) - Piet Steinhart + - mousezheng - mshavliuk - Rémy LESCALLIER - WybrenKoelmans @@ -2099,6 +2101,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andrei C. (moldman) - Povilas S. (povilas) - Laurent Negre (raulnet) + - Sergey Fokin (tyraelqp) - Evrard Boulou - pborreli - Boris Betzholz @@ -2796,6 +2799,7 @@ The Symfony Connect username in parenthesis allows to get more information - Benedict Massolle (bemas) - Gerard Berengue Llobera (bere) - Bernd Matzner (bmatzner) + - Anton (bonio) - Bram Tweedegolf (bram_tweedegolf) - Brandon Kelly (brandonkelly) - Choong Wei Tjeng (choonge) From 893f5f9a6e1e54ce32afec7a2520939abb086e14 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 08:45:05 +0200 Subject: [PATCH 06/86] Update VERSION for 4.4.29 --- 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 9ffc2a3ee49fd..321cca741b69d 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '4.4.29-DEV'; + public const VERSION = '4.4.29'; public const VERSION_ID = 40429; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 29; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From 11e76c9d1f0a9ff28a2673e2c4208efbe071503b Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 08:49:36 +0200 Subject: [PATCH 07/86] Bump Symfony version to 4.4.30 --- 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 321cca741b69d..7956190d279d6 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '4.4.29'; - public const VERSION_ID = 40429; + public const VERSION = '4.4.30-DEV'; + public const VERSION_ID = 40430; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 29; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 30; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From 0f01fb3891152f9daf3ebdaea06bfe10aad13792 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 08:52:10 +0200 Subject: [PATCH 08/86] Update CHANGELOG for 5.2.14 --- CHANGELOG-5.2.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG-5.2.md b/CHANGELOG-5.2.md index b3ee27e04730b..d5799da0cdfae 100644 --- a/CHANGELOG-5.2.md +++ b/CHANGELOG-5.2.md @@ -7,6 +7,12 @@ in 5.2 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.2.0...v5.2.1 +* 5.2.14 (2021-07-29) + + * bug #42307 [Mailer] Fixed decode exception when sendgrid response is 202 (rubanooo) + * bug #42296 [Dotenv][Yaml] Remove PHP 8.0 polyfill (derrabus) + * bug #42289 [HttpFoundation] Fixed type mismatch (Toflar) + * 5.2.13 (2021-07-27) * bug #42270 [WebProfilerBundle] [WebProfiler] "empty" filter bugfix. Filter with name "empty" is not … (luzrain) From 8ba9c9702862e3edd981a6a07c704c49b7092c9d Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 08:52:15 +0200 Subject: [PATCH 09/86] Update VERSION for 5.2.14 --- src/Symfony/Component/HttpKernel/Kernel.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 2d3bd723e864f..76b24a7cf0348 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -74,11 +74,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '5.2.13'; - public const VERSION_ID = 50213; + public const VERSION = '5.2.14'; + public const VERSION_ID = 50214; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 2; - public const RELEASE_VERSION = 13; + public const RELEASE_VERSION = 14; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '07/2021'; From b20b74d720b84a0d1d8503530f437fb239dd35dd Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 29 Jul 2021 09:19:11 +0200 Subject: [PATCH 10/86] Bump Symfony version to 5.3.7 --- 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 0d0332d21703f..98bcb7d780a1e 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.6'; - public const VERSION_ID = 50306; + public const VERSION = '5.3.7-DEV'; + public const VERSION_ID = 50307; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 3; - public const RELEASE_VERSION = 6; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 7; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2022'; public const END_OF_LIFE = '01/2022'; From c7442cb8102ae302b52e489069131a45304939fa Mon Sep 17 00:00:00 2001 From: Peter Potrowl <peter.potrowl@gmail.com> Date: Thu, 29 Jul 2021 16:09:35 +0200 Subject: [PATCH 11/86] [PasswordHasher] Fix usage of PasswordHasherAdapter in PasswordHasherFactory --- .../Hasher/PasswordHasherFactory.php | 25 +++++++++++-------- .../Hasher/PasswordHasherFactoryTest.php | 23 +++++++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php b/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php index a2f24224744aa..dd7e015c1ecd2 100644 --- a/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php +++ b/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php @@ -61,14 +61,7 @@ public function getPasswordHasher($user): PasswordHasherInterface throw new \RuntimeException(sprintf('No password hasher has been configured for account "%s".', \is_object($user) ? get_debug_type($user) : $user)); } - if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) { - $this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface - ? new PasswordHasherAdapter($this->passwordHashers[$hasherKey]) - : $this->createHasher($this->passwordHashers[$hasherKey]) - ; - } - - return $this->passwordHashers[$hasherKey]; + return $this->createHasherUsingAdapter($hasherKey); } /** @@ -111,6 +104,18 @@ private function createHasher(array $config, bool $isExtra = false): PasswordHas return new MigratingPasswordHasher($hasher, ...$extrapasswordHashers); } + private function createHasherUsingAdapter(string $hasherKey): PasswordHasherInterface + { + if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) { + $this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface + ? new PasswordHasherAdapter($this->passwordHashers[$hasherKey]) + : $this->createHasher($this->passwordHashers[$hasherKey]) + ; + } + + return $this->passwordHashers[$hasherKey]; + } + private function getHasherConfigFromAlgorithm(array $config): array { if ('auto' === $config['algorithm']) { @@ -142,8 +147,8 @@ private function getHasherConfigFromAlgorithm(array $config): array $hasherChain = [$this->createHasher($config, true)]; foreach ($frompasswordHashers as $name) { - if ($hasher = $this->passwordHashers[$name] ?? false) { - $hasher = $hasher instanceof PasswordHasherInterface ? $hasher : $this->createHasher($hasher, true); + if (isset($this->passwordHashers[$name])) { + $hasher = $this->createHasherUsingAdapter($name); } else { $hasher = $this->createHasher(['algorithm' => $name], true); } diff --git a/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php b/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php index 1f8fcb3e79531..1f24a0d3cace2 100644 --- a/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php +++ b/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php @@ -163,6 +163,29 @@ public function testMigrateFrom() $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null)); } + /** + * @group legacy + */ + public function testMigrateFromLegacy() + { + if (!SodiumPasswordHasher::isSupported()) { + $this->markTestSkipped('Sodium is not available'); + } + + $factory = new PasswordHasherFactory([ + 'plaintext_encoder' => $plaintext = new PlaintextPasswordEncoder(), + SomeUser::class => ['algorithm' => 'sodium', 'migrate_from' => ['bcrypt', 'plaintext_encoder']], + ]); + + $hasher = $factory->getPasswordHasher(SomeUser::class); + $this->assertInstanceOf(MigratingPasswordHasher::class, $hasher); + + $this->assertTrue($hasher->verify((new SodiumPasswordHasher())->hash('foo', null), 'foo', null)); + $this->assertTrue($hasher->verify((new NativePasswordHasher(null, null, null, \PASSWORD_BCRYPT))->hash('foo', null), 'foo', null)); + $this->assertTrue($hasher->verify($plaintext->encodePassword('foo', null), 'foo', null)); + $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null)); + } + public function testDefaultMigratingHashers() { $this->assertInstanceOf( From fbaf499d1e59e5e4aea61d73b298647a537fb4df Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@qossmic.com> Date: Fri, 30 Jul 2021 10:55:43 +0200 Subject: [PATCH 12/86] remove 5.2 branch from PR template --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 84dd98f43ad2b..62662f876fd3a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 5.4 for features / 4.4, 5.2 or 5.3 for bug fixes <!-- see below --> +| Branch? | 5.4 for features / 4.4 or 5.3 for bug fixes <!-- see below --> | Bug fix? | yes/no | New feature? | yes/no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | yes/no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> From 28ae62d037f44ecb2ca84cb9a90a8d9a64c6c7be Mon Sep 17 00:00:00 2001 From: Bob van de Vijver <bobvandevijver@hotmail.com> Date: Thu, 29 Jul 2021 11:16:12 +0200 Subject: [PATCH 13/86] [Security] Fix str_contains type mismatch in ChannelListener --- .../Http/Firewall/ChannelListener.php | 2 +- .../Tests/Firewall/ChannelListenerTest.php | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php b/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php index b357564864cd0..71459406614ab 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php @@ -51,7 +51,7 @@ public function supports(Request $request): ?bool if (null !== $this->logger) { if ('https' === $request->headers->get('X-Forwarded-Proto')) { $this->logger->info('Redirecting to HTTPS. ("X-Forwarded-Proto" header is set to "https" - did you set "trusted_proxies" correctly?)'); - } elseif (str_contains($request->headers->get('Forwarded'), 'proto=https')) { + } elseif (str_contains($request->headers->get('Forwarded', ''), 'proto=https')) { $this->logger->info('Redirecting to HTTPS. ("Forwarded" header is set to "proto=https" - did you set "trusted_proxies" correctly?)'); } else { $this->logger->info('Redirecting to HTTPS.'); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ChannelListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ChannelListenerTest.php index 5fab54c13227d..0153d30395d9c 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ChannelListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ChannelListenerTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Security\Http\Tests\Firewall; use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; +use Symfony\Component\HttpFoundation\HeaderBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\RequestEvent; @@ -153,4 +155,29 @@ public function testHandleWithSecuredRequestAndHttpChannel() $this->assertSame($response, $event->getResponse()); } + + public function testSupportsWithoutHeaders() + { + $request = $this->createMock(Request::class); + $request + ->expects($this->any()) + ->method('isSecure') + ->willReturn(false) + ; + $request->headers = new HeaderBag(); + + $accessMap = $this->createMock(AccessMapInterface::class); + $accessMap + ->expects($this->any()) + ->method('getPatterns') + ->with($this->equalTo($request)) + ->willReturn([[], 'https']) + ; + + $entryPoint = $this->createMock(AuthenticationEntryPointInterface::class); + + $listener = new ChannelListener($accessMap, $entryPoint, new NullLogger()); + + $this->assertTrue($listener->supports($request)); + } } From 705f76571d586e7af8128fbf622c7d0435391f33 Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@qossmic.com> Date: Mon, 19 Jul 2021 11:58:14 +0200 Subject: [PATCH 14/86] always close open stopwatch section after handling kernel.request events --- .../Debug/TraceableEventDispatcher.php | 19 ++++++++++--------- .../Debug/TraceableEventDispatcherTest.php | 16 +++++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php index ce4ddb35d3f75..832bfb58d0637 100644 --- a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php @@ -30,6 +30,7 @@ protected function beforeDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::REQUEST: + $event->getRequest()->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $this->stopwatch->openSection(); break; case KernelEvents::VIEW: @@ -40,8 +41,8 @@ protected function beforeDispatch(string $eventName, $event) } break; case KernelEvents::TERMINATE: - $token = $event->getResponse()->headers->get('X-Debug-Token'); - if (null === $token) { + $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); + if (null === $sectionId) { break; } // There is a very special case when using built-in AppCache class as kernel wrapper, in the case @@ -50,7 +51,7 @@ protected function beforeDispatch(string $eventName, $event) // is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception // which must be caught. try { - $this->stopwatch->openSection($token); + $this->stopwatch->openSection($sectionId); } catch (\LogicException $e) { } break; @@ -67,21 +68,21 @@ protected function afterDispatch(string $eventName, $event) $this->stopwatch->start('controller', 'section'); break; case KernelEvents::RESPONSE: - $token = $event->getResponse()->headers->get('X-Debug-Token'); - if (null === $token) { + $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); + if (null === $sectionId) { break; } - $this->stopwatch->stopSection($token); + $this->stopwatch->stopSection($sectionId); break; case KernelEvents::TERMINATE: // In the special case described in the `preDispatch` method above, the `$token` section // does not exist, then closing it throws an exception which must be caught. - $token = $event->getResponse()->headers->get('X-Debug-Token'); - if (null === $token) { + $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); + if (null === $sectionId) { break; } try { - $this->stopwatch->stopSection($token); + $this->stopwatch->stopSection($sectionId); } catch (\LogicException $e) { } break; diff --git a/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php index 2fb050dafd9f9..90ea544b1abe2 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php @@ -28,12 +28,12 @@ class TraceableEventDispatcherTest extends TestCase public function testStopwatchSections() { $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch = new Stopwatch()); - $kernel = $this->getHttpKernel($dispatcher, function () { return new Response('', 200, ['X-Debug-Token' => '292e1e']); }); + $kernel = $this->getHttpKernel($dispatcher); $request = Request::create('/'); $response = $kernel->handle($request); $kernel->terminate($request, $response); - $events = $stopwatch->getSectionEvents($response->headers->get('X-Debug-Token')); + $events = $stopwatch->getSectionEvents($request->attributes->get('_stopwatch_token')); $this->assertEquals([ '__section__', 'kernel.request', @@ -56,7 +56,7 @@ public function testStopwatchCheckControllerOnRequestEvent() $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch); - $kernel = $this->getHttpKernel($dispatcher, function () { return new Response(); }); + $kernel = $this->getHttpKernel($dispatcher); $request = Request::create('/'); $kernel->handle($request); } @@ -69,12 +69,12 @@ public function testStopwatchStopControllerOnRequestEvent() $stopwatch->expects($this->once()) ->method('isStarted') ->willReturn(true); - $stopwatch->expects($this->once()) + $stopwatch->expects($this->exactly(3)) ->method('stop'); $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch); - $kernel = $this->getHttpKernel($dispatcher, function () { return new Response(); }); + $kernel = $this->getHttpKernel($dispatcher); $request = Request::create('/'); $kernel->handle($request); } @@ -110,10 +110,12 @@ public function testListenerCanRemoveItselfWhenExecuted() $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); } - protected function getHttpKernel($dispatcher, $controller) + protected function getHttpKernel($dispatcher) { $controllerResolver = $this->createMock(ControllerResolverInterface::class); - $controllerResolver->expects($this->once())->method('getController')->willReturn($controller); + $controllerResolver->expects($this->once())->method('getController')->willReturn(function () { + return new Response(); + }); $argumentResolver = $this->createMock(ArgumentResolverInterface::class); $argumentResolver->expects($this->once())->method('getArguments')->willReturn([]); From 4df1173b747adadc4cb26fbfa016e0245445af4f Mon Sep 17 00:00:00 2001 From: Oskar Stark <oskarstark@googlemail.com> Date: Sun, 1 Aug 2021 16:25:20 +0200 Subject: [PATCH 15/86] [Mailer][Sendgrid] Add previous exception --- .../Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php index 0134a6ff5ef7f..07108f19aab3c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php @@ -64,7 +64,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e throw new HttpTransportException('Unable to send an email: '.implode('; ', array_column($result['errors'], 'message')).sprintf(' (code %d).', $statusCode), $response); } catch (DecodingExceptionInterface $e) { - throw new HttpTransportException('Unable to send an email: '.$response->getContent(false).sprintf(' (code %d).', $statusCode), $response); + throw new HttpTransportException('Unable to send an email: '.$response->getContent(false).sprintf(' (code %d).', $statusCode), $response, 0, $e); } } From fb15542ecf6550de87d9bb772563e05ce8f7a65b Mon Sep 17 00:00:00 2001 From: Gocha Ossinkine <ossinkine@ya.ru> Date: Sun, 1 Aug 2021 21:24:46 +0500 Subject: [PATCH 16/86] [Validator] Update MIR card scheme --- .../Component/Validator/Constraints/CardSchemeValidator.php | 4 ++-- .../Validator/Tests/Constraints/CardSchemeValidatorTest.php | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index 478047fb8f272..a63366f51a0a1 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -77,9 +77,9 @@ class CardSchemeValidator extends ConstraintValidator '/^5[1-5][0-9]{14}$/', '/^2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12})$/', ], - // Payment system MIR numbers start with 220, then 1 digit from 0 to 4, then 12 digits + // Payment system MIR numbers start with 220, then 1 digit from 0 to 4, then between 12 and 15 digits 'MIR' => [ - '/^220[0-4][0-9]{12}$/', + '/^220[0-4][0-9]{12,15}$/', ], // All UATP card numbers start with a 1 and have a length of 15 digits. 'UATP' => [ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index ddc9edb6c094d..de1850eafb39f 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -104,6 +104,9 @@ public function getValidNumbers() ['MASTERCARD', '2709999999999999'], ['MASTERCARD', '2720995105105100'], ['MIR', '2200381427330082'], + ['MIR', '22003814273300821'], + ['MIR', '220038142733008212'], + ['MIR', '2200381427330082123'], ['UATP', '110165309696173'], ['VISA', '4111111111111111'], ['VISA', '4012888888881881'], @@ -136,7 +139,8 @@ public function getInvalidNumbers() ['MASTERCARD', '2721001234567890', CardScheme::INVALID_FORMAT_ERROR], // Not assigned yet ['MASTERCARD', '2220991234567890', CardScheme::INVALID_FORMAT_ERROR], // Not assigned yet ['UATP', '11016530969617', CardScheme::INVALID_FORMAT_ERROR], // invalid length - ['MIR', '22003814273300821', CardScheme::INVALID_FORMAT_ERROR], // invalid length + ['MIR', '220038142733008', CardScheme::INVALID_FORMAT_ERROR], // invalid length + ['MIR', '22003814273300821234', CardScheme::INVALID_FORMAT_ERROR], // invalid length ]; } } From b663ea357155e3a41423845d4d2a10ebf9336bb1 Mon Sep 17 00:00:00 2001 From: dlorek <lorekd07d@gmail.com> Date: Sat, 10 Jul 2021 23:26:25 +0200 Subject: [PATCH 17/86] notifier smsapi - fixed checking whether message is sent --- .../Bridge/Smsapi/SmsapiTransport.php | 11 ++++-- .../Smsapi/Tests/SmsapiTransportTest.php | 39 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php index dee0ce5d324e8..af05c13220e9d 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php @@ -18,6 +18,7 @@ use Symfony\Component\Notifier\Message\SmsMessage; use Symfony\Component\Notifier\Transport\AbstractTransport; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -72,10 +73,14 @@ protected function doSend(MessageInterface $message): SentMessage throw new TransportException('Could not reach the remote Smsapi server.', $response, 0, $e); } - if (200 !== $statusCode) { - $error = $response->toArray(false); + try { + $content = $response->toArray(false); + } catch (DecodingExceptionInterface $e) { + throw new TransportException('Could not decode body to an array.', $response, 0, $e); + } - throw new TransportException(sprintf('Unable to send the SMS: "%s".', $error['message']), $response); + if ((isset($content['error']) && null !== $content['error']) || (200 !== $statusCode)) { + throw new TransportException(sprintf('Unable to send the SMS: "%s".', $content['message'] ?? 'unknown error'), $response); } return new SentMessage($message, (string) $this); diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php index 615d55de6b33b..3af790460bf28 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php @@ -11,7 +11,10 @@ namespace Symfony\Component\Notifier\Bridge\Smsapi\Tests; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\Notifier\Bridge\Smsapi\SmsapiTransport; +use Symfony\Component\Notifier\Exception\TransportException; use Symfony\Component\Notifier\Message\ChatMessage; use Symfony\Component\Notifier\Message\MessageInterface; use Symfony\Component\Notifier\Message\SmsMessage; @@ -44,4 +47,40 @@ public function unsupportedMessagesProvider(): iterable yield [new ChatMessage('Hello!')]; yield [$this->createMock(MessageInterface::class)]; } + + public function createClient(int $statusCode, string $content): HttpClientInterface + { + return new MockHttpClient(new MockResponse($content, ['http_code' => $statusCode])); + } + + public function responseProvider(): iterable + { + $responses = [ + ['status' => 200, 'content' => '{"error":101,"message":"Authorization failed"}', 'errorMessage' => 'Unable to send the SMS: "Authorization failed".'], + ['status' => 500, 'content' => '{}', 'errorMessage' => 'Unable to send the SMS: "unknown error".'], + ['status' => 500, 'content' => '{"error":null,"message":"Unknown"}', 'errorMessage' => 'Unable to send the SMS: "Unknown".'], + ['status' => 500, 'content' => '{"error":null,"message":null}', 'errorMessage' => 'Unable to send the SMS: "unknown error".'], + ['status' => 500, 'content' => 'Internal error', 'errorMessage' => 'Could not decode body to an array.'], + ['status' => 200, 'content' => 'Internal error', 'errorMessage' => 'Could not decode body to an array.'], + ]; + + foreach ($responses as $response) { + yield [$response['status'], $response['content'], $response['errorMessage']]; + } + } + + /** + * @dataProvider responseProvider + */ + public function testThrowExceptionWhenMessageWasNotSent(int $statusCode, string $content, string $errorMessage) + { + $client = $this->createClient($statusCode, $content); + $transport = $this->createTransport($client); + $message = new SmsMessage('0611223344', 'Hello!'); + + $this->expectException(TransportException::class); + $this->expectExceptionMessage($errorMessage); + + $transport->send($message); + } } From 75addf1e5370ea6f934c85fa02e963edb0d0d2b5 Mon Sep 17 00:00:00 2001 From: Martin Herndl <martin@herndl.org> Date: Wed, 28 Jul 2021 10:18:49 +0200 Subject: [PATCH 18/86] Remove time-sensitivity from LoginLinkHandlerTest --- .../Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php index 877e1b62bdb57..767f553bf4d55 100644 --- a/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/LoginLink/LoginLinkHandlerTest.php @@ -53,7 +53,6 @@ protected function setUp(): void /** * @dataProvider provideCreateLoginLinkData - * @group time-sensitive */ public function testCreateLoginLink($user, array $extraProperties, Request $request = null) { @@ -65,8 +64,10 @@ public function testCreateLoginLink($user, array $extraProperties, Request $requ return 'weaverryan' == $parameters['user'] && isset($parameters['expires']) && isset($parameters['hash']) + // allow a small expiration offset to avoid time-sensitivity + && abs(time() + 600 - $parameters['expires']) <= 1 // make sure hash is what we expect - && $parameters['hash'] === $this->createSignatureHash('weaverryan', time() + 600, array_values($extraProperties)); + && $parameters['hash'] === $this->createSignatureHash('weaverryan', $parameters['expires'], array_values($extraProperties)); }), UrlGeneratorInterface::ABSOLUTE_URL ) From 499df3d805f315b5beff767a7a60b2235f8743cf Mon Sep 17 00:00:00 2001 From: Soner Sayakci <s.sayakci@shopware.com> Date: Mon, 2 Aug 2021 18:05:51 +0200 Subject: [PATCH 19/86] Fix ServiceLocator indexing when service is decorated --- .../Compiler/PassConfig.php | 2 +- .../Compiler/ServiceLocatorTagPassTest.php | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 12d3b26f740df..47f51c2478940 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -62,10 +62,10 @@ public function __construct() new AutowireRequiredMethodsPass(), new AutowireRequiredPropertiesPass(), new ResolveBindingsPass(), - new DecoratorServicePass(), new CheckDefinitionValidityPass(), new AutowirePass(false), new ServiceLocatorTagPass(), + new DecoratorServicePass(), new ResolveTaggedIteratorArgumentPass(), new ResolveServiceSubscribersPass(), new ResolveReferencesToAliasesPass(), diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php index 25063d35ff3b5..24088fe0f504a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php @@ -13,8 +13,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Argument\BoundArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceLocator; @@ -143,4 +146,56 @@ public function testBindingsAreCopied() $this->assertSame(['foo'], array_keys($locator->getBindings())); $this->assertInstanceOf(BoundArgument::class, $locator->getBindings()['foo']); } + + public function testIndexedByServiceIdWithDecoration() + { + $container = new ContainerBuilder(); + + $locator = new Definition(Locator::class); + $locator->setPublic(true); + $locator->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('test_tag', null, null, true))); + + $container->setDefinition(Locator::class, $locator); + + $service = new Definition(Service::class); + $service->setPublic(true); + $service->addTag('test_tag'); + + $container->setDefinition(Service::class, $service); + + $decorated = new Definition(Decorated::class); + $decorated->setPublic(true); + $decorated->setDecoratedService(Service::class); + + $container->setDefinition(Decorated::class, $decorated); + + $container->compile(); + + /** @var ServiceLocator $locator */ + $locator = $container->get(Locator::class)->locator; + static::assertTrue($locator->has(Service::class)); + static::assertFalse($locator->has(Decorated::class)); + static::assertInstanceOf(Decorated::class, $locator->get(Service::class)); + } +} + +class Locator +{ + /** + * @var ServiceLocator + */ + public $locator; + + public function __construct(ServiceLocator $locator) + { + $this->locator = $locator; + } +} + +class Service +{ +} + +class DecoratedService +{ } From bb6413649a6b017619d7f01b401e1135f754d625 Mon Sep 17 00:00:00 2001 From: Robin Chalas <robin.chalas@gmail.com> Date: Mon, 2 Aug 2021 21:46:59 +0200 Subject: [PATCH 20/86] [Messenger] Separate unit tests from integration tests --- .../Redis/Tests/Transport/ConnectionTest.php | 150 ++---------------- .../Transport/RedisExtIntegrationTest.php | 103 ++++++++++++ 2 files changed, 117 insertions(+), 136 deletions(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php index 333a32b90366c..9223d5a833135 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Messenger\Bridge\Redis\Tests\Transport; -use PHPUnit\Framework\SkippedTestSuiteError; use PHPUnit\Framework\TestCase; use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Messenger\Bridge\Redis\Transport\Connection; @@ -19,37 +18,11 @@ /** * @requires extension redis >= 4.3.0 - * @group integration */ class ConnectionTest extends TestCase { use ExpectDeprecationTrait; - public static function setUpBeforeClass(): void - { - try { - $redis = Connection::fromDsn('redis://localhost/queue'); - $redis->get(); - } catch (TransportException $e) { - if (str_starts_with($e->getMessage(), 'ERR unknown command \'X')) { - throw new SkippedTestSuiteError('Redis server >= 5 is required'); - } - - throw $e; - } catch (\RedisException $e) { - throw new SkippedTestSuiteError($e->getMessage()); - } - } - - private function skipIfRedisClusterUnavailable() - { - try { - new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS'))); - } catch (\Exception $e) { - self::markTestSkipped($e->getMessage()); - } - } - public function testFromInvalidDsn() { $this->expectException(\InvalidArgumentException::class); @@ -64,25 +37,11 @@ public function testFromDsn() new Connection(['stream' => 'queue'], [ 'host' => 'localhost', 'port' => 6379, - ]), - Connection::fromDsn('redis://localhost/queue') + ], [], $this->createMock(\Redis::class)), + Connection::fromDsn('redis://localhost/queue', [], $this->createMock(\Redis::class)) ); } - public function testFromDsnWithMultipleHosts() - { - $this->skipIfRedisClusterUnavailable(); - - $hosts = explode(' ', getenv('REDIS_CLUSTER_HOSTS')); - - $dsn = array_map(function ($host) { - return 'redis://'.$host; - }, $hosts); - $dsn = implode(',', $dsn); - - $this->assertInstanceOf(Connection::class, Connection::fromDsn($dsn)); - } - public function testFromDsnOnUnixSocket() { $this->assertEquals( @@ -97,16 +56,16 @@ public function testFromDsnOnUnixSocket() public function testFromDsnWithOptions() { $this->assertEquals( - Connection::fromDsn('redis://localhost', ['stream' => 'queue', 'group' => 'group1', 'consumer' => 'consumer1', 'auto_setup' => false, 'serializer' => 2]), - Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2&auto_setup=0') + Connection::fromDsn('redis://localhost', ['stream' => 'queue', 'group' => 'group1', 'consumer' => 'consumer1', 'auto_setup' => false, 'serializer' => 2], $this->createMock(\Redis::class)), + Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2&auto_setup=0', [], $this->createMock(\Redis::class)) ); } public function testFromDsnWithOptionsAndTrailingSlash() { $this->assertEquals( - Connection::fromDsn('redis://localhost/', ['stream' => 'queue', 'group' => 'group1', 'consumer' => 'consumer1', 'auto_setup' => false, 'serializer' => 2]), - Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2&auto_setup=0') + Connection::fromDsn('redis://localhost/', ['stream' => 'queue', 'group' => 'group1', 'consumer' => 'consumer1', 'auto_setup' => false, 'serializer' => 2], $this->createMock(\Redis::class)), + Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2&auto_setup=0', [], $this->createMock(\Redis::class)) ); } @@ -157,21 +116,21 @@ public function testFromDsnWithQueryOptions() 'port' => 6379, ], [ 'serializer' => 2, - ]), - Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2') + ], $this->createMock(\Redis::class)), + Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2', [], $this->createMock(\Redis::class)) ); } public function testFromDsnWithMixDsnQueryOptions() { $this->assertEquals( - Connection::fromDsn('redis://localhost/queue/group1?serializer=2', ['consumer' => 'specific-consumer']), - Connection::fromDsn('redis://localhost/queue/group1/specific-consumer?serializer=2') + Connection::fromDsn('redis://localhost/queue/group1?serializer=2', ['consumer' => 'specific-consumer'], $this->createMock(\Redis::class)), + Connection::fromDsn('redis://localhost/queue/group1/specific-consumer?serializer=2', [], $this->createMock(\Redis::class)) ); $this->assertEquals( - Connection::fromDsn('redis://localhost/queue/group1/consumer1', ['consumer' => 'specific-consumer']), - Connection::fromDsn('redis://localhost/queue/group1/consumer1') + Connection::fromDsn('redis://localhost/queue/group1/consumer1', ['consumer' => 'specific-consumer'], $this->createMock(\Redis::class)), + Connection::fromDsn('redis://localhost/queue/group1/consumer1', [], $this->createMock(\Redis::class)) ); } @@ -181,14 +140,12 @@ public function testFromDsnWithMixDsnQueryOptions() public function testDeprecationIfInvalidOptionIsPassedWithDsn() { $this->expectDeprecation('Since symfony/messenger 5.1: Invalid option(s) "foo" passed to the Redis Messenger transport. Passing invalid options is deprecated.'); - Connection::fromDsn('redis://localhost/queue?foo=bar'); + Connection::fromDsn('redis://localhost/queue?foo=bar', [], $this->createMock(\Redis::class)); } public function testRedisClusterInstanceIsSupported() { - $this->skipIfRedisClusterUnavailable(); - - $redis = new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS'))); + $redis = $this->createMock(\RedisCluster::class); $this->assertInstanceOf(Connection::class, new Connection([], [], [], $redis)); } @@ -274,15 +231,6 @@ public function testFailedAuth() Connection::fromDsn('redis://password@localhost/queue', [], $redis); } - public function testDbIndex() - { - $redis = new \Redis(); - - Connection::fromDsn('redis://localhost/queue?dbindex=2', [], $redis); - - $this->assertSame(2, $redis->getDbNum()); - } - public function testGetPendingMessageFirst() { $redis = $this->createMock(\Redis::class); @@ -361,48 +309,6 @@ public function testUnexpectedRedisError() $connection->get(); } - public function testGetAfterReject() - { - $redis = new \Redis(); - $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', [], $redis); - - $connection->add('1', []); - $connection->add('2', []); - - $failing = $connection->get(); - $connection->reject($failing['id']); - - $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget'); - $this->assertNotNull($connection->get()); - - $redis->del('messenger-rejectthenget'); - } - - public function testGetNonBlocking() - { - $redis = new \Redis(); - - $connection = Connection::fromDsn('redis://localhost/messenger-getnonblocking', [], $redis); - - $this->assertNull($connection->get()); // no message, should return null immediately - $connection->add('1', []); - $this->assertNotEmpty($message = $connection->get()); - $connection->reject($message['id']); - $redis->del('messenger-getnonblocking'); - } - - public function testJsonError() - { - $redis = new \Redis(); - $connection = Connection::fromDsn('redis://localhost/json-error', [], $redis); - try { - $connection->add("\xB1\x31", []); - } catch (TransportException $e) { - } - - $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); - } - public function testMaxEntries() { $redis = $this->createMock(\Redis::class); @@ -471,32 +377,4 @@ public function testLastErrorGetsCleared() $this->assertSame('xack error', $e->getMessage()); } - - public function testLazy() - { - $redis = new \Redis(); - $connection = Connection::fromDsn('redis://localhost/messenger-lazy?lazy=1', [], $redis); - - $connection->add('1', []); - $this->assertNotEmpty($message = $connection->get()); - $this->assertSame('1', $message['body']); - $connection->reject($message['id']); - $redis->del('messenger-lazy'); - } - - public function testLazyCluster() - { - $this->skipIfRedisClusterUnavailable(); - - $connection = new Connection( - ['lazy' => true], - ['host' => explode(' ', getenv('REDIS_CLUSTER_HOSTS'))] - ); - - $connection->add('1', []); - $this->assertNotEmpty($message = $connection->get()); - $this->assertSame('1', $message['body']); - $connection->reject($message['id']); - $connection->cleanup(); - } } diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php index 0c92605d1120d..8ffc08c08f0bf 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Bridge\Redis\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Bridge\Redis\Transport\Connection; +use Symfony\Component\Messenger\Exception\TransportException; /** * @requires extension redis @@ -173,6 +174,99 @@ public function testConnectionClaimAndRedeliver() $connection->ack($encoded['id']); } + public function testLazyCluster() + { + $this->skipIfRedisClusterUnavailable(); + + $connection = new Connection( + ['lazy' => true], + ['host' => explode(' ', getenv('REDIS_CLUSTER_HOSTS'))] + ); + + $connection->add('1', []); + $this->assertNotEmpty($message = $connection->get()); + $this->assertSame('1', $message['body']); + $connection->reject($message['id']); + $connection->cleanup(); + } + + public function testLazy() + { + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/messenger-lazy?lazy=1', [], $redis); + + $connection->add('1', []); + $this->assertNotEmpty($message = $connection->get()); + $this->assertSame('1', $message['body']); + $connection->reject($message['id']); + $redis->del('messenger-lazy'); + } + + public function testDbIndex() + { + $redis = new \Redis(); + + Connection::fromDsn('redis://localhost/queue?dbindex=2', [], $redis); + + $this->assertSame(2, $redis->getDbNum()); + } + + public function testFromDsnWithMultipleHosts() + { + $this->skipIfRedisClusterUnavailable(); + + $hosts = explode(' ', getenv('REDIS_CLUSTER_HOSTS')); + + $dsn = array_map(function ($host) { + return 'redis://'.$host; + }, $hosts); + $dsn = implode(',', $dsn); + + $this->assertInstanceOf(Connection::class, Connection::fromDsn($dsn)); + } + + public function testJsonError() + { + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/json-error', [], $redis); + try { + $connection->add("\xB1\x31", []); + } catch (TransportException $e) { + } + + $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); + } + + public function testGetNonBlocking() + { + $redis = new \Redis(); + + $connection = Connection::fromDsn('redis://localhost/messenger-getnonblocking', [], $redis); + + $this->assertNull($connection->get()); // no message, should return null immediately + $connection->add('1', []); + $this->assertNotEmpty($message = $connection->get()); + $connection->reject($message['id']); + $redis->del('messenger-getnonblocking'); + } + + public function testGetAfterReject() + { + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', [], $redis); + + $connection->add('1', []); + $connection->add('2', []); + + $failing = $connection->get(); + $connection->reject($failing['id']); + + $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget'); + $this->assertNotNull($connection->get()); + + $redis->del('messenger-rejectthenget'); + } + private function getConnectionGroup(Connection $connection): string { $property = (new \ReflectionClass(Connection::class))->getProperty('group'); @@ -188,4 +282,13 @@ private function getConnectionStream(Connection $connection): string return $property->getValue($connection); } + + private function skipIfRedisClusterUnavailable() + { + try { + new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS'))); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + } } From 378f2f0abb738622bb2862fa50f558b47455ef91 Mon Sep 17 00:00:00 2001 From: Maciej Malarz <malarzm@gmail.com> Date: Tue, 3 Aug 2021 21:56:25 +0200 Subject: [PATCH 21/86] Typehint against doctrine/persistence interfaces --- .../Validator/Constraints/UniqueEntityValidator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 2cf9ca8c0d074..4996848143b73 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -11,9 +11,9 @@ namespace Symfony\Bridge\Doctrine\Validator\Constraints; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -177,7 +177,7 @@ public function validate($entity, Constraint $constraint) ->addViolation(); } - private function formatWithIdentifiers(EntityManagerInterface $em, ClassMetadata $class, $value) + private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, $value) { if (!\is_object($value) || $value instanceof \DateTimeInterface) { return $this->formatValue($value, self::PRETTY_DATE); From da4345e279523f5a513939588fd0695b2017f41e Mon Sep 17 00:00:00 2001 From: Oskar Stark <oskarstark@googlemail.com> Date: Wed, 4 Aug 2021 22:21:57 +0200 Subject: [PATCH 22/86] Remove preloading of unused class --- src/Symfony/Component/HttpKernel/HttpKernel.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 6cfd5b8cf6f1c..6587f32bd7966 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -33,7 +33,6 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; // Help opcache.preload discover always-needed symbols -class_exists(LegacyEventDispatcherProxy::class); class_exists(ControllerArgumentsEvent::class); class_exists(ControllerEvent::class); class_exists(ExceptionEvent::class); From 3eca446b21607ea1c7a865ece2dd8254c33679cc Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Mon, 26 Jul 2021 15:29:22 +0200 Subject: [PATCH 23/86] Fix return types for PHP 8.1 --- .../Constraints/UniqueEntityValidatorTest.php | 26 ++++++++++++++++--- .../Bundle/TwigBundle/TemplateIterator.php | 1 + .../Config/Resource/GlobResource.php | 1 + .../Component/Console/Helper/HelperSet.php | 3 ++- src/Symfony/Component/DomCrawler/Crawler.php | 2 ++ src/Symfony/Component/DomCrawler/Form.php | 4 +++ .../EventDispatcher/GenericEvent.php | 5 ++++ src/Symfony/Component/Finder/Finder.php | 2 ++ .../Finder/Iterator/CustomFilterIterator.php | 1 + .../Iterator/DateRangeFilterIterator.php | 1 + .../Iterator/DepthRangeFilterIterator.php | 1 + .../ExcludeDirectoryFilterIterator.php | 3 +++ .../Iterator/FileTypeFilterIterator.php | 1 + .../Iterator/FilecontentFilterIterator.php | 1 + .../Iterator/FilenameFilterIterator.php | 1 + .../Finder/Iterator/PathFilterIterator.php | 1 + .../Iterator/SizeRangeFilterIterator.php | 1 + .../Finder/Iterator/SortableIterator.php | 1 + .../Finder/Tests/Iterator/Iterator.php | 14 +++++++--- .../MultiplePcreFilterIteratorTest.php | 2 +- src/Symfony/Component/Form/Button.php | 6 +++++ src/Symfony/Component/Form/ButtonBuilder.php | 2 ++ .../Form/ChoiceList/View/ChoiceGroupView.php | 3 ++- .../ViolationMapper/ViolationPath.php | 1 + src/Symfony/Component/Form/Form.php | 6 +++++ src/Symfony/Component/Form/FormBuilder.php | 2 ++ .../Component/Form/FormErrorIterator.php | 13 ++++++++++ src/Symfony/Component/Form/FormView.php | 6 +++++ .../Form/Tests/Fixtures/CustomArrayObject.php | 11 +++++--- .../Form/Util/InheritDataAwareIterator.php | 2 ++ .../Component/Form/Util/OrderedHashMap.php | 6 +++++ .../Form/Util/OrderedHashMapIterator.php | 10 +++---- .../Component/HttpFoundation/File/Stream.php | 1 + .../Component/HttpFoundation/HeaderBag.php | 2 ++ .../Component/HttpFoundation/ParameterBag.php | 2 ++ .../Session/Attribute/AttributeBag.php | 2 ++ .../HttpFoundation/Session/Session.php | 2 ++ .../Handler/MemcachedSessionHandler.php | 2 ++ .../HttpFoundation/Tests/File/FakeFile.php | 10 +++---- .../Util/ArrayAccessibleResourceBundle.php | 12 +++------ .../Component/Intl/Data/Util/RingBuffer.php | 5 ++-- .../Ldap/Adapter/ExtLdap/Collection.php | 1 + .../OptionsResolver/OptionsResolver.php | 5 ++++ src/Symfony/Component/Process/InputStream.php | 1 + src/Symfony/Component/Process/Process.php | 1 + .../Component/PropertyAccess/PropertyPath.php | 1 + .../Fixtures/NonTraversableArrayObject.php | 11 +++++--- .../Tests/Fixtures/TraversableArrayObject.php | 9 +++++-- .../Component/Routing/RouteCollection.php | 2 ++ .../Exception/AuthenticationException.php | 2 +- .../Component/Templating/PhpEngine.php | 4 +++ .../Validator/ConstraintViolationList.php | 6 +++++ .../Tests/Fixtures/CustomArrayObject.php | 9 +++++-- .../Component/VarDumper/Cloner/Data.php | 6 +++++ 54 files changed, 194 insertions(+), 42 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index 05faff5872dd8..c0945114c9c23 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -827,6 +827,10 @@ public function resultWithEmptyIterator(): array return [ [$entity, new class() implements \Iterator { + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function current() { return null; @@ -837,19 +841,28 @@ public function valid(): bool return false; } - public function next() + public function next(): void { } + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function key() { + return false; } - public function rewind() + public function rewind(): void { } }], [$entity, new class() implements \Iterator { + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function current() { return false; @@ -860,15 +873,20 @@ public function valid(): bool return false; } - public function next() + public function next(): void { } + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function key() { + return false; } - public function rewind() + public function rewind(): void { } }], diff --git a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php index 8af15aa3a9f5f..b16eadc40bf54 100644 --- a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php +++ b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php @@ -45,6 +45,7 @@ public function __construct(KernelInterface $kernel, string $rootDir, array $pat /** * @return \Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { if (null !== $this->templates) { diff --git a/src/Symfony/Component/Config/Resource/GlobResource.php b/src/Symfony/Component/Config/Resource/GlobResource.php index 0b535682f4af3..f9429eb8f9bd9 100644 --- a/src/Symfony/Component/Config/Resource/GlobResource.php +++ b/src/Symfony/Component/Config/Resource/GlobResource.php @@ -102,6 +102,7 @@ public function __wakeup(): void /** * @return \Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { if (!file_exists($this->prefix) || (!$this->recursive && '' === $this->pattern)) { diff --git a/src/Symfony/Component/Console/Helper/HelperSet.php b/src/Symfony/Component/Console/Helper/HelperSet.php index d9d73f25fc69a..9aa1e67ba8c9b 100644 --- a/src/Symfony/Component/Console/Helper/HelperSet.php +++ b/src/Symfony/Component/Console/Helper/HelperSet.php @@ -98,8 +98,9 @@ public function getCommand() } /** - * @return Helper[] + * @return \Traversable<Helper> */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->helpers); diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 3f5c2a50d6fec..de7b3aedc37ae 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -1149,6 +1149,7 @@ public function getNode($position) /** * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->nodes); @@ -1157,6 +1158,7 @@ public function count() /** * @return \ArrayIterator|\DOMNode[] */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->nodes); diff --git a/src/Symfony/Component/DomCrawler/Form.php b/src/Symfony/Component/DomCrawler/Form.php index dbba779ced5d0..0c86116a64eca 100644 --- a/src/Symfony/Component/DomCrawler/Form.php +++ b/src/Symfony/Component/DomCrawler/Form.php @@ -321,6 +321,7 @@ public function all() * * @return bool true if the field exists, false otherwise */ + #[\ReturnTypeWillChange] public function offsetExists($name) { return $this->has($name); @@ -335,6 +336,7 @@ public function offsetExists($name) * * @throws \InvalidArgumentException if the field does not exist */ + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->fields->get($name); @@ -350,6 +352,7 @@ public function offsetGet($name) * * @throws \InvalidArgumentException if the field does not exist */ + #[\ReturnTypeWillChange] public function offsetSet($name, $value) { $this->fields->set($name, $value); @@ -362,6 +365,7 @@ public function offsetSet($name, $value) * * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($name) { $this->fields->remove($name); diff --git a/src/Symfony/Component/EventDispatcher/GenericEvent.php b/src/Symfony/Component/EventDispatcher/GenericEvent.php index d86a584153ded..23333bc21284f 100644 --- a/src/Symfony/Component/EventDispatcher/GenericEvent.php +++ b/src/Symfony/Component/EventDispatcher/GenericEvent.php @@ -123,6 +123,7 @@ public function hasArgument($key) * * @throws \InvalidArgumentException if key does not exist in $this->args */ + #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->getArgument($key); @@ -136,6 +137,7 @@ public function offsetGet($key) * * @return void */ + #[\ReturnTypeWillChange] public function offsetSet($key, $value) { $this->setArgument($key, $value); @@ -148,6 +150,7 @@ public function offsetSet($key, $value) * * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($key) { if ($this->hasArgument($key)) { @@ -162,6 +165,7 @@ public function offsetUnset($key) * * @return bool */ + #[\ReturnTypeWillChange] public function offsetExists($key) { return $this->hasArgument($key); @@ -172,6 +176,7 @@ public function offsetExists($key) * * @return \ArrayIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->arguments); diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php index 92249ad902178..e1194ed695e23 100644 --- a/src/Symfony/Component/Finder/Finder.php +++ b/src/Symfony/Component/Finder/Finder.php @@ -618,6 +618,7 @@ public function in($dirs) * * @throws \LogicException if the in() method has not been called */ + #[\ReturnTypeWillChange] public function getIterator() { if (0 === \count($this->dirs) && 0 === \count($this->iterators)) { @@ -702,6 +703,7 @@ public function hasResults() * * @return int */ + #[\ReturnTypeWillChange] public function count() { return iterator_count($this->getIterator()); diff --git a/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php b/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php index a30bbd0b9d265..f85cb7bffb772 100644 --- a/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/CustomFilterIterator.php @@ -46,6 +46,7 @@ public function __construct(\Iterator $iterator, array $filters) * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { $fileinfo = $this->current(); diff --git a/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php b/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php index 2e97e00d37456..90616f471b1f7 100644 --- a/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php @@ -38,6 +38,7 @@ public function __construct(\Iterator $iterator, array $comparators) * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { $fileinfo = $this->current(); diff --git a/src/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php b/src/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php index 18e751d77b928..e96fefd961b16 100644 --- a/src/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php @@ -38,6 +38,7 @@ public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { return $this->getInnerIterator()->getDepth() >= $this->minDepth; diff --git a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php index 366ad70cdb9bc..cf9e678771da9 100644 --- a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -52,6 +52,7 @@ public function __construct(\Iterator $iterator, array $directories) * * @return bool True if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) { @@ -71,6 +72,7 @@ public function accept() /** * @return bool */ + #[\ReturnTypeWillChange] public function hasChildren() { return $this->isRecursive && $this->iterator->hasChildren(); @@ -79,6 +81,7 @@ public function hasChildren() /** * @return self */ + #[\ReturnTypeWillChange] public function getChildren() { $children = new self($this->iterator->getChildren(), []); diff --git a/src/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php b/src/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php index 0ea2c508802de..d054cefb9fff9 100644 --- a/src/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php @@ -39,6 +39,7 @@ public function __construct(\Iterator $iterator, int $mode) * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { $fileinfo = $this->current(); diff --git a/src/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php b/src/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php index 81594b8774048..41eb767f7a651 100644 --- a/src/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php @@ -24,6 +24,7 @@ class FilecontentFilterIterator extends MultiplePcreFilterIterator * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { if (!$this->matchRegexps && !$this->noMatchRegexps) { diff --git a/src/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php b/src/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php index e168cd8ffa798..8365756c15209 100644 --- a/src/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php @@ -25,6 +25,7 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { return $this->isAccepted($this->current()->getFilename()); diff --git a/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php b/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php index 3fda557be366b..f4aaa1fb0027d 100644 --- a/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php @@ -24,6 +24,7 @@ class PathFilterIterator extends MultiplePcreFilterIterator * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { $filename = $this->current()->getRelativePathname(); diff --git a/src/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php b/src/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php index 2aeef67b87f73..4078f3692e052 100644 --- a/src/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php @@ -38,6 +38,7 @@ public function __construct(\Iterator $iterator, array $comparators) * * @return bool true if the value should be kept, false otherwise */ + #[\ReturnTypeWillChange] public function accept() { $fileinfo = $this->current(); diff --git a/src/Symfony/Component/Finder/Iterator/SortableIterator.php b/src/Symfony/Component/Finder/Iterator/SortableIterator.php index 8559ba51cd794..adc7e999db8b4 100644 --- a/src/Symfony/Component/Finder/Iterator/SortableIterator.php +++ b/src/Symfony/Component/Finder/Iterator/SortableIterator.php @@ -81,6 +81,7 @@ public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = /** * @return \Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { if (1 === $this->sort) { diff --git a/src/Symfony/Component/Finder/Tests/Iterator/Iterator.php b/src/Symfony/Component/Finder/Tests/Iterator/Iterator.php index bc2eb53b393e0..108c66a273c99 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/Iterator.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/Iterator.php @@ -23,12 +23,12 @@ public function __construct(array $values = []) $this->rewind(); } - public function attach(\SplFileInfo $fileinfo) + public function attach(\SplFileInfo $fileinfo): void { $this->values[] = $fileinfo; } - public function rewind() + public function rewind(): void { reset($this->values); } @@ -38,16 +38,24 @@ public function valid(): bool return false !== $this->current(); } - public function next() + public function next(): void { next($this->values); } + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function current() { return current($this->values); } + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function key() { return key($this->values); diff --git a/src/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php index 15e069b9f81c1..590aea21af693 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php @@ -54,7 +54,7 @@ public function __construct() { } - public function accept() + public function accept(): bool { throw new \BadFunctionCallException('Not implemented'); } diff --git a/src/Symfony/Component/Form/Button.php b/src/Symfony/Component/Form/Button.php index f3f1edebf10d2..9c3cf9b6b5976 100644 --- a/src/Symfony/Component/Form/Button.php +++ b/src/Symfony/Component/Form/Button.php @@ -51,6 +51,7 @@ public function __construct(FormConfigInterface $config) * * @return bool Always returns false */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { return false; @@ -67,6 +68,7 @@ public function offsetExists($offset) * * @throws BadMethodCallException */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { throw new BadMethodCallException('Buttons cannot have children.'); @@ -84,6 +86,7 @@ public function offsetGet($offset) * * @throws BadMethodCallException */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { throw new BadMethodCallException('Buttons cannot have children.'); @@ -100,6 +103,7 @@ public function offsetSet($offset, $value) * * @throws BadMethodCallException */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { throw new BadMethodCallException('Buttons cannot have children.'); @@ -436,6 +440,7 @@ public function createView(FormView $parent = null) * * @return int Always returns 0 */ + #[\ReturnTypeWillChange] public function count() { return 0; @@ -446,6 +451,7 @@ public function count() * * @return \EmptyIterator Always returns an empty iterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \EmptyIterator(); diff --git a/src/Symfony/Component/Form/ButtonBuilder.php b/src/Symfony/Component/Form/ButtonBuilder.php index 4d16632bbe40d..fb310899700f8 100644 --- a/src/Symfony/Component/Form/ButtonBuilder.php +++ b/src/Symfony/Component/Form/ButtonBuilder.php @@ -717,6 +717,7 @@ public function getOption($name, $default = null) * * @return int Always returns 0 */ + #[\ReturnTypeWillChange] public function count() { return 0; @@ -727,6 +728,7 @@ public function count() * * @return \EmptyIterator Always returns an empty iterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \EmptyIterator(); diff --git a/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php b/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php index dd80486c9acea..a8446655c3565 100644 --- a/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php +++ b/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php @@ -36,8 +36,9 @@ public function __construct($label, array $choices = []) /** * {@inheritdoc} * - * @return self[]|ChoiceView[] + * @return \Traversable<ChoiceGroupView|ChoiceView> */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->choices); diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php index fca0bfa16b6b3..47593b82cb1ff 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php @@ -223,6 +223,7 @@ public function mapsForm($index) * * @return ViolationPathIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new ViolationPathIterator($this); diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 9abb6bdeab146..32cc437574d4b 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -958,6 +958,7 @@ public function get($name) * * @return bool */ + #[\ReturnTypeWillChange] public function offsetExists($name) { return $this->has($name); @@ -972,6 +973,7 @@ public function offsetExists($name) * * @throws OutOfBoundsException if the named child does not exist */ + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->get($name); @@ -990,6 +992,7 @@ public function offsetGet($name) * * @see self::add() */ + #[\ReturnTypeWillChange] public function offsetSet($name, $child) { $this->add($child); @@ -1004,6 +1007,7 @@ public function offsetSet($name, $child) * * @throws AlreadySubmittedException if the form has already been submitted */ + #[\ReturnTypeWillChange] public function offsetUnset($name) { $this->remove($name); @@ -1014,6 +1018,7 @@ public function offsetUnset($name) * * @return \Traversable<FormInterface> */ + #[\ReturnTypeWillChange] public function getIterator() { return $this->children; @@ -1024,6 +1029,7 @@ public function getIterator() * * @return int The number of embedded form children */ + #[\ReturnTypeWillChange] public function count() { return \count($this->children); diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index 2fa65e095c496..9ec863ac493c8 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -161,6 +161,7 @@ public function all() /** * @return int */ + #[\ReturnTypeWillChange] public function count() { if ($this->locked) { @@ -215,6 +216,7 @@ public function getForm() * * @return FormBuilderInterface[]|\Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { if ($this->locked) { diff --git a/src/Symfony/Component/Form/FormErrorIterator.php b/src/Symfony/Component/Form/FormErrorIterator.php index f4614844985a0..0ef5a2e95844c 100644 --- a/src/Symfony/Component/Form/FormErrorIterator.php +++ b/src/Symfony/Component/Form/FormErrorIterator.php @@ -93,6 +93,7 @@ public function getForm() * * @return FormError|self An error or an iterator containing nested errors */ + #[\ReturnTypeWillChange] public function current() { return current($this->errors); @@ -101,6 +102,7 @@ public function current() /** * Advances the iterator to the next position. */ + #[\ReturnTypeWillChange] public function next() { next($this->errors); @@ -111,6 +113,7 @@ public function next() * * @return int The 0-indexed position */ + #[\ReturnTypeWillChange] public function key() { return key($this->errors); @@ -121,6 +124,7 @@ public function key() * * @return bool Whether the iterator is valid */ + #[\ReturnTypeWillChange] public function valid() { return null !== key($this->errors); @@ -132,6 +136,7 @@ public function valid() * This method detects if errors have been added to the form since the * construction of the iterator. */ + #[\ReturnTypeWillChange] public function rewind() { reset($this->errors); @@ -144,6 +149,7 @@ public function rewind() * * @return bool Whether that position exists */ + #[\ReturnTypeWillChange] public function offsetExists($position) { return isset($this->errors[$position]); @@ -158,6 +164,7 @@ public function offsetExists($position) * * @throws OutOfBoundsException If the given position does not exist */ + #[\ReturnTypeWillChange] public function offsetGet($position) { if (!isset($this->errors[$position])) { @@ -174,6 +181,7 @@ public function offsetGet($position) * * @throws BadMethodCallException */ + #[\ReturnTypeWillChange] public function offsetSet($position, $value) { throw new BadMethodCallException('The iterator doesn\'t support modification of elements.'); @@ -186,6 +194,7 @@ public function offsetSet($position, $value) * * @throws BadMethodCallException */ + #[\ReturnTypeWillChange] public function offsetUnset($position) { throw new BadMethodCallException('The iterator doesn\'t support modification of elements.'); @@ -197,6 +206,7 @@ public function offsetUnset($position) * * @return bool Whether the current element is an instance of this class */ + #[\ReturnTypeWillChange] public function hasChildren() { return current($this->errors) instanceof self; @@ -207,6 +217,7 @@ public function hasChildren() * * @return self */ + #[\ReturnTypeWillChange] public function getChildren() { return current($this->errors); @@ -229,6 +240,7 @@ public function getChildren() * * @return int The number of iterated elements */ + #[\ReturnTypeWillChange] public function count() { return \count($this->errors); @@ -243,6 +255,7 @@ public function count() * * @throws OutOfBoundsException If the position is invalid */ + #[\ReturnTypeWillChange] public function seek($position) { if (!isset($this->errors[$position])) { diff --git a/src/Symfony/Component/Form/FormView.php b/src/Symfony/Component/Form/FormView.php index 644bf515e6a71..460e52857680d 100644 --- a/src/Symfony/Component/Form/FormView.php +++ b/src/Symfony/Component/Form/FormView.php @@ -108,6 +108,7 @@ public function setMethodRendered() * * @return self The child view */ + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->children[$name]; @@ -120,6 +121,7 @@ public function offsetGet($name) * * @return bool Whether the child view exists */ + #[\ReturnTypeWillChange] public function offsetExists($name) { return isset($this->children[$name]); @@ -132,6 +134,7 @@ public function offsetExists($name) * * @throws BadMethodCallException always as setting a child by name is not allowed */ + #[\ReturnTypeWillChange] public function offsetSet($name, $value) { throw new BadMethodCallException('Not supported.'); @@ -144,6 +147,7 @@ public function offsetSet($name, $value) * * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($name) { unset($this->children[$name]); @@ -154,6 +158,7 @@ public function offsetUnset($name) * * @return \ArrayIterator<string, FormView> The iterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->children); @@ -164,6 +169,7 @@ public function getIterator() * * @return int The number of children views */ + #[\ReturnTypeWillChange] public function count() { return \count($this->children); diff --git a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php index 5c12b6b400bb8..41cb5af4cdf7b 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php @@ -29,12 +29,17 @@ public function offsetExists($offset): bool return \array_key_exists($offset, $this->array); } + /** + * @param mixed $offset + * @return mixed + */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->array[$offset]; } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (null === $offset) { $this->array[] = $value; @@ -43,7 +48,7 @@ public function offsetSet($offset, $value) } } - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->array[$offset]); } @@ -73,7 +78,7 @@ public function __unserialize(array $data): void $this->array = $data; } - public function unserialize($serialized) + public function unserialize($serialized): void { $this->__unserialize((array) unserialize((string) $serialized)); } diff --git a/src/Symfony/Component/Form/Util/InheritDataAwareIterator.php b/src/Symfony/Component/Form/Util/InheritDataAwareIterator.php index 1bb324423623b..7cba17dbebe1c 100644 --- a/src/Symfony/Component/Form/Util/InheritDataAwareIterator.php +++ b/src/Symfony/Component/Form/Util/InheritDataAwareIterator.php @@ -30,6 +30,7 @@ class InheritDataAwareIterator extends \IteratorIterator implements \RecursiveIt * * @return static */ + #[\ReturnTypeWillChange] public function getChildren() { return new static($this->current()); @@ -38,6 +39,7 @@ public function getChildren() /** * @return bool */ + #[\ReturnTypeWillChange] public function hasChildren() { return (bool) $this->current()->getConfig()->getInheritData(); diff --git a/src/Symfony/Component/Form/Util/OrderedHashMap.php b/src/Symfony/Component/Form/Util/OrderedHashMap.php index 7b1ca264d2bbb..b60a7ce4b0959 100644 --- a/src/Symfony/Component/Form/Util/OrderedHashMap.php +++ b/src/Symfony/Component/Form/Util/OrderedHashMap.php @@ -101,6 +101,7 @@ public function __construct(array $elements = []) /** * @return bool */ + #[\ReturnTypeWillChange] public function offsetExists($key) { return isset($this->elements[$key]); @@ -111,6 +112,7 @@ public function offsetExists($key) * * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($key) { if (!isset($this->elements[$key])) { @@ -125,6 +127,7 @@ public function offsetGet($key) * * @return void */ + #[\ReturnTypeWillChange] public function offsetSet($key, $value) { if (null === $key || !isset($this->elements[$key])) { @@ -148,6 +151,7 @@ public function offsetSet($key, $value) * * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($key) { if (false !== ($position = array_search((string) $key, $this->orderedKeys))) { @@ -165,6 +169,7 @@ public function offsetUnset($key) /** * @return \Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { return new OrderedHashMapIterator($this->elements, $this->orderedKeys, $this->managedCursors); @@ -173,6 +178,7 @@ public function getIterator() /** * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->elements); diff --git a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php index 6e295e1871451..87cab46052b40 100644 --- a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php +++ b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php @@ -105,6 +105,7 @@ public function __destruct() * * @return mixed */ + #[\ReturnTypeWillChange] public function current() { return $this->current; @@ -112,10 +113,8 @@ public function current() /** * {@inheritdoc} - * - * @return void */ - public function next() + public function next(): void { ++$this->cursor; @@ -133,6 +132,7 @@ public function next() * * @return mixed */ + #[\ReturnTypeWillChange] public function key() { if (null === $this->key) { @@ -154,10 +154,8 @@ public function valid(): bool /** * {@inheritdoc} - * - * @return void */ - public function rewind() + public function rewind(): void { $this->cursor = 0; diff --git a/src/Symfony/Component/HttpFoundation/File/Stream.php b/src/Symfony/Component/HttpFoundation/File/Stream.php index 4a08e7f2dd355..cef3e03977cfe 100644 --- a/src/Symfony/Component/HttpFoundation/File/Stream.php +++ b/src/Symfony/Component/HttpFoundation/File/Stream.php @@ -23,6 +23,7 @@ class Stream extends File * * @return int|false */ + #[\ReturnTypeWillChange] public function getSize() { return false; diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php index 15393544fcbfe..9fb113de44e26 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php @@ -279,6 +279,7 @@ public function removeCacheControlDirective($key) * * @return \ArrayIterator An \ArrayIterator instance */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->headers); @@ -289,6 +290,7 @@ public function getIterator() * * @return int The number of headers */ + #[\ReturnTypeWillChange] public function count() { return \count($this->headers); diff --git a/src/Symfony/Component/HttpFoundation/ParameterBag.php b/src/Symfony/Component/HttpFoundation/ParameterBag.php index 1de753d3da37b..a2fe0af869873 100644 --- a/src/Symfony/Component/HttpFoundation/ParameterBag.php +++ b/src/Symfony/Component/HttpFoundation/ParameterBag.php @@ -210,6 +210,7 @@ public function filter($key, $default = null, $filter = \FILTER_DEFAULT, $option * * @return \ArrayIterator An \ArrayIterator instance */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->parameters); @@ -220,6 +221,7 @@ public function getIterator() * * @return int The number of parameters */ + #[\ReturnTypeWillChange] public function count() { return \count($this->parameters); diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php index ee33698cf0842..bd35531739d3c 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php @@ -131,6 +131,7 @@ public function clear() * * @return \ArrayIterator An \ArrayIterator instance */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->attributes); @@ -141,6 +142,7 @@ public function getIterator() * * @return int The number of attributes */ + #[\ReturnTypeWillChange] public function count() { return \count($this->attributes); diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php index 960679ace8f61..f42ed38ef5573 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Session.php +++ b/src/Symfony/Component/HttpFoundation/Session/Session.php @@ -126,6 +126,7 @@ public function isStarted() * * @return \ArrayIterator An \ArrayIterator instance */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->getAttributeBag()->all()); @@ -136,6 +137,7 @@ public function getIterator() * * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->getAttributeBag()->all()); diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php index d8663a57b76d2..af9d45cae3b40 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php @@ -57,6 +57,7 @@ public function __construct(\Memcached $memcached, array $options = []) /** * @return bool */ + #[\ReturnTypeWillChange] public function close() { return $this->memcached->quit(); @@ -73,6 +74,7 @@ protected function doRead($sessionId) /** * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { $this->memcached->touch($this->prefix.$sessionId, time() + $this->ttl); diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/FakeFile.php b/src/Symfony/Component/HttpFoundation/Tests/File/FakeFile.php index c415989f2f7f8..8b2f12f4144cf 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/FakeFile.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/FakeFile.php @@ -17,28 +17,28 @@ class FakeFile extends OrigFile { private $realpath; - public function __construct($realpath, $path) + public function __construct(string $realpath, string $path) { $this->realpath = $realpath; parent::__construct($path, false); } - public function isReadable() + public function isReadable(): bool { return true; } - public function getRealpath() + public function getRealpath(): string { return $this->realpath; } - public function getSize() + public function getSize(): int { return 42; } - public function getMTime() + public function getMTime(): int { return time(); } diff --git a/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php b/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php index da6faf67810b6..2679948b14733 100644 --- a/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php +++ b/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php @@ -45,25 +45,21 @@ public function offsetExists($offset): bool } /** + * @param mixed $offset * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->get($offset); } - /** - * @return void - */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { throw new BadMethodCallException('Resource bundles cannot be modified.'); } - /** - * @return void - */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { throw new BadMethodCallException('Resource bundles cannot be modified.'); } diff --git a/src/Symfony/Component/Intl/Data/Util/RingBuffer.php b/src/Symfony/Component/Intl/Data/Util/RingBuffer.php index 76bca285bbbc2..72d86025f718a 100644 --- a/src/Symfony/Component/Intl/Data/Util/RingBuffer.php +++ b/src/Symfony/Component/Intl/Data/Util/RingBuffer.php @@ -52,6 +52,7 @@ public function offsetExists($key): bool * * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($key) { if (!isset($this->indices[$key])) { @@ -66,7 +67,7 @@ public function offsetGet($key) * * @return void */ - public function offsetSet($key, $value) + public function offsetSet($key, $value): void { if (false !== ($keyToRemove = array_search($this->cursor, $this->indices))) { unset($this->indices[$keyToRemove]); @@ -83,7 +84,7 @@ public function offsetSet($key, $value) * * @return void */ - public function offsetUnset($key) + public function offsetUnset($key): void { if (isset($this->indices[$key])) { $this->values[$this->indices[$key]] = null; diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php index 05e81c8378e57..d8da8ddbf6586 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php @@ -45,6 +45,7 @@ public function toArray() /** * @return int */ + #[\ReturnTypeWillChange] public function count() { $con = $this->connection->getResource(); diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 6c6764e1818bd..fc1cf85475861 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -832,6 +832,7 @@ public function resolve(array $options = []) * @throws OptionDefinitionException If there is a cyclic dependency between * lazy options and/or normalizers */ + #[\ReturnTypeWillChange] public function offsetGet($option/*, bool $triggerDeprecation = true*/) { if (!$this->locked) { @@ -1072,6 +1073,7 @@ private function verifyTypes(string $type, $value, array &$invalidTypes, int $le * * @see \ArrayAccess::offsetExists() */ + #[\ReturnTypeWillChange] public function offsetExists($option) { if (!$this->locked) { @@ -1088,6 +1090,7 @@ public function offsetExists($option) * * @throws AccessException */ + #[\ReturnTypeWillChange] public function offsetSet($option, $value) { throw new AccessException('Setting options via array access is not supported. Use setDefault() instead.'); @@ -1100,6 +1103,7 @@ public function offsetSet($option, $value) * * @throws AccessException */ + #[\ReturnTypeWillChange] public function offsetUnset($option) { throw new AccessException('Removing options via array access is not supported. Use remove() instead.'); @@ -1116,6 +1120,7 @@ public function offsetUnset($option) * * @see \Countable::count() */ + #[\ReturnTypeWillChange] public function count() { if (!$this->locked) { diff --git a/src/Symfony/Component/Process/InputStream.php b/src/Symfony/Component/Process/InputStream.php index c86fca86878df..4f8f71331aafc 100644 --- a/src/Symfony/Component/Process/InputStream.php +++ b/src/Symfony/Component/Process/InputStream.php @@ -69,6 +69,7 @@ public function isClosed() /** * @return \Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { $this->open = true; diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index a30cc3d118e0e..9fafddd64413d 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -622,6 +622,7 @@ public function getIncrementalOutput() * * @return \Generator */ + #[\ReturnTypeWillChange] public function getIterator($flags = 0) { $this->readPipesForOutput(__FUNCTION__, false); diff --git a/src/Symfony/Component/PropertyAccess/PropertyPath.php b/src/Symfony/Component/PropertyAccess/PropertyPath.php index f831ec3fda0bb..ac1f7c3c04cf4 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyPath.php +++ b/src/Symfony/Component/PropertyAccess/PropertyPath.php @@ -154,6 +154,7 @@ public function getParent() * * @return PropertyPathIteratorInterface */ + #[\ReturnTypeWillChange] public function getIterator() { return new PropertyPathIterator($this); diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php index cf02ee69f2979..da8911ed7207f 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php @@ -29,12 +29,17 @@ public function offsetExists($offset): bool return \array_key_exists($offset, $this->array); } + /** + * @param mixed $offset + * @return mixed + */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->array[$offset]; } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (null === $offset) { $this->array[] = $value; @@ -43,7 +48,7 @@ public function offsetSet($offset, $value) } } - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->array[$offset]); } @@ -68,7 +73,7 @@ public function __unserialize(array $data): void $this->array = $data; } - public function unserialize($serialized) + public function unserialize($serialized): void { $this->__unserialize((array) unserialize((string) $serialized)); } diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php index 5693c6b73e685..26ab98575f25f 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php @@ -29,12 +29,17 @@ public function offsetExists($offset): bool return \array_key_exists($offset, $this->array); } + /** + * @param mixed $offset + * @return mixed + */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->array[$offset]; } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (null === $offset) { $this->array[] = $value; @@ -43,7 +48,7 @@ public function offsetSet($offset, $value) } } - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->array[$offset]); } diff --git a/src/Symfony/Component/Routing/RouteCollection.php b/src/Symfony/Component/Routing/RouteCollection.php index 3baf0986c5cb1..56e925cac5158 100644 --- a/src/Symfony/Component/Routing/RouteCollection.php +++ b/src/Symfony/Component/Routing/RouteCollection.php @@ -51,6 +51,7 @@ public function __clone() * * @return \ArrayIterator|Route[] An \ArrayIterator object for iterating over routes */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->routes); @@ -61,6 +62,7 @@ public function getIterator() * * @return int The number of routes */ + #[\ReturnTypeWillChange] public function count() { return \count($this->routes); diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index 8a1c8327087dc..04a1212e21bfb 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -128,7 +128,7 @@ public function __sleep(): array /** * @internal */ - public function __wakeup() + public function __wakeup(): void { if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) { @trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, implement the __serialize() and __unserialize() methods instead.', $c), \E_USER_DEPRECATED); diff --git a/src/Symfony/Component/Templating/PhpEngine.php b/src/Symfony/Component/Templating/PhpEngine.php index b849da174b5f8..e4f85606981ce 100644 --- a/src/Symfony/Component/Templating/PhpEngine.php +++ b/src/Symfony/Component/Templating/PhpEngine.php @@ -173,6 +173,7 @@ protected function evaluate(Storage $template, array $parameters = []) * * @throws \InvalidArgumentException if the helper is not defined */ + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->get($name); @@ -185,6 +186,7 @@ public function offsetGet($name) * * @return bool true if the helper is defined, false otherwise */ + #[\ReturnTypeWillChange] public function offsetExists($name) { return isset($this->helpers[$name]); @@ -198,6 +200,7 @@ public function offsetExists($name) * * @return void */ + #[\ReturnTypeWillChange] public function offsetSet($name, $value) { $this->set($name, $value); @@ -212,6 +215,7 @@ public function offsetSet($name, $value) * * @throws \LogicException */ + #[\ReturnTypeWillChange] public function offsetUnset($name) { throw new \LogicException(sprintf('You can\'t unset a helper (%s).', $name)); diff --git a/src/Symfony/Component/Validator/ConstraintViolationList.php b/src/Symfony/Component/Validator/ConstraintViolationList.php index bd6443fc45889..e057e916ae16f 100644 --- a/src/Symfony/Component/Validator/ConstraintViolationList.php +++ b/src/Symfony/Component/Validator/ConstraintViolationList.php @@ -110,6 +110,7 @@ public function remove($offset) * * @return \ArrayIterator|ConstraintViolationInterface[] */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->violations); @@ -118,6 +119,7 @@ public function getIterator() /** * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->violations); @@ -126,6 +128,7 @@ public function count() /** * @return bool */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { return $this->has($offset); @@ -136,6 +139,7 @@ public function offsetExists($offset) * * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->get($offset); @@ -146,6 +150,7 @@ public function offsetGet($offset) * * @return void */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $violation) { if (null === $offset) { @@ -160,6 +165,7 @@ public function offsetSet($offset, $violation) * * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { $this->remove($offset); diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php index 34b208b2bea0c..f248576d2f2e5 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php @@ -29,12 +29,17 @@ public function offsetExists($offset): bool return \array_key_exists($offset, $this->array); } + /** + * @param mixed $offset + * @return mixed + */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->array[$offset]; } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (null === $offset) { $this->array[] = $value; @@ -43,7 +48,7 @@ public function offsetSet($offset, $value) } } - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->array[$offset]); } diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 114bf50e5b038..8f621b12a7627 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -111,6 +111,7 @@ public function getValue($recursive = false) /** * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->getValue()); @@ -119,6 +120,7 @@ public function count() /** * @return \Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { if (!\is_array($value = $this->getValue())) { @@ -150,6 +152,7 @@ public function __isset($key) /** * @return bool */ + #[\ReturnTypeWillChange] public function offsetExists($key) { return $this->__isset($key); @@ -158,6 +161,7 @@ public function offsetExists($key) /** * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->__get($key); @@ -166,6 +170,7 @@ public function offsetGet($key) /** * @return void */ + #[\ReturnTypeWillChange] public function offsetSet($key, $value) { throw new \BadMethodCallException(self::class.' objects are immutable.'); @@ -174,6 +179,7 @@ public function offsetSet($key, $value) /** * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($key) { throw new \BadMethodCallException(self::class.' objects are immutable.'); From 6d0e144365200c24231f5ccee06a2bef81e9d3aa Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Thu, 5 Aug 2021 00:42:04 +0200 Subject: [PATCH 24/86] Fix test Signed-off-by: Alexander M. Turek <me@derrabus.de> --- src/Symfony/Component/VarExporter/Tests/VarExporterTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php index 852e30c393885..cd10c7af37a8a 100644 --- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php +++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php @@ -313,7 +313,7 @@ public function __construct(array $array) parent::__construct($array, 1); } - public function setFlags($flags) + public function setFlags($flags): void { throw new \BadMethodCallException('Calling MyArrayObject::setFlags() is forbidden'); } @@ -341,12 +341,12 @@ public function __construct(bool $throw = true) final class FinalArrayIterator extends \ArrayIterator { - public function serialize() + public function serialize(): string { return serialize([123, parent::serialize()]); } - public function unserialize($data) + public function unserialize($data): void { if ('' === $data) { throw new \InvalidArgumentException('Serialized data is empty.'); From ab3c43f5476d7b74c97b892b304b627645f2c72e Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Thu, 5 Aug 2021 01:19:25 +0200 Subject: [PATCH 25/86] Fix return types for PHP 8.1 Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../Storage/Handler/MarshallingSessionHandler.php | 10 +++++++++- .../Storage/Handler/MarshallingSessionHandlerTest.php | 2 +- .../Component/VarDumper/Tests/Caster/CasterTest.php | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php index e1cad6a9454e5..c321c8c932377 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MarshallingSessionHandler.php @@ -30,6 +30,7 @@ public function __construct(AbstractSessionHandler $handler, MarshallerInterface /** * @return bool */ + #[\ReturnTypeWillChange] public function open($savePath, $name) { return $this->handler->open($savePath, $name); @@ -38,6 +39,7 @@ public function open($savePath, $name) /** * @return bool */ + #[\ReturnTypeWillChange] public function close() { return $this->handler->close(); @@ -46,14 +48,16 @@ public function close() /** * @return bool */ + #[\ReturnTypeWillChange] public function destroy($sessionId) { return $this->handler->destroy($sessionId); } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { return $this->handler->gc($maxlifetime); @@ -62,6 +66,7 @@ public function gc($maxlifetime) /** * @return string */ + #[\ReturnTypeWillChange] public function read($sessionId) { return $this->marshaller->unmarshall($this->handler->read($sessionId)); @@ -70,6 +75,7 @@ public function read($sessionId) /** * @return bool */ + #[\ReturnTypeWillChange] public function write($sessionId, $data) { $failed = []; @@ -85,6 +91,7 @@ public function write($sessionId, $data) /** * @return bool */ + #[\ReturnTypeWillChange] public function validateId($sessionId) { return $this->handler->validateId($sessionId); @@ -93,6 +100,7 @@ public function validateId($sessionId) /** * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { return $this->handler->updateTimestamp($sessionId, $data); diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MarshallingSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MarshallingSessionHandlerTest.php index db8c7432707c0..7216cdd1ece74 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MarshallingSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MarshallingSessionHandlerTest.php @@ -72,7 +72,7 @@ public function testGc() $marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller); $this->handler->expects($this->once())->method('gc') - ->with(4711)->willReturn(true); + ->with(4711)->willReturn(1); $marshallingSessionHandler->gc(4711); } diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php index f0a1fbbe8b045..c39e82cf6adb0 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php @@ -164,7 +164,7 @@ public function testAnonymousClass() , $c ); - $c = eval('return new class implements \Countable { private $foo = "foo"; public function count() { return 0; } };'); + $c = eval('return new class implements \Countable { private $foo = "foo"; public function count(): int { return 0; } };'); $this->assertDumpMatchesFormat( <<<'EOTXT' From bf9dca3f1727ca339fdbee7eda083beec628914a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Thu, 5 Aug 2021 01:33:30 +0200 Subject: [PATCH 26/86] Don't pass null to strpos() Signed-off-by: Alexander M. Turek <me@derrabus.de> --- src/Symfony/Component/HttpFoundation/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index ab22200fc941b..39f6cfee4e3bf 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1333,7 +1333,7 @@ public static function getMimeTypes(string $format) public function getFormat(?string $mimeType) { $canonicalMimeType = null; - if (false !== $pos = strpos($mimeType, ';')) { + if ($mimeType && false !== $pos = strpos($mimeType, ';')) { $canonicalMimeType = trim(substr($mimeType, 0, $pos)); } From d8b2f49bd835025624cec91efc9ecd8a7eb01fdf Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Thu, 5 Aug 2021 01:50:27 +0200 Subject: [PATCH 27/86] Don't pass null to preg_replace() Signed-off-by: Alexander M. Turek <me@derrabus.de> --- src/Symfony/Component/Console/Helper/Helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php index 881b4dc4fb4a1..a008166b9827e 100644 --- a/src/Symfony/Component/Console/Helper/Helper.php +++ b/src/Symfony/Component/Console/Helper/Helper.php @@ -170,7 +170,7 @@ public static function removeDecoration(OutputFormatterInterface $formatter, ?st // remove <...> formatting $string = $formatter->format($string ?? ''); // remove already formatted characters - $string = preg_replace("/\033\[[^m]*m/", '', $string); + $string = preg_replace("/\033\[[^m]*m/", '', $string ?? ''); $formatter->setDecorated($isDecorated); return $string; From af37c646b5bb7f9562bc2a5d4634811d3d3f109c Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Thu, 5 Aug 2021 07:31:49 +0200 Subject: [PATCH 28/86] Fix broken mock Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../Storage/Proxy/SessionHandlerProxyTest.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php index 1422eccfbc049..972a2745132e1 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php @@ -103,17 +103,21 @@ public function testRead() public function testWrite() { $this->mock->expects($this->once()) - ->method('write'); + ->method('write') + ->willReturn(true) + ; - $this->proxy->write('id', 'data'); + $this->assertTrue($this->proxy->write('id', 'data')); } public function testDestroy() { $this->mock->expects($this->once()) - ->method('destroy'); + ->method('destroy') + ->willReturn(true) + ; - $this->proxy->destroy('id'); + $this->assertTrue($this->proxy->destroy('id')); } public function testGc() @@ -149,7 +153,9 @@ public function testUpdateTimestamp() $proxy->updateTimestamp('id', 'data'); $this->mock->expects($this->once()) - ->method('write'); + ->method('write') + ->willReturn(true) + ; $this->proxy->updateTimestamp('id', 'data'); } From 0a46d3793d0190cfdc418d1ca8b529c71f191728 Mon Sep 17 00:00:00 2001 From: Tomas <norkunas.tom@gmail.com> Date: Thu, 5 Aug 2021 13:47:43 +0300 Subject: [PATCH 29/86] Fix ExecutionContextInterface::setParameter phpdoc example --- .../Component/Validator/Context/ExecutionContextInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index 14f7617e43fb2..f23182e473fbe 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -76,8 +76,8 @@ public function addViolation($message, array $params = []); * add the violation when you're done with the configuration: * * $context->buildViolation('Please enter a number between %min% and %max%.') - * ->setParameter('%min%', 3) - * ->setParameter('%max%', 10) + * ->setParameter('%min%', '3') + * ->setParameter('%max%', '10') * ->setTranslationDomain('number_validation') * ->addViolation(); * From b43da3a714da28d79dabb61a8a1e9a3f747e26aa Mon Sep 17 00:00:00 2001 From: Fabien Salathe <fabacrans@gmail.com> Date: Mon, 26 Jul 2021 17:08:08 +0200 Subject: [PATCH 30/86] [FrameworkBundle] Update cache:clear help --- .../Bundle/FrameworkBundle/Command/CacheClearCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 908858019b371..d112c9b086c0f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -59,7 +59,7 @@ protected function configure() ]) ->setDescription('Clear the cache') ->setHelp(<<<'EOF' -The <info>%command.name%</info> command clears the application cache for a given environment +The <info>%command.name%</info> command clears and warms up the application cache for a given environment and debug mode: <info>php %command.full_name% --env=dev</info> From 2f742bc25ffa082e46138fe8b1efa9621991ce1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Ols=CC=8Cavsky=CC=81?= <molsavsky1@gmail.com> Date: Wed, 4 Aug 2021 10:56:59 +0200 Subject: [PATCH 31/86] Do not add namespace argument to NullAdapter in CachePoolPass --- .../DependencyInjection/CachePoolPass.php | 5 +++-- .../DependencyInjection/CachePoolPassTest.php | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php index f52d0271e4117..c707ad9a28793 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php @@ -14,6 +14,7 @@ use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\ChainAdapter; +use Symfony\Component\Cache\Adapter\NullAdapter; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -130,7 +131,7 @@ public function process(ContainerBuilder $container) $chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider']))); } - if (isset($tags[0]['namespace']) && ArrayAdapter::class !== $adapter->getClass()) { + if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) { $chainedPool->replaceArgument($i++, $tags[0]['namespace']); } @@ -155,7 +156,7 @@ public function process(ContainerBuilder $container) if ($tags[0][$attr]) { $pool->addTag($this->kernelResetTag, ['method' => $tags[0][$attr]]); } - } elseif ('namespace' !== $attr || ArrayAdapter::class !== $class) { + } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) { $pool->replaceArgument($i++, $tags[0][$attr]); } unset($tags[0][$attr]); diff --git a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php index 9769b3992e88f..a77df6b1ec9ad 100644 --- a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php +++ b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Adapter\ApcuAdapter; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\ChainAdapter; +use Symfony\Component\Cache\Adapter\NullAdapter; use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DependencyInjection\CachePoolPass; use Symfony\Component\DependencyInjection\ChildDefinition; @@ -116,6 +117,23 @@ public function testNamespaceArgumentIsNotReplacedIfArrayAdapterIsUsed() $this->assertCount(0, $container->getDefinition('app.cache_pool')->getArguments()); } + public function testNamespaceArgumentIsNotReplacedIfNullAdapterIsUsed() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + + $container->register('cache.adapter.null', NullAdapter::class); + + $cachePool = new ChildDefinition('cache.adapter.null'); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertCount(0, $container->getDefinition('app.cache_pool')->getArguments()); + } + public function testArgsAreReplaced() { $container = new ContainerBuilder(); From 2982eec5f12500926c02e0ca882af6cd486a6e18 Mon Sep 17 00:00:00 2001 From: Richard van Laak <rvanlaak@gmail.com> Date: Tue, 20 Jul 2021 12:33:05 +0200 Subject: [PATCH 32/86] Report mismatches between trans-unit id and source text via status script --- .github/workflows/integration-tests.yml | 10 ++ .../Resources/bin/translation-status.php | 93 ++++++++++++++++--- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 4074f78d39356..9832c8a9d09a2 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -117,3 +117,13 @@ jobs: # 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 + + - uses: marceloprado/has-changed-path@v1 + id: changed-translation-files + with: + paths: src/**/Resources/translations/*.xlf + + - name: Check Translation Status + if: steps.changed-translation-files.outputs.changed == 'true' + run: | + php src/Symfony/Component/Translation/Resources/bin/translation-status.php -v diff --git a/src/Symfony/Component/Translation/Resources/bin/translation-status.php b/src/Symfony/Component/Translation/Resources/bin/translation-status.php index 4e0723bb40615..a769164273a6a 100644 --- a/src/Symfony/Component/Translation/Resources/bin/translation-status.php +++ b/src/Symfony/Component/Translation/Resources/bin/translation-status.php @@ -19,13 +19,16 @@ # show the translation status of all locales $ php translation-status.php - # show the translation status of all locales and all their missing translations + # only show the translation status of incomplete or erroneous locales + $ php translation-status.php --incomplete + + # show the translation status of all locales, all their missing translations and mismatches between trans-unit id and source $ php translation-status.php -v # show the status of a single locale $ php translation-status.php fr - # show the status of a single locale and all its missing translations + # show the status of a single locale, missing translations and mismatches between trans-unit id and source $ php translation-status.php fr -v END; @@ -35,6 +38,8 @@ 'verbose_output' => false, // NULL = analyze all locales 'locale_to_analyze' => null, + // append --incomplete to only show incomplete languages + 'include_completed_languages' => true, // the reference files all the other translations are compared to 'original_files' => [ 'src/Symfony/Component/Form/Resources/translations/validators.en.xlf', @@ -46,12 +51,17 @@ $argc = $_SERVER['argc']; $argv = $_SERVER['argv']; -if ($argc > 3) { +if ($argc > 4) { echo str_replace('translation-status.php', $argv[0], $usageInstructions); exit(1); } foreach (array_slice($argv, 1) as $argumentOrOption) { + if ('--incomplete' === $argumentOrOption) { + $config['include_completed_languages'] = false; + continue; + } + if (str_starts_with($argumentOrOption, '-')) { $config['verbose_output'] = true; } else { @@ -67,6 +77,7 @@ } $totalMissingTranslations = 0; +$totalTranslationMismatches = 0; foreach ($config['original_files'] as $originalFilePath) { $translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']); @@ -75,11 +86,14 @@ $totalMissingTranslations += array_sum(array_map(function ($translation) { return count($translation['missingKeys']); }, array_values($translationStatus))); + $totalTranslationMismatches += array_sum(array_map(function ($translation) { + return count($translation['mismatches']); + }, array_values($translationStatus))); - printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output']); + printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output'], $config['include_completed_languages']); } -exit($totalMissingTranslations > 0 ? 1 : 0); +exit($totalTranslationMismatches > 0 ? 1 : 0); function findTranslationFiles($originalFilePath, $localeToAnalyze) { @@ -112,21 +126,29 @@ function calculateTranslationStatus($originalFilePath, $translationFilePaths) foreach ($translationFilePaths as $locale => $translationPath) { $translatedKeys = extractTranslationKeys($translationPath); $missingKeys = array_diff_key($allTranslationKeys, $translatedKeys); + $mismatches = findTransUnitMismatches($allTranslationKeys, $translatedKeys); $translationStatus[$locale] = [ 'total' => count($allTranslationKeys), 'translated' => count($translatedKeys), 'missingKeys' => $missingKeys, + 'mismatches' => $mismatches, ]; + $translationStatus[$locale]['is_completed'] = isTranslationCompleted($translationStatus[$locale]); } return $translationStatus; } -function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput) +function isTranslationCompleted(array $translationStatus): bool +{ + return $translationStatus['total'] === $translationStatus['translated'] && 0 === count($translationStatus['mismatches']); +} + +function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput, $includeCompletedLanguages) { printTitle($originalFilePath); - printTable($translationStatus, $verboseOutput); + printTable($translationStatus, $verboseOutput, $includeCompletedLanguages); echo \PHP_EOL.\PHP_EOL; } @@ -152,13 +174,35 @@ function extractTranslationKeys($filePath) return $translationKeys; } +/** + * Check whether the trans-unit id and source match with the base translation. + */ +function findTransUnitMismatches(array $baseTranslationKeys, array $translatedKeys): array +{ + $mismatches = []; + + foreach ($baseTranslationKeys as $translationId => $translationKey) { + if (!isset($translatedKeys[$translationId])) { + continue; + } + if ($translatedKeys[$translationId] !== $translationKey) { + $mismatches[$translationId] = [ + 'found' => $translatedKeys[$translationId], + 'expected' => $translationKey, + ]; + } + } + + return $mismatches; +} + function printTitle($title) { echo $title.\PHP_EOL; echo str_repeat('=', strlen($title)).\PHP_EOL.\PHP_EOL; } -function printTable($translations, $verboseOutput) +function printTable($translations, $verboseOutput, bool $includeCompletedLanguages) { if (0 === count($translations)) { echo 'No translations found'; @@ -168,24 +212,47 @@ function printTable($translations, $verboseOutput) $longestLocaleNameLength = max(array_map('strlen', array_keys($translations))); foreach ($translations as $locale => $translation) { + if (!$includeCompletedLanguages && $translation['is_completed']) { + continue; + } + if ($translation['translated'] > $translation['total']) { textColorRed(); - } elseif ($translation['translated'] === $translation['total']) { + } elseif (count($translation['mismatches']) > 0) { + textColorRed(); + } elseif ($translation['is_completed']) { textColorGreen(); } - echo sprintf('| Locale: %-'.$longestLocaleNameLength.'s | Translated: %d/%d', $locale, $translation['translated'], $translation['total']).\PHP_EOL; + echo sprintf( + '| Locale: %-'.$longestLocaleNameLength.'s | Translated: %2d/%2d | Mismatches: %d |', + $locale, + $translation['translated'], + $translation['total'], + count($translation['mismatches']) + ).\PHP_EOL; textColorNormal(); + $shouldBeClosed = false; if (true === $verboseOutput && count($translation['missingKeys']) > 0) { - echo str_repeat('-', 80).\PHP_EOL; - echo '| Missing Translations:'.\PHP_EOL; + echo '| Missing Translations:'.\PHP_EOL; foreach ($translation['missingKeys'] as $id => $content) { - echo sprintf('| (id=%s) %s', $id, $content).\PHP_EOL; + echo sprintf('| (id=%s) %s', $id, $content).\PHP_EOL; } + $shouldBeClosed = true; + } + if (true === $verboseOutput && count($translation['mismatches']) > 0) { + echo '| Mismatches between trans-unit id and source:'.\PHP_EOL; + foreach ($translation['mismatches'] as $id => $content) { + echo sprintf('| (id=%s) Expected: %s', $id, $content['expected']).\PHP_EOL; + echo sprintf('| Found: %s', $content['found']).\PHP_EOL; + } + $shouldBeClosed = true; + } + if ($shouldBeClosed) { echo str_repeat('-', 80).\PHP_EOL; } } From ad1ff4fe949bb39953c156e0caff081f728e0d8e Mon Sep 17 00:00:00 2001 From: Pavel Popov <pavelpopovw@gmail.com> Date: Fri, 6 Aug 2021 22:46:30 +0300 Subject: [PATCH 33/86] Add trailing Line return if last line is non empty --- src/Symfony/Component/Mime/Crypto/DkimSigner.php | 8 +++++++- .../Component/Mime/Tests/Crypto/DkimSignerTest.php | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Mime/Crypto/DkimSigner.php b/src/Symfony/Component/Mime/Crypto/DkimSigner.php index 299c82a5ccb4b..3d046b8d9461d 100644 --- a/src/Symfony/Component/Mime/Crypto/DkimSigner.php +++ b/src/Symfony/Component/Mime/Crypto/DkimSigner.php @@ -203,7 +203,13 @@ private function hashBody(AbstractPart $body, string $bodyCanon, int $maxLength) hash_update($hash, $canon); } - if (0 === $length) { + // Add trailing Line return if last line is non empty + if (\strlen($currentLine) > 0) { + hash_update($hash, "\r\n"); + $length += \strlen("\r\n"); + } + + if (!$relaxed && 0 === $length) { hash_update($hash, "\r\n"); $length = 2; } diff --git a/src/Symfony/Component/Mime/Tests/Crypto/DkimSignerTest.php b/src/Symfony/Component/Mime/Tests/Crypto/DkimSignerTest.php index 94905dd7be9e3..e48b0c8e4e3c0 100644 --- a/src/Symfony/Component/Mime/Tests/Crypto/DkimSignerTest.php +++ b/src/Symfony/Component/Mime/Tests/Crypto/DkimSignerTest.php @@ -122,14 +122,14 @@ public function getCanonicalizeHeaderData() DkimSigner::CANON_SIMPLE, "\r\n", '', \PHP_INT_MAX, ]; yield 'relaxed_empty' => [ - DkimSigner::CANON_RELAXED, "\r\n", '', \PHP_INT_MAX, + DkimSigner::CANON_RELAXED, '', '', \PHP_INT_MAX, ]; yield 'simple_empty_single_ending_CLRF' => [ DkimSigner::CANON_SIMPLE, "\r\n", "\r\n", \PHP_INT_MAX, ]; yield 'relaxed_empty_single_ending_CLRF' => [ - DkimSigner::CANON_RELAXED, "\r\n", "\r\n", \PHP_INT_MAX, + DkimSigner::CANON_RELAXED, '', "\r\n", \PHP_INT_MAX, ]; yield 'simple_multiple_ending_CLRF' => [ From 29afac2064246a9bb1af6cc403e9fda357e55e67 Mon Sep 17 00:00:00 2001 From: Zairig Imad <imadzairig@gmail.com> Date: Sat, 7 Aug 2021 20:52:22 +0100 Subject: [PATCH 34/86] [Notifier] fix typo firebase --- .../Component/Notifier/Bridge/Firebase/FirebaseTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php index bd1833947ee54..f53f8ec075208 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php @@ -78,7 +78,7 @@ protected function doSend(MessageInterface $message): SentMessage try { $statusCode = $response->getStatusCode(); } catch (TransportExceptionInterface $e) { - throw new TransportException('Could not reach the remote Forebase server.', $response, 0, $e); + throw new TransportException('Could not reach the remote Firebase server.', $response, 0, $e); } $contentType = $response->getHeaders(false)['content-type'][0] ?? ''; From b9341b7d44617e493455a6f21dad84357ce9cdb1 Mon Sep 17 00:00:00 2001 From: Wahyu Kristianto <w.kristories@gmail.com> Date: Sun, 8 Aug 2021 11:32:25 +0700 Subject: [PATCH 35/86] [Security][Validator] Add missing translations for Indonesian (id) --- .../Core/Resources/translations/security.id.xlf | 12 ++++++++++-- .../Resources/translations/validators.id.xlf | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf index 91315bdf1d016..119e2d0cd70fb 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.id.xlf @@ -64,11 +64,19 @@ </trans-unit> <trans-unit id="17"> <source>Too many failed login attempts, please try again later.</source> - <target>Terlalu banyak percobaan login yang salah, Silahkan coba lagi nanti.</target> + <target>Terlalu banyak percobaan login yang salah, silahkan coba lagi nanti.</target> </trans-unit> <trans-unit id="18"> <source>Invalid or expired login link.</source> - <target>Link login salah atau sudah kadaluwarsa.</target> + <target>Link login salah atau sudah kedaluwarsa.</target> + </trans-unit> + <trans-unit id="19"> + <source>Too many failed login attempts, please try again in %minutes% minute.</source> + <target>Terlalu banyak percobaan login yang salah, silahkan coba lagi dalam %minutes% menit.</target> + </trans-unit> + <trans-unit id="20"> + <source>Too many failed login attempts, please try again in %minutes% minutes.</source> + <target>Terlalu banyak percobaan login yang salah, silahkan coba lagi dalam %minutes% menit.</target> </trans-unit> </body> </file> diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 40d07cf57cbb9..4793a16f32032 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -386,6 +386,10 @@ <source>This value is not a valid International Securities Identification Number (ISIN).</source> <target>Nilai ini bukan merupakan International Securities Identification Number (ISIN) yang sah.</target> </trans-unit> + <trans-unit id="100"> + <source>This value should be a valid expression.</source> + <target>Nilai ini harus berupa ekspresi yang valid.</target> + </trans-unit> </body> </file> </xliff> From 50bcb220d92ce8c368a46df55011580ee4928bb1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Mon, 9 Aug 2021 10:09:12 +0200 Subject: [PATCH 36/86] cs fix --- src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php | 1 + .../Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php | 1 + .../PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php | 1 + .../Component/Validator/Tests/Fixtures/CustomArrayObject.php | 1 + 4 files changed, 4 insertions(+) diff --git a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php index 41cb5af4cdf7b..942add40e3736 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php @@ -31,6 +31,7 @@ public function offsetExists($offset): bool /** * @param mixed $offset + * * @return mixed */ #[\ReturnTypeWillChange] diff --git a/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php b/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php index 2679948b14733..803e5561f6573 100644 --- a/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php +++ b/src/Symfony/Component/Intl/Data/Util/ArrayAccessibleResourceBundle.php @@ -46,6 +46,7 @@ public function offsetExists($offset): bool /** * @param mixed $offset + * * @return mixed */ #[\ReturnTypeWillChange] diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php index da8911ed7207f..72e053171c841 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php @@ -31,6 +31,7 @@ public function offsetExists($offset): bool /** * @param mixed $offset + * * @return mixed */ #[\ReturnTypeWillChange] diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php index f248576d2f2e5..4ca7f4a99fabe 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php @@ -31,6 +31,7 @@ public function offsetExists($offset): bool /** * @param mixed $offset + * * @return mixed */ #[\ReturnTypeWillChange] From db60d1fd87131f860672f8d11fd605bcb658652a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Mon, 9 Aug 2021 12:33:25 +0200 Subject: [PATCH 37/86] [Cache] fix wiring async cache recomputing in debug mode --- .../Cache/DependencyInjection/CacheCollectorPass.php | 9 +++++++++ .../DependencyInjection/CacheCollectorPassTest.php | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Symfony/Component/Cache/DependencyInjection/CacheCollectorPass.php b/src/Symfony/Component/Cache/DependencyInjection/CacheCollectorPass.php index 0bc7bc78e0ca7..843232e441530 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CacheCollectorPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CacheCollectorPass.php @@ -72,6 +72,15 @@ private function addToCollector(string $id, string $name, ContainerBuilder $cont } $recorder->setArguments([new Reference($innerId = $id.$this->cachePoolRecorderInnerSuffix)]); + foreach ($definition->getMethodCalls() as [$method, $args]) { + if ('setCallbackWrapper' !== $method || !$args[0] instanceof Definition || !($args[0]->getArguments()[2] ?? null) instanceof Definition) { + continue; + } + if ([new Reference($id), 'setCallbackWrapper'] == $args[0]->getArguments()[2]->getFactory()) { + $args[0]->getArguments()[2]->setFactory([new Reference($innerId), 'setCallbackWrapper']); + } + } + $definition->setTags([]); $definition->setPublic(false); diff --git a/src/Symfony/Component/Cache/Tests/DependencyInjection/CacheCollectorPassTest.php b/src/Symfony/Component/Cache/Tests/DependencyInjection/CacheCollectorPassTest.php index d0ea55313b885..8ea6950429faa 100644 --- a/src/Symfony/Component/Cache/Tests/DependencyInjection/CacheCollectorPassTest.php +++ b/src/Symfony/Component/Cache/Tests/DependencyInjection/CacheCollectorPassTest.php @@ -22,6 +22,7 @@ use Symfony\Component\Cache\Tests\Fixtures\ArrayCache; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; class CacheCollectorPassTest extends TestCase @@ -31,6 +32,13 @@ public function testProcess() $container = new ContainerBuilder(); $container ->register('fs', FilesystemAdapter::class) + ->addMethodCall('setCallbackWrapper', [(new Definition()) + ->addArgument(null) + ->addArgument(null) + ->addArgument((new Definition('callable')) + ->setFactory([new Reference('fs'), 'setCallbackWrapper']) + ), + ]) ->addTag('cache.pool'); $container ->register('tagged_fs', TagAwareAdapter::class) @@ -60,6 +68,9 @@ public function testProcess() $this->assertSame(TagAwareAdapter::class, $container->getDefinition('php')->getClass()); $this->assertFalse($collector->isPublic(), 'The "data_collector.cache" should be private after processing'); + + $innerFs = $container->getDefinition('fs.recorder_inner'); + $this->assertEquals([new Reference('fs.recorder_inner'), 'setCallbackWrapper'], $innerFs->getMethodCalls()[0][1][0]->getArgument(2)->getFactory()); } public function testProcessCacheObjectsAreDecorated() From 0f5125364e3f76be1c016b59bd9fbc7cf1f9d65c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Mon, 9 Aug 2021 14:05:14 +0200 Subject: [PATCH 38/86] cs fix --- .../PropertyAccess/Tests/Fixtures/TraversableArrayObject.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php index 26ab98575f25f..eb4da3f201342 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php @@ -31,6 +31,7 @@ public function offsetExists($offset): bool /** * @param mixed $offset + * * @return mixed */ #[\ReturnTypeWillChange] From c5cbc0d1ac228d30744d23254a1e1eb3a59f0cc0 Mon Sep 17 00:00:00 2001 From: Marco Petersen <m@rcopetersen.com> Date: Tue, 10 Aug 2021 21:52:50 +0200 Subject: [PATCH 39/86] Update Tagalog translations --- .../Security/Core/Resources/translations/security.tl.xlf | 8 ++++++++ .../Validator/Resources/translations/validators.tl.xlf | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.tl.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.tl.xlf index 5bf5304b5cae1..66547b2a3d1be 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.tl.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.tl.xlf @@ -70,6 +70,14 @@ <source>Invalid or expired login link.</source> <target>Inbalido o nagexpire na ang link para makapaglogin.</target> </trans-unit> + <trans-unit id="19"> + <source>Too many failed login attempts, please try again in %minutes% minute.</source> + <target>Madaming bagsak na pagtatangka, pakisubukan ulit pagkatapos ng %minutes% minuto.</target> + </trans-unit> + <trans-unit id="20"> + <source>Too many failed login attempts, please try again in %minutes% minute.</source> + <target>Madaming bagsak na pagtatangka, pakisubukan ulit pagkatapos ng %minutes% minuto.</target> + </trans-unit> </body> </file> </xliff> diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf index e930e59014191..90fe83bb31cb9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf @@ -386,6 +386,10 @@ <source>This value is not a valid International Securities Identification Number (ISIN).</source> <target>Ang halagang ito ay hindi wastong International Securities Identification Number (ISIN).</target> </trans-unit> + <trans-unit id="100"> + <source>This value should be a valid expression.</source> + <target>Ang halagang ito ay dapat wastong ekspresyon.</target> + </trans-unit> </body> </file> </xliff> From 2bfeb5db7e2c33a1491349531b7b90a68906f2e0 Mon Sep 17 00:00:00 2001 From: Hendrik Luup <hendrik.luup@we.ee> Date: Wed, 11 Aug 2021 17:07:37 +0300 Subject: [PATCH 40/86] Add Estonian (et) translations --- .../Resources/translations/validators.et.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.et.xlf | 83 ++++++++++++ .../Resources/translations/validators.et.xlf | 38 +++++- 3 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Component/Security/Core/Resources/translations/security.et.xlf diff --git a/src/Symfony/Component/Form/Resources/translations/validators.et.xlf b/src/Symfony/Component/Form/Resources/translations/validators.et.xlf index 1a9867fa20953..6524c86b144ee 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.et.xlf @@ -14,6 +14,126 @@ <source>The CSRF token is invalid. Please try to resubmit the form.</source> <target>CSRF-märgis on vigane. Palun proovi vormi uuesti esitada.</target> </trans-unit> + <trans-unit id="99"> + <source>This value is not a valid HTML5 color.</source> + <target>See väärtus ei ole korrektne HTML5 värv.</target> + </trans-unit> + <trans-unit id="100"> + <source>Please enter a valid birthdate.</source> + <target>Palun sisesta korrektne sünnikuupäev.</target> + </trans-unit> + <trans-unit id="101"> + <source>The selected choice is invalid.</source> + <target>Tehtud valik on vigane.</target> + </trans-unit> + <trans-unit id="102"> + <source>The collection is invalid.</source> + <target>Kogum on vigane.</target> + </trans-unit> + <trans-unit id="103"> + <source>Please select a valid color.</source> + <target>Palun vali korrektne värv.</target> + </trans-unit> + <trans-unit id="104"> + <source>Please select a valid country.</source> + <target>Palun vali korrektne riik.</target> + </trans-unit> + <trans-unit id="105"> + <source>Please select a valid currency.</source> + <target>Palun vali korrektne valuuta.</target> + </trans-unit> + <trans-unit id="106"> + <source>Please choose a valid date interval.</source> + <target>Palun vali korrektne kuupäevade vahemik.</target> + </trans-unit> + <trans-unit id="107"> + <source>Please enter a valid date and time.</source> + <target>Palun sisesta korrektne kuupäev ja kellaaeg.</target> + </trans-unit> + <trans-unit id="108"> + <source>Please enter a valid date.</source> + <target>Palun sisesta korrektne kuupäev.</target> + </trans-unit> + <trans-unit id="109"> + <source>Please select a valid file.</source> + <target>Palun vali korrektne fail.</target> + </trans-unit> + <trans-unit id="110"> + <source>The hidden field is invalid.</source> + <target>Peidetud väli on vigane.</target> + </trans-unit> + <trans-unit id="111"> + <source>Please enter an integer.</source> + <target>Palun sisesta täisarv.</target> + </trans-unit> + <trans-unit id="112"> + <source>Please select a valid language.</source> + <target>Palun vali korrektne keel.</target> + </trans-unit> + <trans-unit id="113"> + <source>Please select a valid locale.</source> + <target>Palun vali korrektne keelekood.</target> + </trans-unit> + <trans-unit id="114"> + <source>Please enter a valid money amount.</source> + <target>Palun sisesta korrektne rahaline väärtus.</target> + </trans-unit> + <trans-unit id="115"> + <source>Please enter a number.</source> + <target>Palun sisesta number.</target> + </trans-unit> + <trans-unit id="116"> + <source>The password is invalid.</source> + <target>Vigane parool.</target> + </trans-unit> + <trans-unit id="117"> + <source>Please enter a percentage value.</source> + <target>Palun sisesta protsendiline väärtus.</target> + </trans-unit> + <trans-unit id="118"> + <source>The values do not match.</source> + <target>Väärtused ei klapi.</target> + </trans-unit> + <trans-unit id="119"> + <source>Please enter a valid time.</source> + <target>Palun sisesta korrektne aeg.</target> + </trans-unit> + <trans-unit id="120"> + <source>Please select a valid timezone.</source> + <target>Palun vali korrektne ajavöönd.</target> + </trans-unit> + <trans-unit id="121"> + <source>Please enter a valid URL.</source> + <target>Palun sisesta korrektne URL.</target> + </trans-unit> + <trans-unit id="122"> + <source>Please enter a valid search term.</source> + <target>Palun sisesta korrektne otsingutermin.</target> + </trans-unit> + <trans-unit id="123"> + <source>Please provide a valid phone number.</source> + <target>Palun sisesta korrektne telefoninumber.</target> + </trans-unit> + <trans-unit id="124"> + <source>The checkbox has an invalid value.</source> + <target>Märkeruudu väärtus on vigane.</target> + </trans-unit> + <trans-unit id="125"> + <source>Please enter a valid email address.</source> + <target>Palun sisesta korrektne e-posti aadress.</target> + </trans-unit> + <trans-unit id="126"> + <source>Please select a valid option.</source> + <target>Palun tee korrektne valik.</target> + </trans-unit> + <trans-unit id="127"> + <source>Please select a valid range.</source> + <target>Palun vali korrektne vahemik.</target> + </trans-unit> + <trans-unit id="128"> + <source>Please enter a valid week.</source> + <target>Palun sisesta korrektne nädal.</target> + </trans-unit> </body> </file> </xliff> diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.et.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.et.xlf new file mode 100644 index 0000000000000..cc2b16ae853dc --- /dev/null +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.et.xlf @@ -0,0 +1,83 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Autentimisel juhtus ootamatu viga.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Autentimisandmeid ei leitud.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Autentimispäring ei õnnestunud süsteemi probleemi tõttu.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Vigased autentimisandmed.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Küpsis on juba kellegi teise poolt kasutuses.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Ressursi pärimiseks pole piisavalt õiguseid.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Vigane CSRF märgis.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Ei leitud sobivat autentimismeetodit, mis toetaks autentimismärgist.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Seanss puudub, see on kas aegunud või pole küpsised lubatud.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Identsustõendit ei leitud.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Kasutajanime ei leitud.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Kasutajakonto on aegunud.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Autentimistunnused on aegunud.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Kasutajakonto on keelatud.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Kasutajakonto on lukustatud.</target> + </trans-unit> + <trans-unit id="17"> + <source>Too many failed login attempts, please try again later.</source> + <target>Liiga palju ebaõnnestunud autentimise katseid, palun proovi hiljem uuesti.</target> + </trans-unit> + <trans-unit id="18"> + <source>Invalid or expired login link.</source> + <target>Vigane või aegunud sisselogimise link.</target> + </trans-unit> + <trans-unit id="19"> + <source>Too many failed login attempts, please try again in %minutes% minute.</source> + <target>Liiga palju ebaõnnestunud autentimise katseid, palun proovi uuesti %minutes% minuti pärast.</target> + </trans-unit> + <trans-unit id="20"> + <source>Too many failed login attempts, please try again in %minutes% minutes.</source> + <target>Liiga palju ebaõnnestunud autentimise katseid, palun proovi uuesti %minutes% minuti pärast.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf index 261b8f34e62f9..930b47f82e95a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf @@ -32,11 +32,11 @@ </trans-unit> <trans-unit id="8"> <source>One or more of the given values is invalid.</source> - <target>One or more of the given values is invalid.</target> + <target>Üks või rohkem väärtustest on vigane.</target> </trans-unit> <trans-unit id="9"> <source>This field was not expected.</source> - <target>See väli ei oodatud.</target> + <target>See väli ei olnud oodatud.</target> </trans-unit> <trans-unit id="10"> <source>This field is missing.</source> @@ -179,7 +179,7 @@ <target>Väärtus peaks olema kasutaja kehtiv salasõna.</target> </trans-unit> <trans-unit id="48"> - <source>This value should have exactly {{ limit }} characters.</source> + <source>This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.</source> <target>Väärtus peaks olema täpselt {{ limit }} tähemärk pikk.|Väärtus peaks olema täpselt {{ limit }} tähemärki pikk.</target> </trans-unit> <trans-unit id="49"> @@ -203,15 +203,15 @@ <target>PHP laiendi tõttu ebaõnnestus faili üleslaadimine.</target> </trans-unit> <trans-unit id="54"> - <source>This collection should contain {{ limit }} elements or more.</source> + <source>This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.</source> <target>Kogumikus peaks olema vähemalt {{ limit }} element.|Kogumikus peaks olema vähemalt {{ limit }} elementi.</target> </trans-unit> <trans-unit id="55"> - <source>This collection should contain {{ limit }} elements or less.</source> + <source>This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.</source> <target>Kogumikus peaks olema ülimalt {{ limit }} element.|Kogumikus peaks olema ülimalt {{ limit }} elementi.</target> </trans-unit> <trans-unit id="56"> - <source>This collection should contain exactly {{ limit }} elements.</source> + <source>This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.</source> <target>Kogumikus peaks olema täpselt {{ limit }} element.|Kogumikus peaks olema täpselt {{ limit }}|elementi.</target> </trans-unit> <trans-unit id="57"> @@ -304,7 +304,7 @@ </trans-unit> <trans-unit id="79"> <source>The host could not be resolved.</source> - <target>Peremeest ei õnnestunud lahendada.</target> + <target>Sellist domeeni ei õnnestunud leida.</target> </trans-unit> <trans-unit id="80"> <source>This value does not match the expected {{ charset }} charset.</source> @@ -366,6 +366,30 @@ <source>This value should be between {{ min }} and {{ max }}.</source> <target>See väärtus peaks olema vahemikus {{ min }} kuni {{ max }}.</target> </trans-unit> + <trans-unit id="95"> + <source>This value is not a valid hostname.</source> + <target>See väärtus pole korrektne domeeninimi.</target> + </trans-unit> + <trans-unit id="96"> + <source>The number of elements in this collection should be a multiple of {{ compared_value }}.</source> + <target>Selles kogus olevate elementide arv peab olema arvu {{ compared_value }} kordne.</target> + </trans-unit> + <trans-unit id="97"> + <source>This value should satisfy at least one of the following constraints:</source> + <target>See väärtus peab vastama vähemalt ühele järgmistest tingimustest:</target> + </trans-unit> + <trans-unit id="98"> + <source>Each element of this collection should satisfy its own set of constraints.</source> + <target>Kõik väärtused selles kogus peavad vastama oma tingimustele.</target> + </trans-unit> + <trans-unit id="99"> + <source>This value is not a valid International Securities Identification Number (ISIN).</source> + <target>See väärtus pole korrektne ISIN-kood.</target> + </trans-unit> + <trans-unit id="100"> + <source>This value should be a valid expression.</source> + <target>See väärtus pole korrektne avaldis.</target> + </trans-unit> </body> </file> </xliff> From 94d843f7669207445ba5f694858c324d9cc4090c Mon Sep 17 00:00:00 2001 From: Hendrik Luup <hendrik.luup@we.ee> Date: Fri, 13 Aug 2021 17:07:59 +0300 Subject: [PATCH 41/86] Do not use str_start_with We are not loading polyfill here so str_starts_with is not available PHP <8.0 --- .../Component/Translation/Resources/bin/translation-status.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Resources/bin/translation-status.php b/src/Symfony/Component/Translation/Resources/bin/translation-status.php index a769164273a6a..fac8acbadca32 100644 --- a/src/Symfony/Component/Translation/Resources/bin/translation-status.php +++ b/src/Symfony/Component/Translation/Resources/bin/translation-status.php @@ -62,7 +62,7 @@ continue; } - if (str_starts_with($argumentOrOption, '-')) { + if (0 === strpos($argumentOrOption, '-')) { $config['verbose_output'] = true; } else { $config['locale_to_analyze'] = $argumentOrOption; From 49c6f3e11979adb4f2fac441fe783146f3c05979 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Fri, 13 Aug 2021 17:54:02 +0200 Subject: [PATCH 42/86] Fix deprecation messages --- .../Doctrine/Security/RememberMe/DoctrineTokenProvider.php | 2 +- .../Bridge/Doctrine/Security/User/EntityUserProvider.php | 2 +- .../Bridge/Monolog/Processor/AbstractTokenProcessor.php | 2 +- .../SecurityBundle/DataCollector/SecurityDataCollector.php | 4 ++-- src/Symfony/Component/Console/Helper/Helper.php | 4 ++-- .../Ldap/Security/CheckLdapCredentialsListener.php | 4 ++-- .../Core/Authentication/AuthenticationProviderManager.php | 2 +- .../Authentication/Provider/DaoAuthenticationProvider.php | 2 +- .../Provider/LdapBindAuthenticationProvider.php | 4 ++-- .../Provider/PreAuthenticatedAuthenticationProvider.php | 2 +- .../Security/Core/Authentication/Token/AbstractToken.php | 2 +- .../Core/Authentication/Token/PreAuthenticatedToken.php | 2 +- .../Security/Core/Authentication/Token/RememberMeToken.php | 2 +- .../Core/Authentication/Token/Storage/TokenStorage.php | 2 +- .../Core/Authentication/Token/UsernamePasswordToken.php | 2 +- .../Component/Security/Core/User/ChainUserProvider.php | 4 ++-- .../Component/Security/Core/User/InMemoryUserProvider.php | 6 +++--- .../Security/Guard/Provider/GuardAuthenticationProvider.php | 2 +- .../Security/Http/Authentication/AuthenticatorManager.php | 4 ++-- .../Authentication/DefaultAuthenticationSuccessHandler.php | 4 ++-- .../Authenticator/AbstractPreAuthenticatedAuthenticator.php | 2 +- .../Security/Http/Authenticator/FormLoginAuthenticator.php | 2 +- .../Security/Http/Authenticator/HttpBasicAuthenticator.php | 2 +- .../Security/Http/Authenticator/JsonLoginAuthenticator.php | 2 +- .../Security/Http/EventListener/UserProviderListener.php | 2 +- .../Http/Firewall/AbstractAuthenticationListener.php | 2 +- .../Http/Firewall/AbstractPreAuthenticatedListener.php | 2 +- .../Security/Http/Firewall/BasicAuthenticationListener.php | 2 +- .../Component/Security/Http/Firewall/ContextListener.php | 6 +++--- .../Component/Security/Http/Firewall/SwitchUserListener.php | 4 ++-- .../Firewall/UsernamePasswordJsonAuthenticationListener.php | 2 +- .../Component/Security/Http/LoginLink/LoginLinkHandler.php | 4 ++-- .../Security/Http/RememberMe/AbstractRememberMeHandler.php | 2 +- .../RememberMe/PersistentTokenBasedRememberMeServices.php | 6 +++--- .../Http/RememberMe/TokenBasedRememberMeServices.php | 4 ++-- 35 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php index a8825e75e915f..01dce37978c94 100644 --- a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php @@ -117,7 +117,7 @@ public function createNewToken(PersistentTokenInterface $token) $sql = 'INSERT INTO rememberme_token (class, username, series, value, lastUsed) VALUES (:class, :username, :series, :value, :lastUsed)'; $paramValues = [ 'class' => $token->getClass(), - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 'username' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername(), 'series' => $token->getSeries(), 'value' => $token->getTokenValue(), diff --git a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php index 20264f4d954dd..b9bdf26e0d1ca 100644 --- a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php @@ -66,7 +66,7 @@ public function loadUserByIdentifier(string $identifier): UserInterface throw new \InvalidArgumentException(sprintf('You must either make the "%s" entity Doctrine Repository ("%s") implement "Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface" or set the "property" option in the corresponding entity provider configuration.', $this->classOrAlias, get_debug_type($repository))); } - // @deprecated since 5.3, change to $repository->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $repository->loadUserByIdentifier() in 6.0 if (method_exists($repository, 'loadUserByIdentifier')) { $user = $repository->loadUserByIdentifier($identifier); } else { diff --git a/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php b/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php index 15919978857c3..1f37d88aea4e2 100644 --- a/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php @@ -46,7 +46,7 @@ public function __invoke(array $record): array 'roles' => $token->getRoleNames(), ]; - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 if (method_exists($token, 'getUserIdentifier')) { $record['extra'][$this->getKey()]['username'] = $record['extra'][$this->getKey()]['user_identifier'] = $token->getUserIdentifier(); } else { diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index 45447f50e82b5..e6456dd05b4da 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -100,7 +100,7 @@ public function collect(Request $request, Response $response, \Throwable $except $impersonatorUser = null; if ($token instanceof SwitchUserToken) { $originalToken = $token->getOriginalToken(); - // @deprecated since 5.3, change to $originalToken->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $originalToken->getUserIdentifier() in 6.0 $impersonatorUser = method_exists($originalToken, 'getUserIdentifier') ? $originalToken->getUserIdentifier() : $originalToken->getUsername(); } @@ -130,7 +130,7 @@ public function collect(Request $request, Response $response, \Throwable $except 'token' => $token, 'token_class' => $this->hasVarDumper ? new ClassStub(\get_class($token)) : \get_class($token), 'logout_url' => $logoutUrl, - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 'user' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername(), 'roles' => $assignedRoles, 'inherited_roles' => array_unique($inheritedRoles), diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php index a008166b9827e..cfcbbd9a125f5 100644 --- a/src/Symfony/Component/Console/Helper/Helper.php +++ b/src/Symfony/Component/Console/Helper/Helper.php @@ -42,7 +42,7 @@ public function getHelperSet() /** * Returns the length of a string, using mb_strwidth if it is available. * - * @deprecated since 5.3 + * @deprecated since Symfony 5.3 * * @return int The length of the string */ @@ -154,7 +154,7 @@ public static function formatMemory(int $memory) } /** - * @deprecated since 5.3 + * @deprecated since Symfony 5.3 */ public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string) { diff --git a/src/Symfony/Component/Ldap/Security/CheckLdapCredentialsListener.php b/src/Symfony/Component/Ldap/Security/CheckLdapCredentialsListener.php index e32793c3d3bf4..c8458909b7b60 100644 --- a/src/Symfony/Component/Ldap/Security/CheckLdapCredentialsListener.php +++ b/src/Symfony/Component/Ldap/Security/CheckLdapCredentialsListener.php @@ -83,7 +83,7 @@ public function onCheckPassport(CheckPassportEvent $event) } else { throw new LogicException('Using the "query_string" config without using a "search_dn" and a "search_password" is not supported.'); } - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $username = $ldap->escape(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), '', LdapInterface::ESCAPE_FILTER); $query = str_replace('{username}', $username, $ldapBadge->getQueryString()); $result = $ldap->query($ldapBadge->getDnString(), $query)->execute(); @@ -93,7 +93,7 @@ public function onCheckPassport(CheckPassportEvent $event) $dn = $result[0]->getDn(); } else { - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $username = $ldap->escape(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), '', LdapInterface::ESCAPE_DN); $dn = str_replace('{username}', $username, $ldapBadge->getDnString()); } diff --git a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php index 92a48dc964c2d..76be0f4da328b 100644 --- a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php +++ b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php @@ -110,7 +110,7 @@ public function authenticate(TokenInterface $token) $this->eventDispatcher->dispatch(new AuthenticationSuccessEvent($result), AuthenticationEvents::AUTHENTICATION_SUCCESS); } - // @deprecated since 5.3 + // @deprecated since Symfony 5.3 if ($user = $result->getUser() instanceof UserInterface && !method_exists($result->getUser(), 'getUserIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "getUserIdentifier(): string" in user class "%s" is deprecated. This method will replace "getUsername()" in Symfony 6.0.', get_debug_type($result->getUser())); } diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index d83c1a0ca77a6..a0e01da4e1a28 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -120,7 +120,7 @@ protected function retrieveUser(string $userIdentifier, UsernamePasswordToken $t } try { - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 if (method_exists($this->userProvider, 'loadUserByIdentifier')) { $user = $this->userProvider->loadUserByIdentifier($userIdentifier); } else { diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php index 418523e20c6b9..7de715d70a122 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php @@ -70,7 +70,7 @@ protected function retrieveUser(string $userIdentifier, UsernamePasswordToken $t throw new UserNotFoundException('User identifier can not be null.'); } - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 if (method_exists($this->userProvider, 'loadUserByIdentifier')) { return $this->userProvider->loadUserByIdentifier($userIdentifier); } else { @@ -85,7 +85,7 @@ protected function retrieveUser(string $userIdentifier, UsernamePasswordToken $t */ protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 $userIdentifier = method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername(); $password = $token->getCredentials(); diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php index 4f69f33a23d95..d81e31bb07b75 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php @@ -59,7 +59,7 @@ public function authenticate(TokenInterface $token) } $userIdentifier = method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername(); - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 if (method_exists($this->userProvider, 'loadUserByIdentifier')) { $user = $this->userProvider->loadUserByIdentifier($userIdentifier); } else { diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index 0363e18428a37..d2ef93a0e54c3 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -75,7 +75,7 @@ public function getUserIdentifier(): string } if ($this->user instanceof UserInterface) { - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 return method_exists($this->user, 'getUserIdentifier') ? $this->user->getUserIdentifier() : $this->user->getUsername(); } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php index 95a4d2d780cb0..ec6d7c7168f56 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php @@ -50,7 +50,7 @@ public function __construct($user, $credentials, string $firewallName, array $ro * * @return string The provider key * - * @deprecated since 5.2, use getFirewallName() instead + * @deprecated since Symfony 5.2, use getFirewallName() instead */ public function getProviderKey() { diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php index c019195eecb62..6ad39c514afe2 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php @@ -64,7 +64,7 @@ public function setAuthenticated(bool $authenticated) * * @return string The provider secret * - * @deprecated since 5.2, use getFirewallName() instead + * @deprecated since Symfony 5.2, use getFirewallName() instead */ public function getProviderKey() { diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php b/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php index 1fc30bfcd1473..b479324498854 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php @@ -49,7 +49,7 @@ public function setToken(TokenInterface $token = null) // ensure any initializer is called $this->getToken(); - // @deprecated since 5.3 + // @deprecated since Symfony 5.3 if (!method_exists($token, 'getUserIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "getUserIdentifier(): string" in token class "%s" is deprecated. This method will replace "getUsername()" in Symfony 6.0.', get_debug_type($token)); } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php index 8228f6773955d..a087b082a187c 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php @@ -70,7 +70,7 @@ public function getCredentials() * * @return string The provider key * - * @deprecated since 5.2, use getFirewallName() instead + * @deprecated since Symfony 5.2, use getFirewallName() instead */ public function getProviderKey() { diff --git a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php index 30dfeb9b2db1a..7f40abb10ce18 100644 --- a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php @@ -60,7 +60,7 @@ public function loadUserByIdentifier(string $userIdentifier): UserInterface { foreach ($this->providers as $provider) { try { - // @deprecated since 5.3, change to $provider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $provider->loadUserByIdentifier() in 6.0 if (!method_exists($provider, 'loadUserByIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($provider)); @@ -101,7 +101,7 @@ public function refreshUser(UserInterface $user) } if ($supportedUserFound) { - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $username = method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(); $e = new UserNotFoundException(sprintf('There is no user with name "%s".', $username)); $e->setUserIdentifier($username); diff --git a/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php b/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php index 2e9ea5a27f675..d077939471aa5 100644 --- a/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php @@ -51,7 +51,7 @@ public function __construct(array $users = []) */ public function createUser(UserInterface $user) { - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $userIdentifier = strtolower(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername()); if (isset($this->users[$userIdentifier])) { throw new \LogicException('Another user with the same username already exists.'); @@ -74,7 +74,7 @@ public function loadUserByIdentifier(string $identifier): UserInterface { $user = $this->getUser($identifier); - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 return new InMemoryUser(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), $user->getPassword(), $user->getRoles(), $user->isEnabled()); } @@ -87,7 +87,7 @@ public function refreshUser(UserInterface $user) throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_debug_type($user))); } - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $storedUser = $this->getUser(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername()); $userIdentifier = method_exists($storedUser, 'getUserIdentifier') ? $storedUser->getUserIdentifier() : $storedUser->getUsername(); diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index e84a4c6a42ada..4b5c69cf92901 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php @@ -117,7 +117,7 @@ private function authenticateViaGuard(AuthenticatorInterface $guardAuthenticator if (null === $user) { $e = new UserNotFoundException(sprintf('Null returned from "%s::getUser()".', get_debug_type($guardAuthenticator))); - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 $e->setUserIdentifier(method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()); throw $e; diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php index e72eb075b163e..6afa8eadf0fa7 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php @@ -75,7 +75,7 @@ public function __construct(iterable $authenticators, TokenStorageInterface $tok public function authenticateUser(UserInterface $user, AuthenticatorInterface $authenticator, Request $request, array $badges = []): ?Response { // create an authenticated token for the User - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $token = $authenticator->createAuthenticatedToken($passport = new SelfValidatingPassport(new UserBadge(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), function () use ($user) { return $user; }), $badges), $this->firewallName); // announce the authenticated token @@ -229,7 +229,7 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, PassportInterface $passport, Request $request, AuthenticatorInterface $authenticator): ?Response { - // @deprecated since 5.3 + // @deprecated since Symfony 5.3 $user = $authenticatedToken->getUser(); if ($user instanceof UserInterface && !method_exists($user, 'getUserIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "getUserIdentifier(): string" in user class "%s" is deprecated. This method will replace "getUsername()" in Symfony 6.0.', get_debug_type($authenticatedToken->getUser())); diff --git a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php index a0f6f3ea74ac0..950f19ca6ccd1 100644 --- a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php +++ b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -30,7 +30,7 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle protected $httpUtils; protected $options; - /** @deprecated since 5.2, use $firewallName instead */ + /** @deprecated since Symfony 5.2, use $firewallName instead */ protected $providerKey; protected $firewallName; protected $defaultOptions = [ @@ -78,7 +78,7 @@ public function setOptions(array $options) * * @return string * - * @deprecated since 5.2, use getFirewallName() instead + * @deprecated since Symfony 5.2, use getFirewallName() instead */ public function getProviderKey() { diff --git a/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php index 1202444a1b647..a5736aecd800c 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/AbstractPreAuthenticatedAuthenticator.php @@ -86,7 +86,7 @@ public function supports(Request $request): ?bool public function authenticate(Request $request): PassportInterface { - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 $method = 'loadUserByIdentifier'; if (!method_exists($this->userProvider, 'loadUserByIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($this->userProvider)); diff --git a/src/Symfony/Component/Security/Http/Authenticator/FormLoginAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/FormLoginAuthenticator.php index 892f19a9a66bf..aeb84a5799de0 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/FormLoginAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/FormLoginAuthenticator.php @@ -81,7 +81,7 @@ public function authenticate(Request $request): PassportInterface { $credentials = $this->getCredentials($request); - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 $method = 'loadUserByIdentifier'; if (!method_exists($this->userProvider, 'loadUserByIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($this->userProvider)); diff --git a/src/Symfony/Component/Security/Http/Authenticator/HttpBasicAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/HttpBasicAuthenticator.php index 55ef80d80d492..ef213d30a3e34 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/HttpBasicAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/HttpBasicAuthenticator.php @@ -64,7 +64,7 @@ public function authenticate(Request $request): PassportInterface $username = $request->headers->get('PHP_AUTH_USER'); $password = $request->headers->get('PHP_AUTH_PW', ''); - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 $method = 'loadUserByIdentifier'; if (!method_exists($this->userProvider, 'loadUserByIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($this->userProvider)); diff --git a/src/Symfony/Component/Security/Http/Authenticator/JsonLoginAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/JsonLoginAuthenticator.php index 41e04aef3d763..7605bb7774312 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/JsonLoginAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/JsonLoginAuthenticator.php @@ -91,7 +91,7 @@ public function authenticate(Request $request): PassportInterface throw $e; } - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 $method = 'loadUserByIdentifier'; if (!method_exists($this->userProvider, 'loadUserByIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($this->userProvider)); diff --git a/src/Symfony/Component/Security/Http/EventListener/UserProviderListener.php b/src/Symfony/Component/Security/Http/EventListener/UserProviderListener.php index a6e78f6a1fe79..a3408789d1c71 100644 --- a/src/Symfony/Component/Security/Http/EventListener/UserProviderListener.php +++ b/src/Symfony/Component/Security/Http/EventListener/UserProviderListener.php @@ -45,7 +45,7 @@ public function checkPassport(CheckPassportEvent $event): void return; } - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 if (method_exists($this->userProvider, 'loadUserByIdentifier')) { $badge->setUserLoader([$this->userProvider, 'loadUserByIdentifier']); } else { diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php index 7b8622f22f5a4..33e2c08b64d86 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php @@ -199,7 +199,7 @@ private function onFailure(Request $request, AuthenticationException $failed): R private function onSuccess(Request $request, TokenInterface $token): Response { if (null !== $this->logger) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 $this->logger->info('User has been authenticated successfully.', ['username' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()]); } diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php index 9b9851f4ffa14..b698e1e4d7dca 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -87,7 +87,7 @@ public function authenticate(RequestEvent $event) } if (null !== $token = $this->tokenStorage->getToken()) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 if ($token instanceof PreAuthenticatedToken && $this->providerKey == $token->getFirewallName() && $token->isAuthenticated() && (method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()) === $user) { return; } diff --git a/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php index 9469fa8819c0f..2e3a8e5dcab5d 100644 --- a/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php @@ -77,7 +77,7 @@ public function authenticate(RequestEvent $event) } if (null !== $token = $this->tokenStorage->getToken()) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && (method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()) === $username) { return; } diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 25219dfd48eb3..53e948eb36969 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -234,7 +234,7 @@ protected function refreshUser(TokenInterface $token): ?TokenInterface $userDeauthenticated = true; if (null !== $this->logger) { - // @deprecated since 5.3, change to $refreshedUser->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $refreshedUser->getUserIdentifier() in 6.0 $this->logger->debug('Cannot refresh token because user has changed.', ['username' => method_exists($refreshedUser, 'getUserIdentifier') ? $refreshedUser->getUserIdentifier() : $refreshedUser->getUsername(), 'provider' => \get_class($provider)]); } @@ -244,11 +244,11 @@ protected function refreshUser(TokenInterface $token): ?TokenInterface $token->setUser($refreshedUser); if (null !== $this->logger) { - // @deprecated since 5.3, change to $refreshedUser->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $refreshedUser->getUserIdentifier() in 6.0 $context = ['provider' => \get_class($provider), 'username' => method_exists($refreshedUser, 'getUserIdentifier') ? $refreshedUser->getUserIdentifier() : $refreshedUser->getUsername()]; if ($token instanceof SwitchUserToken) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 $context['impersonator_username'] = method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getOriginalToken()->getUsername(); } diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index b765b89da7d18..2d4be7fcfe004 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -140,7 +140,7 @@ private function attemptSwitchUser(Request $request, string $username): ?TokenIn $originalToken = $this->getOriginalToken($token); if (null !== $originalToken) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 if ((method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()) === $username) { return $token; } @@ -149,7 +149,7 @@ private function attemptSwitchUser(Request $request, string $username): ?TokenIn $token = $this->attemptExitUser($request); } - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 $currentUsername = method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername(); $nonExistentUsername = '_'.md5(random_bytes(8).$username); diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php index c1a92cbd58916..9679b33ff92a5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php @@ -153,7 +153,7 @@ public function authenticate(RequestEvent $event) private function onSuccess(Request $request, TokenInterface $token): ?Response { if (null !== $this->logger) { - // @deprecated since 5.3, change to $token->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0 $this->logger->info('User has been authenticated successfully.', ['username' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()]); } diff --git a/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php b/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php index 29abec856fecf..b49fd8b1ea31b 100644 --- a/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php +++ b/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php @@ -50,7 +50,7 @@ public function createLoginLink(UserInterface $user, Request $request = null): L $expires = $expiresAt->format('U'); $parameters = [ - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 'user' => method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), 'expires' => $expires, 'hash' => $this->signatureHashUtil->computeSignatureHash($user, $expires), @@ -85,7 +85,7 @@ public function consumeLoginLink(Request $request): UserInterface $userIdentifier = $request->get('user'); try { - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 if (method_exists($this->userProvider, 'loadUserByIdentifier')) { $user = $this->userProvider->loadUserByIdentifier($userIdentifier); } else { diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php index 03ccb83649d31..97918c86cb8b4 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php @@ -63,7 +63,7 @@ abstract protected function processRememberMe(RememberMeDetails $rememberMeDetai public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): UserInterface { try { - // @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0 $method = 'loadUserByIdentifier'; if (!method_exists($this->userProvider, 'loadUserByIdentifier')) { trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($this->userProvider)); diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index c7376faa910d9..dc60806c4e9eb 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -94,7 +94,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) ); $userProvider = $this->getUserProvider($persistentToken->getClass()); - // @deprecated since 5.3, change to $persistentToken->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $persistentToken->getUserIdentifier() in 6.0 if (method_exists($persistentToken, 'getUserIdentifier')) { $userIdentifier = $persistentToken->getUserIdentifier(); } else { @@ -103,7 +103,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) $userIdentifier = $persistentToken->getUsername(); } - // @deprecated since 5.3, change to $userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $userProvider->loadUserByIdentifier() in 6.0 if (method_exists($userProvider, 'loadUserByIdentifier')) { return $userProvider->loadUserByIdentifier($userIdentifier); } else { @@ -124,7 +124,7 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt $this->tokenProvider->createNewToken( new PersistentToken( \get_class($user = $token->getUser()), - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), $series, $this->generateHash($tokenValue), diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php index a6e79f42e56d7..21725fe7ef00b 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php @@ -41,7 +41,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request) } try { $userProvider = $this->getUserProvider($class); - // @deprecated since 5.3, change to $userProvider->loadUserByIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $userProvider->loadUserByIdentifier() in 6.0 if (method_exists($userProvider, 'loadUserByIdentifier')) { $user = $userProvider->loadUserByIdentifier($userIdentifier); } else { @@ -79,7 +79,7 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt { $user = $token->getUser(); $expires = time() + $this->options['lifetime']; - // @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0 + // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 $value = $this->generateCookieValue(\get_class($user), method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), $expires, $user->getPassword()); $response->headers->setCookie( From dac74edf3e87495726ee15fadff3e8a6a564f411 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Sun, 15 Aug 2021 12:54:18 +0200 Subject: [PATCH 43/86] [Security] Remove faulty legacy mark from SwitchUserListenerTest --- .../Security/Http/Tests/Firewall/SwitchUserListenerTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index 54bc144ed093d..6c9ecc5cc28ac 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -30,9 +30,6 @@ use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -/** - * @group legacy - */ class SwitchUserListenerTest extends TestCase { private $tokenStorage; From f75f7582843f28e23deff97d37091a9562199bcf Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Mon, 16 Aug 2021 21:37:05 +0200 Subject: [PATCH 44/86] Show nice CLI output in Psalm action --- .github/workflows/psalm.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index a9adb8e7cf532..9c126e2ef2422 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -52,4 +52,5 @@ jobs: - name: Psalm run: | + ./vendor/bin/psalm.phar --no-progress ./vendor/bin/psalm.phar --output-format=github --no-progress From ca80ee3cd6af13b95c76387d1533a1249e4fab06 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Tue, 17 Aug 2021 13:01:12 +0200 Subject: [PATCH 45/86] [Security] Fix wrong cache directive when using the new PUBLIC_ACCESS attribute --- .../Security/UserChangingUserProvider.php | 3 +- .../Hasher/UserPasswordHasher.php | 2 +- .../Tests/Hasher/UserPasswordHasherTest.php | 2 +- .../Security/Http/Firewall/AccessListener.php | 8 +++- .../Tests/Firewall/AccessListenerTest.php | 37 +++++++++++++++++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php index e7206f4020726..a5306b6bf1607 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\RememberMeBundle\Security; +use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\User; use Symfony\Component\Security\Core\User\UserInterface; @@ -39,7 +40,7 @@ public function refreshUser(UserInterface $user) { $user = $this->inner->refreshUser($user); - $alterUser = \Closure::bind(function (User $user) { $user->password = 'foo'; }, null, User::class); + $alterUser = \Closure::bind(function (InMemoryUser $user) { $user->password = 'foo'; }, null, class_exists(User::class) ? User::class : InMemoryUser::class); $alterUser($user); return $user; diff --git a/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php b/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php index 4ec8a1b6ab248..dcc65e9dfc8a6 100644 --- a/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php +++ b/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php @@ -50,7 +50,7 @@ public function hashPassword($user, string $plainPassword): string } elseif ($user instanceof UserInterface) { $salt = $user->getSalt(); - if (null !== $salt) { + if ($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)); } } diff --git a/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php b/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php index b483864d22d53..32805b1917ec7 100644 --- a/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php +++ b/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php @@ -158,7 +158,7 @@ public function testNeedsRehash() $passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory); - \Closure::bind(function () use ($passwordHasher) { $this->password = $passwordHasher->hashPassword($this, 'foo', 'salt'); }, $user, User::class)(); + \Closure::bind(function () use ($passwordHasher) { $this->password = $passwordHasher->hashPassword($this, 'foo', 'salt'); }, $user, class_exists(User::class) ? User::class : InMemoryUser::class)(); $this->assertFalse($passwordHasher->needsRehash($user)); $this->assertTrue($passwordHasher->needsRehash($user)); $this->assertFalse($passwordHasher->needsRehash($user)); diff --git a/src/Symfony/Component/Security/Http/Firewall/AccessListener.php b/src/Symfony/Component/Security/Http/Firewall/AccessListener.php index ec6b0b79e1e37..4864403eae0ac 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AccessListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AccessListener.php @@ -75,7 +75,13 @@ public function authenticate(RequestEvent $event) $attributes = $request->attributes->get('_access_control_attributes'); $request->attributes->remove('_access_control_attributes'); - if (!$attributes || ([AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes && $event instanceof LazyResponseEvent)) { + if ( + !$attributes + || ( + ([AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes || [AuthenticatedVoter::PUBLIC_ACCESS] === $attributes) + && $event instanceof LazyResponseEvent + ) + ) { return; } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/AccessListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/AccessListenerTest.php index aac67379b4e7f..0faa43341ed0d 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/AccessListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/AccessListenerTest.php @@ -360,4 +360,41 @@ public function testHandleMWithultipleAttributesShouldBeHandledAsAnd() $listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST)); } + + public function testLazyPublicPagesShouldNotAccessTokenStorage() + { + $tokenStorage = $this->createMock(TokenStorageInterface::class); + $tokenStorage->expects($this->never())->method('getToken'); + + $request = new Request(); + $accessMap = $this->createMock(AccessMapInterface::class); + $accessMap->expects($this->any()) + ->method('getPatterns') + ->with($this->equalTo($request)) + ->willReturn([[AuthenticatedVoter::PUBLIC_ACCESS], null]) + ; + + $listener = new AccessListener($tokenStorage, $this->createMock(AccessDecisionManagerInterface::class), $accessMap, $this->createMock(AuthenticationManagerInterface::class), false); + $listener(new LazyResponseEvent(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST))); + } + + /** + * @group legacy + */ + public function testLegacyLazyPublicPagesShouldNotAccessTokenStorage() + { + $tokenStorage = $this->createMock(TokenStorageInterface::class); + $tokenStorage->expects($this->never())->method('getToken'); + + $request = new Request(); + $accessMap = $this->createMock(AccessMapInterface::class); + $accessMap->expects($this->any()) + ->method('getPatterns') + ->with($this->equalTo($request)) + ->willReturn([[AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY], null]) + ; + + $listener = new AccessListener($tokenStorage, $this->createMock(AccessDecisionManagerInterface::class), $accessMap, $this->createMock(AuthenticationManagerInterface::class), false); + $listener(new LazyResponseEvent(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST))); + } } From 25dac25d079899152dcbfa87a8c9d43552a7c353 Mon Sep 17 00:00:00 2001 From: Brad Jones <brad@bradjonesllc.com> Date: Tue, 17 Aug 2021 23:34:26 -0600 Subject: [PATCH 46/86] Update NativeSessionStorage docblock to match defaults Symfony overrides a number of PHP's default session INI values, including `use_strict_mode`. This was enabled by default in the HTTP framework bundle in 3.4 https://github.com/symfony/symfony/blob/8ac480a5eaa31595ca4f7c3e29106e9d4ba45527/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md#340 but the docblock was not updated to correspond with this change. --- .../HttpFoundation/Session/Storage/NativeSessionStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index 97975dba92b4f..916961f5eed5c 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -86,7 +86,7 @@ class NativeSessionStorage implements SessionStorageInterface * name, "PHPSESSID" * referer_check, "" * serialize_handler, "php" - * use_strict_mode, "0" + * use_strict_mode, "1" * use_cookies, "1" * use_only_cookies, "1" * use_trans_sid, "0" From 69904582ba67071166836426c920eb428c79b0aa Mon Sep 17 00:00:00 2001 From: Martin Herndl <martin@herndl.org> Date: Wed, 18 Aug 2021 10:29:30 +0200 Subject: [PATCH 47/86] [HttpKernel] Fix SplFileInfo mock in HttpKernelBrowserTest --- .../Component/HttpKernel/Tests/HttpKernelBrowserTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php index 7cd4d52d39650..b32a8955f7372 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php @@ -157,7 +157,7 @@ public function testUploadedFileWhenSizeExceedsUploadMaxFileSize() /* should be modified when the getClientSize will be removed */ $file->expects($this->any()) ->method('getSize') - ->willReturn(\INF) + ->willReturn(\PHP_INT_MAX) ; $file->expects($this->any()) ->method('getClientSize') From 45e0f520570573a7a8569443ed821fbaa14b29e4 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Wed, 18 Aug 2021 11:28:11 +0200 Subject: [PATCH 48/86] Don't produce TypeErrors for non-string CSRF tokens Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../Security/Http/Firewall/LogoutListener.php | 2 +- .../SimpleFormAuthenticationListener.php | 2 +- ...namePasswordFormAuthenticationListener.php | 2 +- .../Tests/Firewall/LogoutListenerTest.php | 20 +++- ...PasswordFormAuthenticationListenerTest.php | 98 ++++++++++++++++--- 5 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php b/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php index e78f21826f362..83aba4166a6e4 100644 --- a/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/LogoutListener.php @@ -87,7 +87,7 @@ public function authenticate(RequestEvent $event) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { + if (!\is_string($csrfToken) || false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new LogoutException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index f158d906a4c5f..997e2e7ba04eb 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -84,7 +84,7 @@ protected function attemptAuthentication(Request $request) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { + if (!\is_string($csrfToken) || false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index b3661eae8afd1..3aaa6dd71a1af 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -72,7 +72,7 @@ protected function attemptAuthentication(Request $request) if (null !== $this->csrfTokenManager) { $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); - if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { + if (!\is_string($csrfToken) || false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php index 397639fd940f7..4e86dccdd8c39 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php @@ -152,7 +152,10 @@ public function testSuccessHandlerReturnsNonResponse() $listener($event); } - public function testCsrfValidationFails() + /** + * @dataProvider provideInvalidCsrfTokens + */ + public function testCsrfValidationFails($invalidToken) { $this->expectException(LogoutException::class); $tokenManager = $this->getTokenManager(); @@ -160,20 +163,31 @@ public function testCsrfValidationFails() [$listener, , $httpUtils, $options] = $this->getListener(null, $tokenManager); $request = new Request(); - $request->query->set('_csrf_token', 'token'); + if (null !== $invalidToken) { + $request->query->set('_csrf_token', $invalidToken); + } $httpUtils->expects($this->once()) ->method('checkRequestPath') ->with($request, $options['logout_path']) ->willReturn(true); - $tokenManager->expects($this->once()) + $tokenManager ->method('isTokenValid') ->willReturn(false); $listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST)); } + public function provideInvalidCsrfTokens(): array + { + return [ + ['invalid'], + [['in' => 'valid']], + [null], + ]; + } + private function getTokenManager() { return $this->createMock(CsrfTokenManagerInterface::class); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php index 312014cd1a6f5..e6d9e06d8b698 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php @@ -24,6 +24,7 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Security; +use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler; use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler; @@ -37,7 +38,7 @@ class UsernamePasswordFormAuthenticationListenerTest extends TestCase /** * @dataProvider getUsernameForLength */ - public function testHandleWhenUsernameLength($username, $ok) + public function testHandleWhenUsernameLength(string $username, bool $ok) { $request = Request::create('/login_check', 'POST', ['_username' => $username]); $request->setSession($this->createMock(SessionInterface::class)); @@ -84,10 +85,8 @@ public function testHandleWhenUsernameLength($username, $ok) /** * @dataProvider postOnlyDataProvider */ - public function testHandleNonStringUsernameWithArray($postOnly) + public function testHandleNonStringUsernameWithArray(bool $postOnly) { - $this->expectException(BadRequestHttpException::class); - $this->expectExceptionMessage('The key "_username" must be a string, "array" given.'); $request = Request::create('/login_check', 'POST', ['_username' => []]); $request->setSession($this->createMock(SessionInterface::class)); $listener = new UsernamePasswordFormAuthenticationListener( @@ -101,16 +100,18 @@ public function testHandleNonStringUsernameWithArray($postOnly) ['require_previous_session' => false, 'post_only' => $postOnly] ); $event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST); + + $this->expectException(BadRequestHttpException::class); + $this->expectExceptionMessage('The key "_username" must be a string, "array" given.'); + $listener($event); } /** * @dataProvider postOnlyDataProvider */ - public function testHandleNonStringUsernameWithInt($postOnly) + public function testHandleNonStringUsernameWithInt(bool $postOnly) { - $this->expectException(BadRequestHttpException::class); - $this->expectExceptionMessage('The key "_username" must be a string, "integer" given.'); $request = Request::create('/login_check', 'POST', ['_username' => 42]); $request->setSession($this->createMock(SessionInterface::class)); $listener = new UsernamePasswordFormAuthenticationListener( @@ -124,16 +125,18 @@ public function testHandleNonStringUsernameWithInt($postOnly) ['require_previous_session' => false, 'post_only' => $postOnly] ); $event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST); + + $this->expectException(BadRequestHttpException::class); + $this->expectExceptionMessage('The key "_username" must be a string, "integer" given.'); + $listener($event); } /** * @dataProvider postOnlyDataProvider */ - public function testHandleNonStringUsernameWithObject($postOnly) + public function testHandleNonStringUsernameWithObject(bool $postOnly) { - $this->expectException(BadRequestHttpException::class); - $this->expectExceptionMessage('The key "_username" must be a string, "object" given.'); $request = Request::create('/login_check', 'POST', ['_username' => new \stdClass()]); $request->setSession($this->createMock(SessionInterface::class)); $listener = new UsernamePasswordFormAuthenticationListener( @@ -147,13 +150,17 @@ public function testHandleNonStringUsernameWithObject($postOnly) ['require_previous_session' => false, 'post_only' => $postOnly] ); $event = new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST); + + $this->expectException(BadRequestHttpException::class); + $this->expectExceptionMessage('The key "_username" must be a string, "object" given.'); + $listener($event); } /** * @dataProvider postOnlyDataProvider */ - public function testHandleNonStringUsernameWith__toString($postOnly) + public function testHandleNonStringUsernameWith__toString(bool $postOnly) { $usernameClass = $this->createMock(DummyUserClass::class); $usernameClass @@ -177,7 +184,63 @@ public function testHandleNonStringUsernameWith__toString($postOnly) $listener($event); } - public function postOnlyDataProvider() + /** + * @dataProvider provideInvalidCsrfTokens + */ + public function testInvalidCsrfToken($invalidToken) + { + $formBody = ['_username' => 'fabien', '_password' => 'symfony']; + if (null !== $invalidToken) { + $formBody['_csrf_token'] = $invalidToken; + } + + $request = Request::create('/login_check', 'POST', $formBody); + $request->setSession($this->createMock(SessionInterface::class)); + + $httpUtils = $this->createMock(HttpUtils::class); + $httpUtils + ->method('checkRequestPath') + ->willReturn(true) + ; + $httpUtils + ->method('createRedirectResponse') + ->willReturn(new RedirectResponse('/hello')) + ; + + $failureHandler = $this->createMock(AuthenticationFailureHandlerInterface::class); + $failureHandler + ->expects($this->once()) + ->method('onAuthenticationFailure') + ->willReturn(new Response()) + ; + + $authenticationManager = $this->createMock(AuthenticationProviderManager::class); + $authenticationManager + ->expects($this->never()) + ->method('authenticate') + ; + + $csrfTokenManager = $this->createMock(CsrfTokenManagerInterface::class); + $csrfTokenManager->method('isTokenValid')->willReturn(false); + + $listener = new UsernamePasswordFormAuthenticationListener( + $this->createMock(TokenStorageInterface::class), + $authenticationManager, + $this->createMock(SessionAuthenticationStrategyInterface::class), + $httpUtils, + 'TheProviderKey', + new DefaultAuthenticationSuccessHandler($httpUtils), + $failureHandler, + ['require_previous_session' => false], + null, + null, + $csrfTokenManager + ); + + $listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MASTER_REQUEST)); + } + + public function postOnlyDataProvider(): array { return [ [true], @@ -185,13 +248,22 @@ public function postOnlyDataProvider() ]; } - public function getUsernameForLength() + public function getUsernameForLength(): array { return [ [str_repeat('x', Security::MAX_USERNAME_LENGTH + 1), false], [str_repeat('x', Security::MAX_USERNAME_LENGTH - 1), true], ]; } + + public function provideInvalidCsrfTokens(): array + { + return [ + ['invalid'], + [['in' => 'valid']], + [null], + ]; + } } class DummyUserClass From 091769a34954a2b91e25df22ef1a4c93bd5d9676 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Wed, 18 Aug 2021 20:12:39 +0200 Subject: [PATCH 49/86] [PropertyInfo] Support for the never return type Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .github/patch-types.php | 1 + .../PropertyInfo/Extractor/ReflectionExtractor.php | 2 +- .../Tests/Extractor/ReflectionExtractorTest.php | 10 +++++++++- .../PropertyInfo/Tests/Fixtures/Php81Dummy.php | 11 +++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php diff --git a/.github/patch-types.php b/.github/patch-types.php index 4d49778403fc3..a308eda397d51 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -42,6 +42,7 @@ case false !== strpos($file, '/src/Symfony/Component/ErrorHandler/Tests/Fixtures/'): case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php'): case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php'): + case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php'): case false !== strpos($file, '/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ObjectOuter.php'): case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/NotLoadableClass.php'): case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php'): diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index d3b9b721e9c5f..0af4b9bf1bb36 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -335,7 +335,7 @@ private function extractFromReflectionType(\ReflectionType $reflectionType, \Ref foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) { $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; - if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass) { + if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass || 'never' === $phpTypeOrClass) { continue; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 60b4efdbcf815..95e1ca5cda118 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -233,7 +233,7 @@ public function php71TypesProvider() } /** - * * @dataProvider php80TypesProvider + * @dataProvider php80TypesProvider * @requires PHP 8 */ public function testExtractPhp80Type($property, array $type = null) @@ -255,6 +255,14 @@ public function php80TypesProvider() ]; } + /** + * @requires PHP 8.1 + */ + public function testExtractPhp81Type() + { + $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy', 'nothing', [])); + } + /** * @dataProvider defaultValueProvider */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php new file mode 100644 index 0000000000000..b4e896a434524 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php @@ -0,0 +1,11 @@ +<?php + +namespace Symfony\Component\PropertyInfo\Tests\Fixtures; + +class Php81Dummy +{ + public function getNothing(): never + { + throw new \Exception('Oops'); + } +} From ee614c3d30ec9f98fe92192627554a6ea65d647a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Wed, 18 Aug 2021 21:10:23 +0200 Subject: [PATCH 50/86] Remove broken test case Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../DataTransformer/DateTimeToStringTransformerTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php index 60d9d5a84e428..dc01ba15503d9 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php @@ -17,9 +17,9 @@ class DateTimeToStringTransformerTest extends TestCase { - public function dataProvider() + public function dataProvider(): array { - $data = [ + return [ ['Y-m-d H:i:s', '2010-02-03 16:05:06', '2010-02-03 16:05:06 UTC'], ['Y-m-d H:i:00', '2010-02-03 16:05:00', '2010-02-03 16:05:00 UTC'], ['Y-m-d H:i', '2010-02-03 16:05', '2010-02-03 16:05:00 UTC'], @@ -36,7 +36,6 @@ public function dataProvider() // different day representations ['Y-m-j', '2010-02-3', '2010-02-03 00:00:00 UTC'], - ['z', '33', '1970-02-03 00:00:00 UTC'], // not bijective // this will not work as PHP will use actual date to replace missing info @@ -63,8 +62,6 @@ public function dataProvider() ['Y-z', '2010-33', '2010-02-03 00:00:00 UTC'], ]; - - return $data; } /** From 2155f76b6abf6352ec189d55e2199c4514af65fb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Thu, 19 Aug 2021 10:01:58 +0200 Subject: [PATCH 51/86] [Form] fix typo in Danish translation --- .../Component/Form/Resources/translations/validators.da.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf index dafe20fa02c32..b4f078ff35f40 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf @@ -120,7 +120,7 @@ </trans-unit> <trans-unit id="125"> <source>Please enter a valid email address.</source> - <target>Indtast venligst en gyldig emailaddresse.</target> + <target>Indtast venligst en gyldig e-mailadresse.</target> </trans-unit> <trans-unit id="126"> <source>Please select a valid option.</source> From e8f822df3f84a380c35b58ada8fb2bf957b930e2 Mon Sep 17 00:00:00 2001 From: Emre YILMAZ <33000794+EmreRed@users.noreply.github.com> Date: Thu, 19 Aug 2021 10:56:37 +0300 Subject: [PATCH 52/86] Update validators.tr.xlf --- .../Validator/Resources/translations/validators.tr.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 6c39fac818238..8dc9c70de500d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -386,6 +386,10 @@ <source>This value is not a valid International Securities Identification Number (ISIN).</source> <target>Bu değer geçerli bir Uluslararası Menkul Kıymetler Kimlik Numarası değil (ISIN).</target> </trans-unit> + <trans-unit id="100"> + <source>This value should be a valid expression.</source> + <target>Bu değer geçerli bir ifade olmalıdır.</target> + </trans-unit> </body> </file> </xliff> From d2f39e90536c960b48adfd709ed42484ab0978e9 Mon Sep 17 00:00:00 2001 From: Simon Ackermann <simon@hemmer.ch> Date: Mon, 16 Aug 2021 09:49:56 +0200 Subject: [PATCH 53/86] Remove polyfills from ExpressionLanguage --- src/Symfony/Component/ExpressionLanguage/Lexer.php | 6 +++--- src/Symfony/Component/ExpressionLanguage/composer.json | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Lexer.php b/src/Symfony/Component/ExpressionLanguage/Lexer.php index af859318d50d6..46d3e1c0c38e6 100644 --- a/src/Symfony/Component/ExpressionLanguage/Lexer.php +++ b/src/Symfony/Component/ExpressionLanguage/Lexer.php @@ -50,13 +50,13 @@ public function tokenize($expression) } $tokens[] = new Token(Token::NUMBER_TYPE, $number, $cursor + 1); $cursor += \strlen($match[0]); - } elseif (str_contains('([{', $expression[$cursor])) { + } elseif (false !== strpos('([{', $expression[$cursor])) { // opening bracket $brackets[] = [$expression[$cursor], $cursor]; $tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1); ++$cursor; - } elseif (str_contains(')]}', $expression[$cursor])) { + } elseif (false !== strpos(')]}', $expression[$cursor])) { // closing bracket if (empty($brackets)) { throw new SyntaxError(sprintf('Unexpected "%s".', $expression[$cursor]), $cursor, $expression); @@ -77,7 +77,7 @@ public function tokenize($expression) // operators $tokens[] = new Token(Token::OPERATOR_TYPE, $match[0], $cursor + 1); $cursor += \strlen($match[0]); - } elseif (str_contains('.,?:', $expression[$cursor])) { + } elseif (false !== strpos('.,?:', $expression[$cursor])) { // punctuation $tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1); ++$cursor; diff --git a/src/Symfony/Component/ExpressionLanguage/composer.json b/src/Symfony/Component/ExpressionLanguage/composer.json index 01922550ee40f..0e5cdadfb0573 100644 --- a/src/Symfony/Component/ExpressionLanguage/composer.json +++ b/src/Symfony/Component/ExpressionLanguage/composer.json @@ -18,7 +18,6 @@ "require": { "php": ">=7.1.3", "symfony/cache": "^3.4|^4.0|^5.0", - "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2" }, "autoload": { From b684d40f0ffbc21ae75fe15cd7c66b7bafcbe380 Mon Sep 17 00:00:00 2001 From: Pavel Popov <pavelpopovw@gmail.com> Date: Fri, 20 Aug 2021 13:35:51 +0300 Subject: [PATCH 54/86] Ignoring X-Transport header while signing email with DKIM --- src/Symfony/Component/Mime/Crypto/DkimSigner.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Mime/Crypto/DkimSigner.php b/src/Symfony/Component/Mime/Crypto/DkimSigner.php index 3d046b8d9461d..dfb6f226b5e51 100644 --- a/src/Symfony/Component/Mime/Crypto/DkimSigner.php +++ b/src/Symfony/Component/Mime/Crypto/DkimSigner.php @@ -68,6 +68,7 @@ public function sign(Message $message, array $options = []): Message throw new InvalidArgumentException('Invalid DKIM signing algorithm "%s".', $options['algorithm']); } $headersToIgnore['return-path'] = true; + $headersToIgnore['x-transport'] = true; foreach ($options['headers_to_ignore'] as $name) { $headersToIgnore[strtolower($name)] = true; } From ca787648a96150218d1861282843981908e7ba79 Mon Sep 17 00:00:00 2001 From: rtek <rtek@ryank.net> Date: Sun, 22 Aug 2021 17:39:32 -0400 Subject: [PATCH 55/86] Fix ProgressBar to correctly clear multi-line formats --- .../Component/Console/Helper/ProgressBar.php | 6 ++-- .../Console/Tests/Helper/ProgressBarTest.php | 33 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index 91fba2b587364..1c03a1d968afc 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -482,8 +482,10 @@ private function overwrite(string $message): void } $this->output->clear($lineCount); } else { - if ($this->formatLineCount > 0) { - $this->cursor->moveUp($this->formatLineCount); + for ($i = 0; $i < $this->formatLineCount; ++$i) { + $this->cursor->moveToColumn(1); + $this->cursor->clearLine(); + $this->cursor->moveUp(); } $this->cursor->moveToColumn(1); diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index e424a29dfa4a0..ef5f0622269db 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -812,7 +812,7 @@ public function testMultilineFormat() $this->assertEquals( ">---------------------------\nfoobar". $this->generateOutput("=========>------------------\nfoobar"). - "\x1B[1A\x1B[1G\x1B[2K". + "\x1B[1G\x1B[2K\x1B[1A\x1B[1G\x1B[2K". $this->generateOutput("============================\nfoobar"), stream_get_contents($output->getStream()) ); @@ -983,7 +983,7 @@ protected function generateOutput($expected) { $count = substr_count($expected, "\n"); - return ($count ? sprintf("\x1B[%dA\x1B[1G\x1b[2K", $count) : "\x1B[1G\x1B[2K").$expected; + return ($count ? str_repeat("\x1B[1G\x1b[2K\x1B[1A", $count) : '')."\x1B[1G\x1B[2K".$expected; } public function testBarWidthWithMultilineFormat() @@ -1095,4 +1095,33 @@ public function testNoWriteWhenMessageIsSame() stream_get_contents($output->getStream()) ); } + + public function testMultiLineFormatIsFullyCleared() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 3); + $bar->setFormat("%current%/%max%\n%message%\nFoo"); + + $bar->setMessage('1234567890'); + $bar->start(); + $bar->display(); + + $bar->setMessage('ABC'); + $bar->advance(); + $bar->display(); + + $bar->setMessage('A'); + $bar->advance(); + $bar->display(); + + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( + "0/3\n1234567890\nFoo". + $this->generateOutput("1/3\nABC\nFoo"). + $this->generateOutput("2/3\nA\nFoo"). + $this->generateOutput("3/3\nA\nFoo"), + stream_get_contents($output->getStream()) + ); + } } From 36b4837f78130801d015a0cecd99fe425b6b7fa1 Mon Sep 17 00:00:00 2001 From: Dmitry Derepko <xepozz@list.ru> Date: Thu, 19 Aug 2021 18:22:31 +0300 Subject: [PATCH 56/86] [Translation] Fix message key handling for the Localise provider --- .../Bridge/Lokalise/LokaliseProvider.php | 19 ++++++------ .../Lokalise/Tests/LokaliseProviderTest.php | 30 ++++++++++--------- .../Translation/Bridge/Lokalise/composer.json | 3 ++ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/Symfony/Component/Translation/Bridge/Lokalise/LokaliseProvider.php b/src/Symfony/Component/Translation/Bridge/Lokalise/LokaliseProvider.php index 7691ed186fd4f..8aca509cf0f3d 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/LokaliseProvider.php +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/LokaliseProvider.php @@ -92,7 +92,7 @@ public function write(TranslatorBagInterface $translatorBag): void $createdKeysByDomain[$domain] = $this->createKeys($keys, $domain); } - $this->updateTranslations(array_merge($createdKeysByDomain, $existingKeysByDomain), $translatorBag); + $this->updateTranslations(array_merge_recursive($createdKeysByDomain, $existingKeysByDomain), $translatorBag); } public function read(array $domains, array $locales): TranslatorBag @@ -203,7 +203,8 @@ private function createKeys(array $keys, string $domain): array continue; } - $createdKeys = array_reduce($response->toArray(false)['keys'], function ($carry, array $keyItem) { + $keys = $response->toArray(false)['keys'] ?? []; + $createdKeys = array_reduce($keys, static function ($carry, array $keyItem) { $carry[$keyItem['key_name']['web']] = $keyItem['key_id']; return $carry; @@ -232,7 +233,7 @@ private function updateTranslations(array $keysByDomain, TranslatorBagInterface 'android' => null, 'other' => null, ], - 'translations' => array_reduce($translatorBag->getCatalogues(), function ($carry, MessageCatalogueInterface $catalogue) use ($keyName, $domain) { + 'translations' => array_reduce($translatorBag->getCatalogues(), static function ($carry, MessageCatalogueInterface $catalogue) use ($keyName, $domain) { // Message could be not found because the catalogue is empty. // We must not send the key in place of the message to avoid wrong message update on the provider. if ($catalogue->get($keyName, $domain) !== $keyName) { @@ -277,7 +278,7 @@ private function getKeysIds(array $keys, string $domain): array $this->logger->error(sprintf('Unable to get keys ids from Lokalise: "%s".', $response->getContent(false))); } - return array_reduce($response->toArray(false)['keys'], function ($carry, array $keyItem) { + return array_reduce($response->toArray(false)['keys'], static function ($carry, array $keyItem) { $carry[$keyItem['key_name']['web']] = $keyItem['key_id']; return $carry; @@ -287,8 +288,8 @@ private function getKeysIds(array $keys, string $domain): array private function ensureAllLocalesAreCreated(TranslatorBagInterface $translatorBag) { $providerLanguages = $this->getLanguages(); - $missingLanguages = array_reduce($translatorBag->getCatalogues(), function ($carry, $catalogue) use ($providerLanguages) { - if (!\in_array($catalogue->getLocale(), $providerLanguages)) { + $missingLanguages = array_reduce($translatorBag->getCatalogues(), static function ($carry, $catalogue) use ($providerLanguages) { + if (!\in_array($catalogue->getLocale(), $providerLanguages, true)) { $carry[] = $catalogue->getLocale(); } @@ -313,9 +314,7 @@ private function getLanguages(): array $responseContent = $response->toArray(false); if (\array_key_exists('languages', $responseContent)) { - return array_map(function ($language) { - return $language['lang_iso']; - }, $responseContent['languages']); + return array_column($responseContent['languages'], 'lang_iso'); } return []; @@ -325,7 +324,7 @@ private function createLanguages(array $languages): void { $response = $this->client->request('POST', 'languages', [ 'json' => [ - 'languages' => array_map(function ($language) { + 'languages' => array_map(static function ($language) { return ['lang_iso' => $language]; }, $languages), ], diff --git a/src/Symfony/Component/Translation/Bridge/Lokalise/Tests/LokaliseProviderTest.php b/src/Symfony/Component/Translation/Bridge/Lokalise/Tests/LokaliseProviderTest.php index ee4926a5e02e5..9156043de3d0e 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/Tests/LokaliseProviderTest.php +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/Tests/LokaliseProviderTest.php @@ -69,14 +69,14 @@ public function testCompleteWriteProcess() $this->assertSame('POST', $method); $this->assertSame('https://api.lokalise.com/api2/projects/PROJECT_ID/languages', $url); - $this->assertSame($expectedBody, $options['body']); + $this->assertJsonStringEqualsJsonString($expectedBody, $options['body']); return new MockResponse(); }; $getKeysIdsForMessagesDomainResponse = function (string $method, string $url, array $options = []): ResponseInterface { $expectedQuery = [ - 'filter_keys' => 'a', + 'filter_keys' => 'young_dog', 'filter_filenames' => 'messages.xliff', ]; @@ -104,7 +104,7 @@ public function testCompleteWriteProcess() $expectedBody = json_encode([ 'keys' => [ [ - 'key_name' => 'a', + 'key_name' => 'young_dog', 'platforms' => ['web'], 'filenames' => [ 'web' => 'messages.xliff', @@ -117,11 +117,11 @@ public function testCompleteWriteProcess() ]); $this->assertSame('POST', $method); - $this->assertSame($expectedBody, $options['body']); + $this->assertJsonStringEqualsJsonString($expectedBody, $options['body']); return new MockResponse(json_encode(['keys' => [ [ - 'key_name' => ['web' => 'a'], + 'key_name' => ['web' => 'young_dog'], 'key_id' => 29, ], ]])); @@ -144,7 +144,7 @@ public function testCompleteWriteProcess() ]); $this->assertSame('POST', $method); - $this->assertSame($expectedBody, $options['body']); + $this->assertJsonStringEqualsJsonString($expectedBody, $options['body']); return new MockResponse(json_encode(['keys' => [ [ @@ -153,8 +153,8 @@ public function testCompleteWriteProcess() ], ]])); }; - - $updateTranslationsResponse = function (string $method, string $url, array $options = []): ResponseInterface { + $updateProcessed = false; + $updateTranslationsResponse = function (string $method, string $url, array $options = []) use (&$updateProcessed): ResponseInterface { $expectedBody = json_encode([ 'keys' => [ [ @@ -169,11 +169,11 @@ public function testCompleteWriteProcess() 'translations' => [ [ 'language_iso' => 'en', - 'translation' => 'trans_en_a', + 'translation' => 'puppy', ], [ 'language_iso' => 'fr', - 'translation' => 'trans_fr_a', + 'translation' => 'chiot', ], ], ], @@ -200,8 +200,9 @@ public function testCompleteWriteProcess() ], ]); + $updateProcessed = true; $this->assertSame('PUT', $method); - $this->assertSame($expectedBody, $options['body']); + $this->assertJsonStringEqualsJsonString($expectedBody, $options['body']); return new MockResponse(); }; @@ -221,15 +222,16 @@ public function testCompleteWriteProcess() $translatorBag = new TranslatorBag(); $translatorBag->addCatalogue(new MessageCatalogue('en', [ - 'messages' => ['a' => 'trans_en_a'], + 'messages' => ['young_dog' => 'puppy'], 'validators' => ['post.num_comments' => '{count, plural, one {# comment} other {# comments}}'], ])); $translatorBag->addCatalogue(new MessageCatalogue('fr', [ - 'messages' => ['a' => 'trans_fr_a'], + 'messages' => ['young_dog' => 'chiot'], 'validators' => ['post.num_comments' => '{count, plural, one {# commentaire} other {# commentaires}}'], ])); $provider->write($translatorBag); + $this->assertTrue($updateProcessed, 'Translations update was not called.'); } /** @@ -248,7 +250,7 @@ public function testReadForOneLocaleAndOneDomain(string $locale, string $domain, $this->assertSame('POST', $method); $this->assertSame('https://api.lokalise.com/api2/projects/PROJECT_ID/files/export', $url); - $this->assertSame($expectedBody, $options['body']); + $this->assertJsonStringEqualsJsonString($expectedBody, $options['body']); return new MockResponse(json_encode([ 'files' => [ diff --git a/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json b/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json index 4e0f1c6c94895..3c3a0fafe4476 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json @@ -21,6 +21,9 @@ "symfony/http-client": "^5.3", "symfony/translation": "^5.3" }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, "autoload": { "psr-4": { "Symfony\\Component\\Translation\\Bridge\\Lokalise\\": "" }, "exclude-from-classmap": [ From 0ef9633f47803422cdc99bf42eecaa118b2008da Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 23 Aug 2021 11:25:03 +0200 Subject: [PATCH 57/86] Remove wrong dep --- .../Component/Translation/Bridge/Lokalise/composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json b/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json index 3c3a0fafe4476..4e0f1c6c94895 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/composer.json @@ -21,9 +21,6 @@ "symfony/http-client": "^5.3", "symfony/translation": "^5.3" }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, "autoload": { "psr-4": { "Symfony\\Component\\Translation\\Bridge\\Lokalise\\": "" }, "exclude-from-classmap": [ From ac9c3067b91f29306c2b4f7908e430ed342fbfe3 Mon Sep 17 00:00:00 2001 From: Misha Klomp <misha.klomp@freshheads.com> Date: Mon, 23 Aug 2021 14:47:37 +0200 Subject: [PATCH 58/86] [Notifier] fix firebase error handling so the transports doesn't try setting the success message, that doesn't exists. --- .../Component/Notifier/Bridge/Firebase/FirebaseTransport.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php index f53f8ec075208..2ad0848bf2049 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php @@ -89,8 +89,8 @@ protected function doSend(MessageInterface $message): SentMessage throw new TransportException('Unable to post the Firebase message: '.$errorMessage, $response); } - if ($jsonContents && isset($jsonContents['results']['error'])) { - throw new TransportException('Unable to post the Firebase message: '.$jsonContents['error'], $response); + if ($jsonContents && isset($jsonContents['results'][0]['error'])) { + throw new TransportException('Unable to post the Firebase message: '.$jsonContents['results'][0]['error'], $response); } $success = $response->toArray(false); From 5812a4959926384b3cffd05054360ba556d665bd Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis <ruudk@users.noreply.github.com> Date: Tue, 24 Aug 2021 16:49:35 +0200 Subject: [PATCH 59/86] [AMQP] [Messenger] Do not leak any credentials when connection fails I noticed that when the connection to AMQP fails for whatever reason all the DSK credentials are leaked. Yes, the password is masked. But it still leaks the server, port and username. I think these things should be private and not be logged to a logger server or error capture service. --- .../Bridge/Amqp/Tests/Transport/ConnectionTest.php | 4 ++-- .../Messenger/Bridge/Amqp/Transport/Connection.php | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/ConnectionTest.php index c37d89676b2c2..c2a70639e9526 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/ConnectionTest.php @@ -559,10 +559,10 @@ public function testItDelaysTheMessageWithADifferentRoutingKeyAndTTLs() $connection->publish('{}', [], 120000); } - public function testObfuscatePasswordInDsn() + public function testNoCredentialLeakageWhenConnectionFails() { $this->expectException(\AMQPException::class); - $this->expectExceptionMessage('Could not connect to the AMQP server. Please verify the provided DSN. ({"host":"localhost","port":5672,"vhost":"/","login":"user","password":"********"})'); + $this->expectExceptionMessage('Could not connect to the AMQP server. Please verify the provided DSN.'); $factory = new TestAmqpFactory( $amqpConnection = $this->createMock(\AMQPConnection::class), $amqpChannel = $this->createMock(\AMQPChannel::class), diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index e03dc72a472c6..1dead1503ade4 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -495,11 +495,7 @@ public function channel(): \AMQPChannel try { $connection->{$connectMethod}(); } catch (\AMQPConnectionException $e) { - $credentials = $this->connectionOptions; - $credentials['password'] = '********'; - unset($credentials['delay']); - - throw new \AMQPException(sprintf('Could not connect to the AMQP server. Please verify the provided DSN. (%s).', json_encode($credentials, \JSON_UNESCAPED_SLASHES)), 0, $e); + throw new \AMQPException('Could not connect to the AMQP server. Please verify the provided DSN.', 0, $e); } $this->amqpChannel = $this->amqpFactory->createChannel($connection); From d12382921ccd057c0ca470d22682309032b7a0cb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 25 Aug 2021 09:01:23 +0200 Subject: [PATCH 60/86] [HttpKernel] skip test on appveyor --- .../Component/HttpKernel/Tests/HttpKernelBrowserTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php index b32a8955f7372..78adfa72b71e1 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelBrowserTest.php @@ -143,6 +143,10 @@ public function testUploadedFileWhenNoFileSelected() public function testUploadedFileWhenSizeExceedsUploadMaxFileSize() { + if (UploadedFile::getMaxFilesize() > \PHP_INT_MAX) { + $this->markTestSkipped('Requires PHP_INT_MAX to be greater than "upload_max_filesize" and "post_max_size" ini settings'); + } + $source = tempnam(sys_get_temp_dir(), 'source'); $kernel = new TestHttpKernel(); From 4807fbc4429acfd860b42b224b338c50402fbab1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 25 Aug 2021 09:18:49 +0200 Subject: [PATCH 61/86] Fix tests --- src/Symfony/Component/Cache/Adapter/AbstractAdapter.php | 2 +- src/Symfony/Component/Cache/Adapter/ProxyAdapter.php | 2 +- src/Symfony/Component/Cache/Traits/ApcuTrait.php | 2 +- src/Symfony/Component/Cache/composer.json | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 040a095ab11ab..71338c3c12e0a 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -51,7 +51,7 @@ static function ($key, $value, $isHit) { // Detect wrapped values that encode for their expiry and creation duration // For compactness, these values are packed in the key of an array using // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F - if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) key($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { $item->value = $v[$k]; $v = unpack('Ve/Nc', substr($k, 1, -1)); $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php index c9baa3ad3961f..d5b0593353ae9 100644 --- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php @@ -59,7 +59,7 @@ static function ($key, $innerItem) use ($poolHash) { // Detect wrapped values that encode for their expiry and creation duration // For compactness, these values are packed in the key of an array using // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F - if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) key($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { $item->value = $v[$k]; $v = unpack('Ve/Nc', substr($k, 1, -1)); $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; diff --git a/src/Symfony/Component/Cache/Traits/ApcuTrait.php b/src/Symfony/Component/Cache/Traits/ApcuTrait.php index 9a02148c14dca..b56ae4f7c39ac 100644 --- a/src/Symfony/Component/Cache/Traits/ApcuTrait.php +++ b/src/Symfony/Component/Cache/Traits/ApcuTrait.php @@ -112,7 +112,7 @@ protected function doSave(array $values, int $lifetime) } catch (\Throwable $e) { if (1 === \count($values)) { // Workaround https://github.com/krakjoe/apcu/issues/170 - apcu_delete(key($values)); + apcu_delete(array_key_first($values)); } throw $e; diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index e481d66a9d427..d71f2169e03c2 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -25,6 +25,7 @@ "psr/cache": "^1.0|^2.0", "psr/log": "^1|^2|^3", "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2", "symfony/var-exporter": "^4.2|^5.0" From 9b6110bfaad5abfe4ec4f90506e8616cfbf48874 Mon Sep 17 00:00:00 2001 From: Martin Herndl <martin@herndl.org> Date: Wed, 4 Aug 2021 11:55:03 +0200 Subject: [PATCH 62/86] [FrameworkBundle] Fall back to default configuration in debug:config and consistently resolve parameter values --- .../Command/ConfigDebugCommand.php | 52 ++++++++++++++----- .../DefaultConfigTestBundle.php | 9 ++++ .../DependencyInjection/Configuration.php | 22 ++++++++ .../DefaultConfigTestExtension.php | 18 +++++++ .../ExtensionWithoutConfigTestExtension.php | 28 ++++++++++ .../ExtensionWithoutConfigTestBundle.php | 9 ++++ .../Functional/ConfigDebugCommandTest.php | 37 +++++++++++++ .../Functional/app/ConfigDump/bundles.php | 4 ++ .../Functional/app/ConfigDump/config.yml | 1 + 9 files changed, 166 insertions(+), 14 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DefaultConfigTestBundle.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/Configuration.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/DefaultConfigTestExtension.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/ExtensionWithoutConfigTestBundle.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php index 7f0a7813a8ddd..a0623f396127b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Command; +use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -18,6 +19,8 @@ use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Compiler\ValidateEnvPlaceholdersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\Yaml\Yaml; /** @@ -77,22 +80,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $extension = $this->findExtension($name); - $container = $this->compileContainer(); - $extensionAlias = $extension->getAlias(); - $extensionConfig = []; - foreach ($container->getCompilerPassConfig()->getPasses() as $pass) { - if ($pass instanceof ValidateEnvPlaceholdersPass) { - $extensionConfig = $pass->getExtensionConfig(); - break; - } - } - - if (!isset($extensionConfig[$extensionAlias])) { - throw new \LogicException(sprintf('The extension with alias "%s" does not have configuration.', $extensionAlias)); - } + $container = $this->compileContainer(); - $config = $container->resolveEnvPlaceholders($extensionConfig[$extensionAlias]); + $config = $container->resolveEnvPlaceholders( + $container->getParameterBag()->resolveValue( + $this->getConfigForExtension($extension, $container) + ) + ); if (null === $path = $input->getArgument('path')) { $io->title( @@ -153,4 +148,33 @@ private function getConfigForPath(array $config, string $path, string $alias) return $config; } + + private function getConfigForExtension(ExtensionInterface $extension, ContainerBuilder $container): array + { + $extensionAlias = $extension->getAlias(); + + $extensionConfig = []; + foreach ($container->getCompilerPassConfig()->getPasses() as $pass) { + if ($pass instanceof ValidateEnvPlaceholdersPass) { + $extensionConfig = $pass->getExtensionConfig(); + break; + } + } + + if (isset($extensionConfig[$extensionAlias])) { + return $extensionConfig[$extensionAlias]; + } + + // Fall back to default config if the extension has one + + if (!$extension instanceof ConfigurationExtensionInterface) { + throw new \LogicException(sprintf('The extension with alias "%s" does not have configuration.', $extensionAlias)); + } + + $configs = $container->getExtensionConfig($extensionAlias); + $configuration = $extension->getConfiguration($configs, $container); + $this->validateConfiguration($extension, $configuration); + + return (new Processor())->processConfiguration($configuration, $configs); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DefaultConfigTestBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DefaultConfigTestBundle.php new file mode 100644 index 0000000000000..8c7a89574729f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DefaultConfigTestBundle.php @@ -0,0 +1,9 @@ +<?php + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\DefaultConfigTestBundle; + +use Symfony\Component\HttpKernel\Bundle\Bundle; + +class DefaultConfigTestBundle extends Bundle +{ +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/Configuration.php new file mode 100644 index 0000000000000..0c0812f3f9553 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/Configuration.php @@ -0,0 +1,22 @@ +<?php + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\DefaultConfigTestBundle\DependencyInjection; + +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; + +class Configuration implements ConfigurationInterface +{ + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('default_config_test'); + + $treeBuilder->getRootNode() + ->children() + ->scalarNode('foo')->defaultValue('%default_config_test_foo%')->end() + ->scalarNode('baz')->defaultValue('%env(BAZ)%')->end() + ->end(); + + return $treeBuilder; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/DefaultConfigTestExtension.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/DefaultConfigTestExtension.php new file mode 100644 index 0000000000000..d380bcaad17fa --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/DefaultConfigTestBundle/DependencyInjection/DefaultConfigTestExtension.php @@ -0,0 +1,18 @@ +<?php + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\DefaultConfigTestBundle\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\Extension; + +class DefaultConfigTestExtension extends Extension +{ + public function load(array $configs, ContainerBuilder $container) + { + $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); + + $container->setParameter('default_config_test', $config['foo']); + $container->setParameter('default_config_test', $config['baz']); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php new file mode 100644 index 0000000000000..e49f391bbafff --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php @@ -0,0 +1,28 @@ +<?php + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\ExtensionWithoutConfigTestBundle\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; + +class ExtensionWithoutConfigTestExtension implements ExtensionInterface +{ + public function load(array $configs, ContainerBuilder $container) + { + } + + public function getNamespace() + { + return ''; + } + + public function getXsdValidationBasePath() + { + return false; + } + + public function getAlias() + { + return 'extension_without_config_test'; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/ExtensionWithoutConfigTestBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/ExtensionWithoutConfigTestBundle.php new file mode 100644 index 0000000000000..5fe9fcdb7799f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/ExtensionWithoutConfigTestBundle.php @@ -0,0 +1,9 @@ +<?php + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\ExtensionWithoutConfigTestBundle; + +use Symfony\Component\HttpKernel\Bundle\Bundle; + +class ExtensionWithoutConfigTestBundle extends Bundle +{ +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php index 3a0b095e32292..0df853997c59a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ConfigDebugCommandTest.php @@ -58,6 +58,16 @@ public function testParametersValuesAreResolved() $this->assertStringContainsString('secret: test', $tester->getDisplay()); } + public function testDefaultParameterValueIsResolvedIfConfigIsExisting() + { + $tester = $this->createCommandTester(); + $ret = $tester->execute(['name' => 'framework']); + + $this->assertSame(0, $ret, 'Returns 0 in case of success'); + $kernelCacheDir = $this->application->getKernel()->getContainer()->getParameter('kernel.cache_dir'); + $this->assertStringContainsString(sprintf("dsn: 'file:%s/profiler'", $kernelCacheDir), $tester->getDisplay()); + } + public function testDumpUndefinedBundleOption() { $tester = $this->createCommandTester(); @@ -74,6 +84,33 @@ public function testDumpWithPrefixedEnv() $this->assertStringContainsString("cookie_httponly: '%env(bool:COOKIE_HTTPONLY)%'", $tester->getDisplay()); } + public function testDumpFallsBackToDefaultConfigAndResolvesParameterValue() + { + $tester = $this->createCommandTester(); + $ret = $tester->execute(['name' => 'DefaultConfigTestBundle']); + + $this->assertSame(0, $ret, 'Returns 0 in case of success'); + $this->assertStringContainsString('foo: bar', $tester->getDisplay()); + } + + public function testDumpFallsBackToDefaultConfigAndResolvesEnvPlaceholder() + { + $tester = $this->createCommandTester(); + $ret = $tester->execute(['name' => 'DefaultConfigTestBundle']); + + $this->assertSame(0, $ret, 'Returns 0 in case of success'); + $this->assertStringContainsString("baz: '%env(BAZ)%'", $tester->getDisplay()); + } + + public function testDumpThrowsExceptionWhenDefaultConfigFallbackIsImpossible() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The extension with alias "extension_without_config_test" does not have configuration.'); + + $tester = $this->createCommandTester(); + $tester->execute(['name' => 'ExtensionWithoutConfigTestBundle']); + } + private function createCommandTester(): CommandTester { $command = $this->application->find('debug:config'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/bundles.php index 15ff182c6fed5..c4fb0bbe8ce48 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/bundles.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/bundles.php @@ -10,9 +10,13 @@ */ use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\DefaultConfigTestBundle\DefaultConfigTestBundle; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\ExtensionWithoutConfigTestBundle\ExtensionWithoutConfigTestBundle; use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; return [ + new DefaultConfigTestBundle(), + new ExtensionWithoutConfigTestBundle(), new FrameworkBundle(), new TestBundle(), ]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/config.yml index 432e35bd2f24d..a7a03a31d6602 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ConfigDump/config.yml @@ -11,3 +11,4 @@ parameters: env(LOCALE): en env(COOKIE_HTTPONLY): '1' secret: test + default_config_test_foo: bar From 709981bedd6ab2b7f5f9b31aaf2a5e929ee9cf0b Mon Sep 17 00:00:00 2001 From: Tomasz Ignatiuk <tomasz@mobilemadness.pl> Date: Wed, 25 Aug 2021 10:50:15 +0200 Subject: [PATCH 63/86] Escape all special characters for parse_mode MARKDOWN_V2 --- .../Notifier/Bridge/Telegram/TelegramTransport.php | 2 +- .../Bridge/Telegram/Tests/TelegramTransportTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php b/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php index 60eee07d9c5d5..5b5cad8e0fb8c 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php @@ -82,7 +82,7 @@ protected function doSend(MessageInterface $message): SentMessage if (!isset($options['parse_mode']) || TelegramOptions::PARSE_MODE_MARKDOWN_V2 === $options['parse_mode']) { $options['parse_mode'] = TelegramOptions::PARSE_MODE_MARKDOWN_V2; - $options['text'] = str_replace('.', '\.', $message->getSubject()); + $options['text'] = preg_replace('/([_*\[\]()~`>#+\-=|{}.!])/', '\\\\$1', $message->getSubject()); } $response = $this->client->request('POST', $endpoint, [ diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php index 2b0cbbdf17c45..718f566b0c240 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php @@ -186,7 +186,7 @@ public function testSendWithChannelOverride() $this->assertEquals('telegram://api.telegram.org?channel=defaultChannel', $sentMessage->getTransport()); } - public function testSendWithMarkdownShouldEscapeDots() + public function testSendWithMarkdownShouldEscapeSpecialCharacters() { $response = $this->createMock(ResponseInterface::class); $response->expects($this->exactly(2)) @@ -223,7 +223,7 @@ public function testSendWithMarkdownShouldEscapeDots() $expectedBody = [ 'chat_id' => 'testChannel', - 'text' => 'I contain a \.', + 'text' => 'I contain special characters \_ \* \[ \] \( \) \~ \` \> \# \+ \- \= \| \{ \} \. \! to send\.', 'parse_mode' => 'MarkdownV2', ]; @@ -235,6 +235,6 @@ public function testSendWithMarkdownShouldEscapeDots() $transport = $this->createTransport($client, 'testChannel'); - $transport->send(new ChatMessage('I contain a .')); + $transport->send(new ChatMessage('I contain special characters _ * [ ] ( ) ~ ` > # + - = | { } . ! to send.')); } } From aec30217ce097ea32cdffecd4727190355cfd577 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Wed, 25 Aug 2021 21:27:26 +0200 Subject: [PATCH 64/86] Fix optional before mandatory parameters Signed-off-by: Alexander M. Turek <me@derrabus.de> --- src/Symfony/Component/Console/Event/ConsoleEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Event/ConsoleEvent.php b/src/Symfony/Component/Console/Event/ConsoleEvent.php index 5440da216c96f..400eb5731bad2 100644 --- a/src/Symfony/Component/Console/Event/ConsoleEvent.php +++ b/src/Symfony/Component/Console/Event/ConsoleEvent.php @@ -28,7 +28,7 @@ class ConsoleEvent extends Event private $input; private $output; - public function __construct(Command $command = null, InputInterface $input, OutputInterface $output) + public function __construct(?Command $command, InputInterface $input, OutputInterface $output) { $this->command = $command; $this->input = $input; From 7cc0c3670d10d2bb372caba3a9197b9b51d14953 Mon Sep 17 00:00:00 2001 From: "Roland Franssen :)" <franssen.roland@gmail.com> Date: Sun, 15 Aug 2021 13:06:47 +0200 Subject: [PATCH 65/86] [Translation] Reverse fallback locales --- .../Translation/Tests/TranslatorTest.php | 10 ++++++++-- .../Component/Translation/Translator.php | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index b7d2d1cd18d58..073f2255fe7f4 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -304,11 +304,17 @@ public function testTransWithIcuVariantFallbackLocale() $translator->addResource('array', ['foo' => 'foofoo'], 'en_GB_scouse'); $translator->addResource('array', ['bar' => 'foobar'], 'en_GB'); $translator->addResource('array', ['baz' => 'foobaz'], 'en_001'); - $translator->addResource('array', ['qux' => 'fooqux'], 'en'); + $translator->addResource('array', ['bar' => 'en', 'qux' => 'fooqux'], 'en'); + $translator->addResource('array', ['bar' => 'nl_NL', 'fallback' => 'nl_NL'], 'nl_NL'); + $translator->addResource('array', ['bar' => 'nl', 'fallback' => 'nl'], 'nl'); + + $translator->setFallbackLocales(['nl_NL', 'nl']); + $this->assertSame('foofoo', $translator->trans('foo')); $this->assertSame('foobar', $translator->trans('bar')); $this->assertSame('foobaz', $translator->trans('baz')); $this->assertSame('fooqux', $translator->trans('qux')); + $this->assertSame('nl_NL', $translator->trans('fallback')); } public function testTransWithIcuRootFallbackLocale() @@ -358,7 +364,7 @@ public function testTransWithFallbackLocaleTer() $translator = new Translator('fr_FR'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', ['foo' => 'foo (en_US)'], 'en_US'); - $translator->addResource('array', ['bar' => 'bar (en)'], 'en'); + $translator->addResource('array', ['foo' => 'foo (en)', 'bar' => 'bar (en)'], 'en'); $translator->setFallbackLocales(['en_US', 'en']); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index c36ae331bac8c..5eb0183cbab43 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -462,14 +462,8 @@ protected function computeFallbackLocales($locale) $this->parentLocales = json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true); } + $originLocale = $locale; $locales = []; - foreach ($this->fallbackLocales as $fallback) { - if ($fallback === $locale) { - continue; - } - - $locales[] = $fallback; - } while ($locale) { $parent = $this->parentLocales[$locale] ?? null; @@ -490,10 +484,18 @@ protected function computeFallbackLocales($locale) } if (null !== $locale) { - array_unshift($locales, $locale); + $locales[] = $locale; } } + foreach ($this->fallbackLocales as $fallback) { + if ($fallback === $originLocale) { + continue; + } + + $locales[] = $fallback; + } + return array_unique($locales); } From 074539d3c9b889f8b33b30d09633f86de1247c03 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev <plbsid@gmail.com> Date: Fri, 11 Jun 2021 17:43:27 +0300 Subject: [PATCH 66/86] Fix Url Validator false positives --- src/Symfony/Component/Validator/Constraints/UrlValidator.php | 2 +- .../Validator/Tests/Constraints/UrlValidatorTest.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 68f26d08755fa..4d962eb098760 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -26,7 +26,7 @@ class UrlValidator extends ConstraintValidator (%s):// # protocol (((?:[\_\.\pL\pN-]|%%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%%[0-9A-Fa-f]{2})+)@)? # basic auth ( - ([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name + ([\pL\pN\pS]+\.?[\pL\pN\pS\-\_]+)+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index e154c6b2df9cc..ca2a27db4c780 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -105,6 +105,7 @@ public function getValidUrls() return [ ['http://a.pl'], ['http://www.example.com'], + ['http://tt.example.com'], ['http://www.example.com.'], ['http://www.example.museum'], ['https://example.com/'], @@ -265,6 +266,10 @@ public function getInvalidUrls() ['http://example.com/exploit.html?hel lo'], ['http://example.com/exploit.html?not_a%hex'], ['http://'], + ['http://www..com'], + ['http://www..example.com'], + ['http://wwww.example..com'], + ['http://.www.example.com'], ]; } From 77bd21adfcb89b8c41154f4367089beb365ae150 Mon Sep 17 00:00:00 2001 From: Volker Killesreiter <killesre@gmail.com> Date: Tue, 30 Mar 2021 17:03:07 +0200 Subject: [PATCH 67/86] [HttpFoundation] Fix isNotModified determination logic --- .../Component/HttpFoundation/Request.php | 2 +- .../Component/HttpFoundation/Response.php | 25 +++++++++--- .../HttpFoundation/Tests/ResponseTest.php | 40 +++++++++++++++++-- .../HttpKernel/HttpCache/HttpCache.php | 17 ++++++-- .../Tests/HttpCache/HttpCacheTest.php | 4 +- .../Component/HttpKernel/composer.json | 2 +- 6 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index cf6ebbc0b0903..98e2efef45292 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1564,7 +1564,7 @@ public function getContent($asResource = false) */ public function getETags() { - return preg_split('/\s*,\s*/', $this->headers->get('if_none_match', ''), -1, \PREG_SPLIT_NO_EMPTY); + return preg_split('/\s*,\s*/', $this->headers->get('If-None-Match', ''), -1, \PREG_SPLIT_NO_EMPTY); } /** diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 4ab97aaf90538..3c0950f3384cf 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -1079,12 +1079,27 @@ public function isNotModified(Request $request): bool $lastModified = $this->headers->get('Last-Modified'); $modifiedSince = $request->headers->get('If-Modified-Since'); - if ($etags = $request->getETags()) { - $notModified = \in_array($this->getEtag(), $etags) || \in_array('*', $etags); - } + if ($ifNoneMatchEtags = $request->getETags()) { + $etag = $this->getEtag(); + if (0 == strncmp($etag, 'W/', 2)) { + $etag = substr($etag, 2); + } + + // Use weak comparison as per https://tools.ietf.org/html/rfc7232#section-3.2. + foreach ($ifNoneMatchEtags as $ifNoneMatchEtag) { + if (0 == strncmp($ifNoneMatchEtag, 'W/', 2)) { + $ifNoneMatchEtag = substr($ifNoneMatchEtag, 2); + } - if ($modifiedSince && $lastModified) { - $notModified = strtotime($modifiedSince) >= strtotime($lastModified) && (!$etags || $notModified); + if ($ifNoneMatchEtag === $etag || '*' === $ifNoneMatchEtag) { + $notModified = true; + break; + } + } + } + // Only do If-Modified-Since date comparison when If-None-Match is not present as per https://tools.ietf.org/html/rfc7232#section-3.3. + elseif ($modifiedSince && $lastModified) { + $notModified = strtotime($modifiedSince) >= strtotime($lastModified); } if ($notModified) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php index f26302eef1120..b6d714ae5973d 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php @@ -194,7 +194,7 @@ public function testIsNotModifiedEtag() $etagTwo = 'randomly_generated_etag_2'; $request = new Request(); - $request->headers->set('if_none_match', sprintf('%s, %s, %s', $etagOne, $etagTwo, 'etagThree')); + $request->headers->set('If-None-Match', sprintf('%s, %s, %s', $etagOne, $etagTwo, 'etagThree')); $response = new Response(); @@ -206,6 +206,38 @@ public function testIsNotModifiedEtag() $response->headers->set('ETag', ''); $this->assertFalse($response->isNotModified($request)); + + // Test wildcard + $request = new Request(); + $request->headers->set('If-None-Match', '*'); + + $response->headers->set('ETag', $etagOne); + $this->assertTrue($response->isNotModified($request)); + } + + public function testIsNotModifiedWeakEtag() + { + $etag = 'randomly_generated_etag'; + $weakEtag = 'W/randomly_generated_etag'; + + $request = new Request(); + $request->headers->set('If-None-Match', $etag); + $response = new Response(); + + $response->headers->set('ETag', $etag); + $this->assertTrue($response->isNotModified($request)); + + $response->headers->set('ETag', $weakEtag); + $this->assertTrue($response->isNotModified($request)); + + $request->headers->set('If-None-Match', $weakEtag); + $response = new Response(); + + $response->headers->set('ETag', $etag); + $this->assertTrue($response->isNotModified($request)); + + $response->headers->set('ETag', $weakEtag); + $this->assertTrue($response->isNotModified($request)); } public function testIsNotModifiedLastModifiedAndEtag() @@ -216,14 +248,14 @@ public function testIsNotModifiedLastModifiedAndEtag() $etag = 'randomly_generated_etag'; $request = new Request(); - $request->headers->set('if_none_match', sprintf('%s, %s', $etag, 'etagThree')); + $request->headers->set('If-None-Match', sprintf('%s, %s', $etag, 'etagThree')); $request->headers->set('If-Modified-Since', $modified); $response = new Response(); $response->headers->set('ETag', $etag); $response->headers->set('Last-Modified', $after); - $this->assertFalse($response->isNotModified($request)); + $this->assertTrue($response->isNotModified($request)); $response->headers->set('ETag', 'non-existent-etag'); $response->headers->set('Last-Modified', $before); @@ -240,7 +272,7 @@ public function testIsNotModifiedIfModifiedSinceAndEtagWithoutLastModified() $etag = 'randomly_generated_etag'; $request = new Request(); - $request->headers->set('if_none_match', sprintf('%s, %s', $etag, 'etagThree')); + $request->headers->set('If-None-Match', sprintf('%s, %s', $etag, 'etagThree')); $request->headers->set('If-Modified-Since', $modified); $response = new Response(); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index 6c4715802efda..be7042279483a 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + /* * This file is part of the Symfony package. * @@ -382,7 +391,7 @@ protected function validate(Request $request, Response $entry, $catch = false) // add our cached last-modified validator if ($entry->headers->has('Last-Modified')) { - $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified')); + $subRequest->headers->set('If-Modified-Since', $entry->headers->get('Last-Modified')); } // Add our cached etag validator to the environment. @@ -391,7 +400,7 @@ protected function validate(Request $request, Response $entry, $catch = false) $cachedEtags = $entry->getEtag() ? [$entry->getEtag()] : []; $requestEtags = $request->getETags(); if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) { - $subRequest->headers->set('if_none_match', implode(', ', $etags)); + $subRequest->headers->set('If-None-Match', implode(', ', $etags)); } $response = $this->forward($subRequest, $catch, $entry); @@ -444,8 +453,8 @@ protected function fetch(Request $request, $catch = false) } // avoid that the backend sends no content - $subRequest->headers->remove('if_modified_since'); - $subRequest->headers->remove('if_none_match'); + $subRequest->headers->remove('If-Modified-Since'); + $subRequest->headers->remove('If-None-Match'); $response = $this->forward($subRequest, $catch); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 9bec2f7c94eb1..fc363862ea680 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -156,7 +156,7 @@ public function testRespondsWith304WhenIfNoneMatchMatchesETag() $this->assertTraceContains('store'); } - public function testRespondsWith304OnlyIfIfNoneMatchAndIfModifiedSinceBothMatch() + public function testRespondsWith304WhenIfNoneMatchAndIfModifiedSinceBothMatch() { $time = \DateTime::createFromFormat('U', time()); @@ -172,7 +172,7 @@ public function testRespondsWith304OnlyIfIfNoneMatchAndIfModifiedSinceBothMatch( $t = \DateTime::createFromFormat('U', time() - 3600); $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $t->format(\DATE_RFC2822)]); $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertEquals(304, $this->response->getStatusCode()); // only Last-Modified matches $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '1234', 'HTTP_IF_MODIFIED_SINCE' => $time->format(\DATE_RFC2822)]); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index a2fa2a0ecac5d..74ce9aadb05db 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -20,7 +20,7 @@ "symfony/error-handler": "^4.4", "symfony/event-dispatcher": "^4.4", "symfony/http-client-contracts": "^1.1|^2", - "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-foundation": "^4.4.24|^5.2.9", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.15", From 34d43aa2eb8f034c2f1c7525f5b3fc8561a7c5c1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 26 Aug 2021 08:31:37 +0200 Subject: [PATCH 68/86] Remove redundant license info --- src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index be7042279483a..7deda42fc7186 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -10,16 +10,9 @@ */ /* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; From 7995559e8291d9519b802a22668c33177c2dc367 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 26 Aug 2021 08:31:47 +0200 Subject: [PATCH 69/86] Fix composer.json versions --- src/Symfony/Component/HttpKernel/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 9a44848d460ac..c2758e45ae8cc 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -20,7 +20,7 @@ "symfony/error-handler": "^4.4", "symfony/event-dispatcher": "^4.4", "symfony/http-client-contracts": "^1.1|^2", - "symfony/http-foundation": "^4.4.24|^5.2.9", + "symfony/http-foundation": "^4.4.30|^5.3.7", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", From 8be1f8b22988a9d7b5c1b8ca6cfd56b633b0ffb2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 26 Aug 2021 08:53:21 +0200 Subject: [PATCH 70/86] Fix composer.json versions --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 7fe4a67faac44..6562fa2d1e241 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -39,7 +39,7 @@ "symfony/browser-kit": "^4.3|^5.0", "symfony/console": "^4.4.21|^5.0", "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/dom-crawler": "^4.4.20|^5.2.4", + "symfony/dom-crawler": "^4.4.30|^5.3.7", "symfony/dotenv": "^4.3.6|^5.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/form": "^4.3.5|^5.0", From 803a9984c517ed0de3235031af3661a91f9c95f2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Thu, 26 Aug 2021 09:22:13 +0200 Subject: [PATCH 71/86] Simplify code --- .../Component/Notifier/Bridge/Smsapi/SmsapiTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php index af05c13220e9d..700447dfdf3a7 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/SmsapiTransport.php @@ -79,7 +79,7 @@ protected function doSend(MessageInterface $message): SentMessage throw new TransportException('Could not decode body to an array.', $response, 0, $e); } - if ((isset($content['error']) && null !== $content['error']) || (200 !== $statusCode)) { + if (isset($content['error']) || 200 !== $statusCode) { throw new TransportException(sprintf('Unable to send the SMS: "%s".', $content['message'] ?? 'unknown error'), $response); } From ab9ad6bd3b34887cff0d249cf6db15b7880adf93 Mon Sep 17 00:00:00 2001 From: Nate Wiebe <nate@northern.co> Date: Fri, 16 Jul 2021 15:11:41 -0400 Subject: [PATCH 72/86] [Translation] Extract translatable content on twig set --- .../Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php | 8 +++----- .../Bridge/Twig/Tests/Translation/TwigExtractorTest.php | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php index e5b0fc4ea1b73..d42245e2b89a4 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php @@ -69,12 +69,10 @@ protected function doEnterNode(Node $node, Environment $env): Node $this->getReadDomainFromArguments($node->getNode('arguments'), 1), ]; } elseif ( - $node instanceof FilterExpression && - 'trans' === $node->getNode('filter')->getAttribute('value') && - $node->getNode('node') instanceof FunctionExpression && - 't' === $node->getNode('node')->getAttribute('name') + $node instanceof FunctionExpression && + 't' === $node->getAttribute('name') ) { - $nodeArguments = $node->getNode('node')->getNode('arguments'); + $nodeArguments = $node->getNode('arguments'); if ($nodeArguments->getIterator()->current() instanceof ConstantExpression) { $this->messages[] = [ diff --git a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php index 6a7336d7b1995..8013714d7b40c 100644 --- a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php @@ -66,6 +66,7 @@ public function getExtractData() ['{% set foo = "new key" | trans %}', ['new key' => 'messages']], ['{{ 1 ? "new key" | trans : "another key" | trans }}', ['new key' => 'messages', 'another key' => 'messages']], ['{{ t("new key") | trans() }}', ['new key' => 'messages']], + ['{% set foo = t("new key") %}', ['new key' => 'messages']], ['{{ t("new key", {}, "domain") | trans() }}', ['new key' => 'domain']], ['{{ 1 ? t("new key") | trans : t("another key") | trans }}', ['new key' => 'messages', 'another key' => 'messages']], From 09eec5e2a85d9af0ba1f86fc1b08eafdf12ef229 Mon Sep 17 00:00:00 2001 From: Martin Kirilov <wucdbm@gmail.com> Date: Sat, 22 May 2021 04:44:23 +0300 Subject: [PATCH 73/86] [Messenger] Fix `ErrorDetailsStamp` denormalization --- .../Messenger/Stamp/ErrorDetailsStamp.php | 4 ++-- .../Tests/Stamp/ErrorDetailsStampTest.php | 24 +++++++++++++++++++ .../Tests/Stamp/StringErrorCodeException.php | 12 ++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Stamp/StringErrorCodeException.php diff --git a/src/Symfony/Component/Messenger/Stamp/ErrorDetailsStamp.php b/src/Symfony/Component/Messenger/Stamp/ErrorDetailsStamp.php index ae03de5a6c12f..62abf23423ddd 100644 --- a/src/Symfony/Component/Messenger/Stamp/ErrorDetailsStamp.php +++ b/src/Symfony/Component/Messenger/Stamp/ErrorDetailsStamp.php @@ -23,7 +23,7 @@ final class ErrorDetailsStamp implements StampInterface /** @var string */ private $exceptionClass; - /** @var int|mixed */ + /** @var int|string */ private $exceptionCode; /** @var string */ @@ -33,7 +33,7 @@ final class ErrorDetailsStamp implements StampInterface private $flattenException; /** - * @param int|mixed $exceptionCode + * @param int|string $exceptionCode */ public function __construct(string $exceptionClass, $exceptionCode, string $exceptionMessage, FlattenException $flattenException = null) { diff --git a/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php b/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php index 8d66537afa0c8..054eed579e785 100644 --- a/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php +++ b/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php @@ -18,6 +18,8 @@ use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp; use Symfony\Component\Messenger\Transport\Serialization\Normalizer\FlattenExceptionNormalizer; use Symfony\Component\Messenger\Transport\Serialization\Serializer; +use Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor; +use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; @@ -70,4 +72,26 @@ public function testDeserialization() $this->assertInstanceOf(ErrorDetailsStamp::class, $deserializedStamp); $this->assertEquals($stamp, $deserializedStamp); } + + public function testDeserializationWithStringExceptionCode() + { + $exception = new StringErrorCodeException('exception message', 'some code'); + $stamp = ErrorDetailsStamp::create($exception); + $extractor = new ConstructorExtractor([ + new ReflectionExtractor(), + ]); + $serializer = new Serializer( + new SymfonySerializer([ + new ArrayDenormalizer(), + new FlattenExceptionNormalizer(), + new ObjectNormalizer(null, null, null, $extractor, null, null, []), + ], [new JsonEncoder()]) + ); + + $deserializedEnvelope = $serializer->decode($serializer->encode(new Envelope(new \stdClass(), [$stamp]))); + + $deserializedStamp = $deserializedEnvelope->last(ErrorDetailsStamp::class); + $this->assertInstanceOf(ErrorDetailsStamp::class, $deserializedStamp); + $this->assertEquals($stamp, $deserializedStamp); + } } diff --git a/src/Symfony/Component/Messenger/Tests/Stamp/StringErrorCodeException.php b/src/Symfony/Component/Messenger/Tests/Stamp/StringErrorCodeException.php new file mode 100644 index 0000000000000..2c575d8f80046 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Stamp/StringErrorCodeException.php @@ -0,0 +1,12 @@ +<?php + +namespace Symfony\Component\Messenger\Tests\Stamp; + +class StringErrorCodeException extends \Exception +{ + public function __construct(string $message, string $code) + { + parent::__construct($message); + $this->code = $code; + } +} From 4d6ad98f2ba6b52e10f8a1f5e53bcb12c6c5f0c9 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Mon, 28 Jun 2021 12:37:41 +0200 Subject: [PATCH 74/86] Fix skip condition for INTL Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../Component/String/Tests/AbstractAsciiTestCase.php | 12 ++++++++---- .../String/Tests/AbstractUnicodeTestCase.php | 6 ++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index 70e4ba311d7a6..d382f82391a6f 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -36,11 +36,13 @@ public function testCreateFromEmptyString() /** * @dataProvider provideBytesAt - * - * @requires extension intl 66.2 */ public function testBytesAt(array $expected, string $string, int $offset, int $form = null) { + if (2 !== grapheme_strlen('च्छे') && 'नमस्ते' === $string) { + $this->markTestSkipped('Skipping due to issue ICU-21661.'); + } + $instance = static::createFromString($string); $instance = $form ? $instance->normalize($form) : $instance; @@ -159,11 +161,13 @@ public static function provideWrap(): array /** * @dataProvider provideLength - * - * @requires extension intl 66.2 */ public function testLength(int $length, string $string) { + if (2 !== grapheme_strlen('च्छे') && 'अनुच्छेद' === $string) { + $this->markTestSkipped('Skipping due to issue ICU-21661.'); + } + $instance = static::createFromString($string); $this->assertSame($length, $instance->length()); diff --git a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php index 0f2a58404c41a..f84942c4ba84b 100644 --- a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php @@ -57,11 +57,13 @@ public static function provideBytesAt(): array /** * @dataProvider provideCodePointsAt - * - * @requires extension intl 66.2 */ public function testCodePointsAt(array $expected, string $string, int $offset, int $form = null) { + if (2 !== grapheme_strlen('च्छे') && 'नमस्ते' === $string) { + $this->markTestSkipped('Skipping due to issue ICU-21661.'); + } + $instance = static::createFromString($string); $instance = $form ? $instance->normalize($form) : $instance; From f4df2055bfc052fedf099f91ba9a920bb8e6357d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Thu, 26 Aug 2021 10:36:58 +0200 Subject: [PATCH 75/86] fix cs --- .../ExtensionWithoutConfigTestExtension.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php index e49f391bbafff..79f0a7006c89b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/ExtensionWithoutConfigTestBundle/DependencyInjection/ExtensionWithoutConfigTestExtension.php @@ -11,7 +11,7 @@ public function load(array $configs, ContainerBuilder $container) { } - public function getNamespace() + public function getNamespace(): string { return ''; } @@ -21,7 +21,7 @@ public function getXsdValidationBasePath() return false; } - public function getAlias() + public function getAlias(): string { return 'extension_without_config_test'; } From f4d8af27064186d6b05720f4d096fcb84a8107df Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Thu, 26 Aug 2021 10:45:41 +0200 Subject: [PATCH 76/86] [Messenger] remove test-nothing test --- .../Tests/Stamp/ErrorDetailsStampTest.php | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php b/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php index 054eed579e785..8d66537afa0c8 100644 --- a/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php +++ b/src/Symfony/Component/Messenger/Tests/Stamp/ErrorDetailsStampTest.php @@ -18,8 +18,6 @@ use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp; use Symfony\Component\Messenger\Transport\Serialization\Normalizer\FlattenExceptionNormalizer; use Symfony\Component\Messenger\Transport\Serialization\Serializer; -use Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor; -use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; @@ -72,26 +70,4 @@ public function testDeserialization() $this->assertInstanceOf(ErrorDetailsStamp::class, $deserializedStamp); $this->assertEquals($stamp, $deserializedStamp); } - - public function testDeserializationWithStringExceptionCode() - { - $exception = new StringErrorCodeException('exception message', 'some code'); - $stamp = ErrorDetailsStamp::create($exception); - $extractor = new ConstructorExtractor([ - new ReflectionExtractor(), - ]); - $serializer = new Serializer( - new SymfonySerializer([ - new ArrayDenormalizer(), - new FlattenExceptionNormalizer(), - new ObjectNormalizer(null, null, null, $extractor, null, null, []), - ], [new JsonEncoder()]) - ); - - $deserializedEnvelope = $serializer->decode($serializer->encode(new Envelope(new \stdClass(), [$stamp]))); - - $deserializedStamp = $deserializedEnvelope->last(ErrorDetailsStamp::class); - $this->assertInstanceOf(ErrorDetailsStamp::class, $deserializedStamp); - $this->assertEquals($stamp, $deserializedStamp); - } } From 8c3c0a39ec27c8e9b7579c2e58109e367bfffe37 Mon Sep 17 00:00:00 2001 From: Jeroen Noten <jeroen.noten@isaac.nl> Date: Mon, 2 Aug 2021 14:02:06 +0200 Subject: [PATCH 77/86] Remove indices in messenger table on MySQL to prevent deadlocks while removing messages when running multiple consumers SELECT ... FOR UPDATE row locks also locks indices. Since locking rows and indices is not one atomic operation, this might cause deadlocks when running multiple workers. Removing indices on queue_name and available_at resolves this problem. --- .../Transport/Doctrine/ConnectionTest.php | 54 +++++++++++++++++++ .../Transport/Doctrine/Connection.php | 9 ++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php index c7575e9b8746a..d8b1447257ba1 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; use Doctrine\DBAL\Abstraction\Result as AbstractionResult; +use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Connection as DBALConnection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Result as DriverResult; @@ -23,8 +24,11 @@ use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\SchemaConfig; +use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Statement; +use Doctrine\DBAL\Types\Types; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Exception\InvalidArgumentException; use Symfony\Component\Messenger\Exception\TransportException; @@ -402,4 +406,54 @@ public function providePlatformSql(): iterable 'SELECT m.* FROM messenger_messages m WITH (UPDLOCK, ROWLOCK) WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY ', ]; } + + /** + * @dataProvider setupIndicesProvider + */ + public function testSetupIndices(string $platformClass, array $expectedIndices) + { + $driverConnection = $this->createMock(DBALConnection::class); + $driverConnection->method('getConfiguration')->willReturn(new Configuration()); + + $schemaManager = $this->createMock(AbstractSchemaManager::class); + $schema = new Schema(); + $expectedTable = $schema->createTable('messenger_messages'); + $expectedTable->addColumn('id', Types::BIGINT); + $expectedTable->setPrimaryKey(['id']); + // Make sure columns for indices exists so addIndex() will not throw + foreach (array_unique(array_merge(...$expectedIndices)) as $columnName) { + $expectedTable->addColumn($columnName, Types::STRING); + } + foreach ($expectedIndices as $indexColumns) { + $expectedTable->addIndex($indexColumns); + } + $schemaManager->method('createSchema')->willReturn($schema); + $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + + $platformMock = $this->createMock($platformClass); + $platformMock + ->expects(self::once()) + ->method('getAlterTableSQL') + ->with(self::callback(static function (TableDiff $tableDiff): bool { + return 0 === \count($tableDiff->addedIndexes) && 0 === \count($tableDiff->changedIndexes) && 0 === \count($tableDiff->removedIndexes); + })) + ->willReturn([]); + $driverConnection->method('getDatabasePlatform')->willReturn($platformMock); + + $connection = new Connection([], $driverConnection); + $connection->setup(); + } + + public function setupIndicesProvider(): iterable + { + yield 'MySQL' => [ + MySQL57Platform::class, + [['delivered_at']], + ]; + + yield 'Other platforms' => [ + AbstractPlatform::class, + [['queue_name'], ['available_at'], ['delivered_at']], + ]; + } } diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 20098e2283669..e936ca09e871f 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -17,6 +17,7 @@ use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\Comparator; @@ -386,7 +387,6 @@ private function getSchema(): Schema $table->addColumn('headers', self::$useDeprecatedConstants ? Type::TEXT : Types::TEXT) ->setNotnull(true); $table->addColumn('queue_name', self::$useDeprecatedConstants ? Type::STRING : Types::STRING) - ->setLength(190) // MySQL 5.6 only supports 191 characters on an indexed column in utf8mb4 mode ->setNotnull(true); $table->addColumn('created_at', self::$useDeprecatedConstants ? Type::DATETIME : Types::DATETIME_MUTABLE) ->setNotnull(true); @@ -395,8 +395,11 @@ private function getSchema(): Schema $table->addColumn('delivered_at', self::$useDeprecatedConstants ? Type::DATETIME : Types::DATETIME_MUTABLE) ->setNotnull(false); $table->setPrimaryKey(['id']); - $table->addIndex(['queue_name']); - $table->addIndex(['available_at']); + // No indices on queue_name and available_at on MySQL to prevent deadlock issues when running multiple consumers. + if (!$this->driverConnection->getDatabasePlatform() instanceof MySqlPlatform) { + $table->addIndex(['queue_name']); + $table->addIndex(['available_at']); + } $table->addIndex(['delivered_at']); return $schema; From 3f1982dab9011bc119ddab852f03635d4470e0d3 Mon Sep 17 00:00:00 2001 From: Alexander Schranz <alexander@sulu.io> Date: Mon, 12 Jul 2021 20:19:35 +0200 Subject: [PATCH 78/86] Add no-interaction for SYMFONY_PHPUNIT_REQUIRE on prophecy --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index 61aa8a2da2b8b..1e24ae7710686 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -225,10 +225,10 @@ @copy("$PHPUNIT_VERSION_DIR/phpunit.xsd", 'phpunit.xsd'); chdir("$PHPUNIT_VERSION_DIR"); if ($SYMFONY_PHPUNIT_REMOVE) { - $passthruOrFail("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE); + $passthruOrFail("$COMPOSER remove --no-update --no-interaction ".$SYMFONY_PHPUNIT_REMOVE); } if ($SYMFONY_PHPUNIT_REQUIRE) { - $passthruOrFail("$COMPOSER require --no-update ".$SYMFONY_PHPUNIT_REQUIRE); + $passthruOrFail("$COMPOSER require --no-update --no-interaction ".$SYMFONY_PHPUNIT_REQUIRE); } if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { $passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); From d1eda26a92f2fca20cedd3415b5c6efef3e38d8b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Thu, 26 Aug 2021 15:38:20 +0200 Subject: [PATCH 79/86] Add no-interaction for SYMFONY_PHPUNIT_REMOVE --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index c43a1ccff1e04..179280b87b510 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -226,7 +226,7 @@ @copy("$PHPUNIT_VERSION_DIR/phpunit.xsd", 'phpunit.xsd'); chdir("$PHPUNIT_VERSION_DIR"); if ($SYMFONY_PHPUNIT_REMOVE) { - $passthruOrFail("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE); + $passthruOrFail("$COMPOSER remove --no-update --no-interaction ".$SYMFONY_PHPUNIT_REMOVE); } if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { $passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); From c56470dbc7706da583d6503cb458a60b0a85315e Mon Sep 17 00:00:00 2001 From: Nate Wiebe <nate@northern.co> Date: Thu, 26 Aug 2021 10:33:21 -0400 Subject: [PATCH 80/86] Cast ini_get to an integer to match expected type --- .../HttpFoundation/Session/Storage/MetadataBag.php | 2 +- .../Tests/Session/Storage/MetadataBagTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php index 0146ee259b384..8efdb856f16e5 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php @@ -163,6 +163,6 @@ private function stampCreated(int $lifetime = null): void { $timeStamp = time(); $this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp; - $this->meta[self::LIFETIME] = $lifetime ?? ini_get('session.cookie_lifetime'); + $this->meta[self::LIFETIME] = $lifetime ?? (int) ini_get('session.cookie_lifetime'); } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php index e040f4862755b..51a1b6472f764 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php @@ -136,4 +136,14 @@ public function testDoesNotSkipLastUsedUpdate() $this->assertEquals($timeStamp, $sessionMetadata[MetadataBag::UPDATED]); } + + public function testLifetimeIsInt() + { + $sessionMetadata = []; + + $bag = new MetadataBag(); + $bag->initialize($sessionMetadata); + + $this->assertIsInt($bag->getLifetime()); + } } From a0e8f4fdb33441356f42b2639ac4ff143c0f6148 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Fri, 27 Aug 2021 19:42:48 +0200 Subject: [PATCH 81/86] Fix test fatal_with_nested_handlers for PHP 8.1 Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../phpt/fatal_with_nested_handlers.phpt | 8 ++- .../fatal_with_nested_handlers_pre81.phpt | 55 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers_pre81.phpt diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt index 15933828bd426..92f7e12fde227 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt +++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt @@ -1,5 +1,7 @@ --TEST-- Test catching fatal errors when handlers are nested +--SKIPIF-- +<?php if (\PHP_VERSION_ID < 80100) echo 'skip' ?> --FILE-- <?php @@ -36,6 +38,9 @@ array(1) { string(37) "Error and exception handlers do match" } object(Symfony\Component\ErrorHandler\Error\FatalError)#%d (%d) { + ["message":protected]=> + string(186) "Error: Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" +%a ["error":"Symfony\Component\ErrorHandler\Error\FatalError":private]=> array(4) { ["type"]=> @@ -47,7 +52,4 @@ object(Symfony\Component\ErrorHandler\Error\FatalError)#%d (%d) { ["line"]=> int(%d) } - ["message":protected]=> - string(186) "Error: Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" -%a } diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers_pre81.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers_pre81.phpt new file mode 100644 index 0000000000000..d6b2baa6c904d --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers_pre81.phpt @@ -0,0 +1,55 @@ +--TEST-- +Test catching fatal errors when handlers are nested +--SKIPIF-- +<?php if (\PHP_VERSION_ID >= 80100) echo 'skip' ?> +--FILE-- +<?php + +namespace Symfony\Component\ErrorHandler; + +$vendor = __DIR__; +while (!file_exists($vendor.'/vendor')) { + $vendor = \dirname($vendor); +} +require $vendor.'/vendor/autoload.php'; + +Debug::enable(); +ini_set('display_errors', 0); + +$eHandler = set_error_handler('var_dump'); +$xHandler = set_exception_handler('var_dump'); + +var_dump([ + $eHandler[0] === $xHandler[0] ? 'Error and exception handlers do match' : 'Error and exception handlers are different', +]); + +$eHandler[0]->setExceptionHandler('print_r'); + +if (true) { + class Broken implements \JsonSerializable + { + } +} + +?> +--EXPECTF-- +array(1) { + [0]=> + string(37) "Error and exception handlers do match" +} +object(Symfony\Component\ErrorHandler\Error\FatalError)#%d (%d) { + ["error":"Symfony\Component\ErrorHandler\Error\FatalError":private]=> + array(4) { + ["type"]=> + int(1) + ["message"]=> + string(179) "Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + } + ["message":protected]=> + string(186) "Error: Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" +%a +} From 51eda098edffdaa9fba1fea6f29ca27d23c3d752 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Sat, 28 Aug 2021 17:30:46 +0200 Subject: [PATCH 82/86] [DomCrawler] Don't pass null to trim() Signed-off-by: Alexander M. Turek <me@derrabus.de> --- .../Test/Constraint/CrawlerSelectorAttributeValueSame.php | 2 +- .../Test/Constraint/CrawlerSelectorAttributeValueSameTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php index 7008779e14203..a198784d448df 100644 --- a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php @@ -47,7 +47,7 @@ protected function matches($crawler): bool return false; } - return $this->expectedText === trim($crawler->attr($this->attribute)); + return $this->expectedText === trim($crawler->attr($this->attribute) ?? ''); } /** diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php index ab528ab356443..47ecdc8a04438 100644 --- a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php @@ -23,6 +23,7 @@ public function testConstraint() { $constraint = new CrawlerSelectorAttributeValueSame('input[name="username"]', 'value', 'Fabien'); $this->assertTrue($constraint->evaluate(new Crawler('<html><body><form><input type="text" name="username" value="Fabien">'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><body><form><input type="text" name="username">'), '', true)); $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); try { From 33424ab9fce76379cb8f33dcd571f82fb732ed54 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Sat, 28 Aug 2021 18:24:37 +0200 Subject: [PATCH 83/86] [HttpClient] Don't pass float to usleep() Signed-off-by: Alexander M. Turek <me@derrabus.de> --- src/Symfony/Component/HttpClient/Response/CurlResponse.php | 2 +- src/Symfony/Component/HttpClient/Response/NativeResponse.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index a645a5ff3e03d..9d289d84770fa 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -353,7 +353,7 @@ private static function select(ClientState $multi, float $timeout): int } if ($multi->pauseExpiries && 0 < $timeout -= microtime(true) - $now) { - usleep(1E6 * $timeout); + usleep((int) (1E6 * $timeout)); } return 0; diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 1c17d8274ab08..55ba6410f77c3 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -366,7 +366,7 @@ private static function select(ClientState $multi, float $timeout): int } if (!$handles) { - usleep(1E6 * $timeout); + usleep((int) (1E6 * $timeout)); return 0; } From 9be270c99e0432fc08b74141ae59c379c7124b2d Mon Sep 17 00:00:00 2001 From: Thibault RICHARD <thibault@widop.com> Date: Sun, 29 Aug 2021 17:08:21 +0200 Subject: [PATCH 84/86] [Cache] Fix comment in MemcachedAdapter --- src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php index 436880ff3785a..80211a84236bc 100644 --- a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php @@ -25,7 +25,6 @@ class MemcachedAdapter extends AbstractAdapter /** * We are replacing characters that are illegal in Memcached keys with reserved characters from * {@see \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS} that are legal in Memcached. -This conversation was marked as resolved by lstrojny * Note: don’t use {@see \Symfony\Component\Cache\Adapter\AbstractAdapter::NS_SEPARATOR}. */ private const RESERVED_MEMCACHED = " \n\r\t\v\f\0"; From 600767a45eca13a1b72d7672a356e95a7f93825b Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 30 Aug 2021 14:36:43 +0200 Subject: [PATCH 85/86] Update CHANGELOG for 5.3.7 --- CHANGELOG-5.3.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md index 76537968a1c3c..c949725e03b9b 100644 --- a/CHANGELOG-5.3.md +++ b/CHANGELOG-5.3.md @@ -7,6 +7,42 @@ 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.7 (2021-08-30) + + * bug #42769 [HttpClient] Don't pass float to `usleep()` (derrabus) + * bug #42753 Cast ini_get to an integer to match expected type (natewiebe13) + * bug #42345 [Messenger] Remove indices in messenger table on MySQL to prevent deadlocks while removing messages when running multiple consumers (jeroennoten) + * bug #41378 [Messenger] Fix `ErrorDetailsStamp` denormalization (wucdbm) + * bug #42160 [Translation] Extract translatable content on twig set (natewiebe13) + * bug #42053 [Notifier] [Smsapi] fixed checking whether message is sent (damlox) + * bug #40744 allow null for framework.translator.default_path (SimonHeimberg) + * bug #39856 [DomCrawler] improve failure messages of the CrawlerSelectorTextContains constraint (xabbuh) + * bug #40545 [HttpFoundation] Fix isNotModified determination logic (ol0lll) + * bug #42368 [FrameworkBundle] Fall back to default configuration in debug:config and consistently resolve parameter values (herndlm) + * bug #41684 Fix Url Validator false positives (sidz) + * bug #42576 [Translation] Reverse fallback locales (ro0NL) + * bug #42721 Escape all special characters for parse_mode MARKDOWN_V2 (thomas2411) + * bug #42707 [Messenger] [AMQP] Do not leak any credentials when connection fails (ruudk) + * bug #42690 [Notifier] Firebase error handling (mishaklomp) + * bug #42628 [PropertyInfo] Support for the `never` return type (derrabus) + * bug #42685 Fix ProgressBar to correctly clear multi-line formats (rtek) + * bug #42649 [Translation] Fix message key handling for the Localise provider (xepozz) + * bug #42659 Ignoring X-Transport header while signing email with DKIM (metaer) + * bug #42585 [ExpressionLanguage] [Lexer] Remove PHP 8.0 polyfill (nigelmann) + * bug #42621 [Security] Don't produce TypeErrors for non-string CSRF tokens (derrabus) + * bug #42596 [Security] Fix wrong cache directive when using the new PUBLIC_ACCESS attribute (wouterj) + * bug #42445 [Cache] fix wiring async cache recomputing in debug mode (nicolas-grekas) + * bug #42365 [Cache] Do not add namespace argument to `NullAdapter` in `CachePoolPass` (olsavmic) + * bug #42331 [HttpKernel] always close open stopwatch section after handling `kernel.request` events (xabbuh) + * bug #42381 [Console] Don't pass null to preg_replace() (derrabus) + * bug #42347 Fix ServiceLocator indexing when service is decorated (shyim) + * bug #42380 [HttpFoundation] Don't pass null to strpos() (derrabus) + * bug #42377 [HttpKernel] Remove preloading legacy event dispatcher (OskarStark) + * bug #42260 Fix return types for PHP 8.1 (derrabus) + * bug #42360 [DoctrineBridge] Typehint against doctrine/persistence interfaces (malarzm) + * bug #42341 [Validator] Update MIR card scheme (ossinkine) + * bug #42321 [PasswordHasher] Fix usage of PasswordHasherAdapter in PasswordHasherFactory (peter17) + * 5.3.6 (2021-07-29) * bug #42307 [Mailer] Fixed decode exception when sendgrid response is 202 (rubanooo) From f11410b321d28761c5895e6a45f436392766388a Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 30 Aug 2021 14:37:19 +0200 Subject: [PATCH 86/86] Update VERSION for 5.3.7 --- 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 98bcb7d780a1e..21e7e8543254b 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.7-DEV'; + public const VERSION = '5.3.7'; public const VERSION_ID = 50307; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 7; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2022'; public const END_OF_LIFE = '01/2022';