From 277c73cdede86a88f01625364082ba88e2b0140a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:11:39 +0200 Subject: [PATCH 01/65] Update CHANGELOG for 4.4.41 --- CHANGELOG-4.4.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index 273282ab8caf0..6d426f3b98105 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,27 @@ 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.41 (2022-04-27) + + * bug #46154 [Mailer] Restore X-Transport after failure (zenas1210) + * bug #46171 [VarDumper] Fix dumping floats on PHP8 (nicolas-grekas) + * bug #46170 Fix dumping enums on PHP 8.2 (nicolas-grekas) + * bug #46143 [Cache] Prevent fatal errors on php 8 when running concurrently with TagAwareAdapter v6.1 (sbelyshkin) + * bug #46149 Modify processing of uploaded files to be compatible with PHP 8.1 (p-golovin) + * bug #46125 [FrameworkBundle] Always add CacheCollectorPass (fancyweb) + * bug #46121 Fix "Notice: Undefined index: headers" in messenger with Oracle (rjd22) + * bug #45980 [Finder] Add support of no-capture regex modifier in MultiplePcreFilterIterator (available from PHP 8.2) (alexandre-daubois) + * bug #46008 [Workflow] Catch error when trying to get an uninitialized marking (lyrixx) + * bug #40998 [Form] Use reference date in reverse transform (KDederichs) + * bug #46012 [HttpKernel] Fix Symfony not working on SMB share (qinshuze) + * bug #45992 [Mailer] Return-Path has higher priority for envelope address than From address (tpetry) + * bug #45998 [HttpClient] Fix sending content-length when streaming the body (nicolas-grekas) + * bug #45565 Fix table header seperator wrapping (alamirault) + * bug #45968 [Intl] Update the ICU data to 71.1 - 4.4 (jderusse) + * bug #45947 [FrameworkBundle] [Command] Fix `debug:router --no-interaction` error … (WilliamBoulle) + * bug #45931 [Process] Fix Process::getEnv() when setEnv() hasn't been called before (asika32764) + * bug #45928 [ExpressionLanguage] Fix matching null against a regular expression (ausi) + * 4.4.40 (2022-04-02) * bug #45910 [Messenger] reset connection on worker shutdown (SanderHagen) From 182df09c5b34d406bd4acccbda4e45f3401c608f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:13:11 +0200 Subject: [PATCH 02/65] Update VERSION for 4.4.41 --- 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 ca9fad5957ba1..8c5765cc05bc3 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.41-DEV'; + public const VERSION = '4.4.41'; public const VERSION_ID = 40441; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 41; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From aca1d8f5bc4ddc167279aad7d2e0606244c837a6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:19:01 +0200 Subject: [PATCH 03/65] Bump Symfony version to 4.4.42 --- 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 8c5765cc05bc3..444939421ac6e 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.41'; - public const VERSION_ID = 40441; + public const VERSION = '4.4.42-DEV'; + public const VERSION_ID = 40442; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 41; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 42; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From 3fb4d83ba8f92b91959fb9f159a84a1cf7e178cc Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:22:14 +0200 Subject: [PATCH 04/65] Update CHANGELOG for 5.4.8 --- CHANGELOG-5.4.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 92f504a6a43a3..14694594d1031 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,40 @@ in 5.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/v5.4.0...v5.4.1 +* 5.4.8 (2022-04-27) + + * bug #46154 [Mailer] Restore X-Transport after failure (zenas1210) + * bug #46178 [DependencyInjection] Properly declare #[When] as allowed on functions (nicolas-grekas) + * bug #46171 [VarDumper] Fix dumping floats on PHP8 (nicolas-grekas) + * bug #46170 Fix dumping enums on PHP 8.2 (nicolas-grekas) + * bug #46143 [Cache] Prevent fatal errors on php 8 when running concurrently with TagAwareAdapter v6.1 (sbelyshkin) + * bug #46149 Modify processing of uploaded files to be compatible with PHP 8.1 (p-golovin) + * bug #46125 [FrameworkBundle] Always add CacheCollectorPass (fancyweb) + * bug #46121 Fix "Notice: Undefined index: headers" in messenger with Oracle (rjd22) + * bug #46106 [String] Fix ansi escape sequences regex (fancyweb) + * bug #46097 [Routing] fix router base url when default uri has trailing slash (Tobion) + * bug #46054 [SecurityBundle] Use config's secret in remember-me signatures (jderusse) + * bug #45980 [Finder] Add support of no-capture regex modifier in MultiplePcreFilterIterator (available from PHP 8.2) (alexandre-daubois) + * bug #45394 [HttpKernel] Use the existing session id if available. (trsteel88) + * bug #46008 [Workflow] Catch error when trying to get an uninitialized marking (lyrixx) + * bug #45171 [Translation] Allow usage of Provider domains if possible (welcoMattic) + * bug #40998 [Form] Use reference date in reverse transform (KDederichs) + * bug #46012 [HttpKernel] Fix Symfony not working on SMB share (qinshuze) + * bug #45983 [Messenger] DoctrineTransportFactory works with notify and decorated PostgreSQL driver (alamirault) + * bug #45992 [Mailer] Return-Path has higher priority for envelope address than From address (tpetry) + * bug #45998 [HttpClient] Fix sending content-length when streaming the body (nicolas-grekas) + * bug #45565 Fix table header seperator wrapping (alamirault) + * bug #45969 [Intl] Update the ICU data to 71.1 - 5.4 (jderusse) + * bug #45968 [Intl] Update the ICU data to 71.1 - 4.4 (jderusse) + * bug #45964 Fix use_cookies framework session configuration (alexander-schranz) + * bug #45947 [FrameworkBundle] [Command] Fix `debug:router --no-interaction` error … (WilliamBoulle) + * bug #45948 [RateLimiter] Adding default empty string value on Security::LAST_USERNAME (David-Crty) + * bug #45931 [Process] Fix Process::getEnv() when setEnv() hasn't been called before (asika32764) + * bug #45928 [ExpressionLanguage] Fix matching null against a regular expression (ausi) + * bug #45925 [RateLimiter] Add typecase to SlidingWindow::getExpirationTime (georgringer) + * bug #45910 [Messenger] reset connection on worker shutdown (SanderHagen) + * bug #45909 [Form][TwigBundle] reset Twig form theme resources between requests (xabbuh) + * 5.4.7 (2022-04-02) * bug #45906 [HttpClient] on redirections don't send content related request headers (xabbuh) From dee04f1a9e5a467f8bdd16837f23ba806fcd2883 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:22:21 +0200 Subject: [PATCH 05/65] Update VERSION for 5.4.8 --- 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 fe7cee1758ae0..578d976fdbea6 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.8-DEV'; + public const VERSION = '5.4.8'; public const VERSION_ID = 50408; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 8; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From d11e41be6cb23016894c564d5c2b9ef3357ecaa7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:24:59 +0200 Subject: [PATCH 06/65] Bump Symfony version to 5.4.9 --- 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 578d976fdbea6..e3004cf4f70ae 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.8'; - public const VERSION_ID = 50408; + public const VERSION = '5.4.9-DEV'; + public const VERSION_ID = 50409; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 8; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 9; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From f9e90c62bc18a1e9074b192db8de14db9c2e7f6c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:25:57 +0200 Subject: [PATCH 07/65] Update CHANGELOG for 6.0.8 --- CHANGELOG-6.0.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG-6.0.md b/CHANGELOG-6.0.md index f39d45b692902..6917e182fc50e 100644 --- a/CHANGELOG-6.0.md +++ b/CHANGELOG-6.0.md @@ -7,6 +7,41 @@ in 6.0 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.0.0...v6.0.1 +* 6.0.8 (2022-04-27) + + * bug #46154 [Mailer] Restore X-Transport after failure (zenas1210) + * bug #46178 [DependencyInjection] Properly declare #[When] as allowed on functions (nicolas-grekas) + * bug #46171 [VarDumper] Fix dumping floats on PHP8 (nicolas-grekas) + * bug #46170 Fix dumping enums on PHP 8.2 (nicolas-grekas) + * bug #46143 [Cache] Prevent fatal errors on php 8 when running concurrently with TagAwareAdapter v6.1 (sbelyshkin) + * bug #46149 Modify processing of uploaded files to be compatible with PHP 8.1 (p-golovin) + * bug #46125 [FrameworkBundle] Always add CacheCollectorPass (fancyweb) + * bug #46121 Fix "Notice: Undefined index: headers" in messenger with Oracle (rjd22) + * bug #46106 [String] Fix ansi escape sequences regex (fancyweb) + * bug #46097 [Routing] fix router base url when default uri has trailing slash (Tobion) + * bug #46054 [SecurityBundle] Use config's secret in remember-me signatures (jderusse) + * bug #46051 Don't replace symfony/security-guard (derrabus) + * bug #45980 [Finder] Add support of no-capture regex modifier in MultiplePcreFilterIterator (available from PHP 8.2) (alexandre-daubois) + * bug #45394 [HttpKernel] Use the existing session id if available. (trsteel88) + * bug #46008 [Workflow] Catch error when trying to get an uninitialized marking (lyrixx) + * bug #45171 [Translation] Allow usage of Provider domains if possible (welcoMattic) + * bug #40998 [Form] Use reference date in reverse transform (KDederichs) + * bug #46012 [HttpKernel] Fix Symfony not working on SMB share (qinshuze) + * bug #45983 [Messenger] DoctrineTransportFactory works with notify and decorated PostgreSQL driver (alamirault) + * bug #45992 [Mailer] Return-Path has higher priority for envelope address than From address (tpetry) + * bug #45998 [HttpClient] Fix sending content-length when streaming the body (nicolas-grekas) + * bug #45565 Fix table header seperator wrapping (alamirault) + * bug #45969 [Intl] Update the ICU data to 71.1 - 5.4 (jderusse) + * bug #45968 [Intl] Update the ICU data to 71.1 - 4.4 (jderusse) + * bug #45964 Fix use_cookies framework session configuration (alexander-schranz) + * bug #45947 [FrameworkBundle] [Command] Fix `debug:router --no-interaction` error … (WilliamBoulle) + * bug #45948 [RateLimiter] Adding default empty string value on Security::LAST_USERNAME (David-Crty) + * bug #45931 [Process] Fix Process::getEnv() when setEnv() hasn't been called before (asika32764) + * bug #45928 [ExpressionLanguage] Fix matching null against a regular expression (ausi) + * bug #45925 [RateLimiter] Add typecase to SlidingWindow::getExpirationTime (georgringer) + * bug #45910 [Messenger] reset connection on worker shutdown (SanderHagen) + * bug #45909 [Form][TwigBundle] reset Twig form theme resources between requests (xabbuh) + * 6.0.7 (2022-04-02) * bug #45906 [HttpClient] on redirections don't send content related request headers (xabbuh) From bb3bd4b8c9b7fa44149751b78abaf8c835015190 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:26:02 +0200 Subject: [PATCH 08/65] Update VERSION for 6.0.8 --- 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 1dd75aa34579f..59b5f6e8f1930 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.0.8-DEV'; + public const VERSION = '6.0.8'; public const VERSION_ID = 60008; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 0; public const RELEASE_VERSION = 8; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2023'; public const END_OF_LIFE = '01/2023'; From 8cd9e0a6ba17df41a1a87f6c297b8f4515ce137c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:28:30 +0200 Subject: [PATCH 09/65] Bump Symfony version to 6.0.9 --- 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 59b5f6e8f1930..7cb4f5a36161e 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.0.8'; - public const VERSION_ID = 60008; + public const VERSION = '6.0.9-DEV'; + public const VERSION_ID = 60009; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 0; - public const RELEASE_VERSION = 8; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 9; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2023'; public const END_OF_LIFE = '01/2023'; From fe63f83daab08ecd1d44c33cb7e007014777cd78 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Apr 2022 19:52:44 +0200 Subject: [PATCH 10/65] Bump Symfony version to 6.1.0 --- 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 89fb8c0617078..aafc62dbb01f9 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.1.0-BETA2'; + public const VERSION = '6.1.0-DEV'; public const VERSION_ID = 60100; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 1; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'BETA2'; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2023'; public const END_OF_LIFE = '01/2023'; From a09e2b4ac57fb0dd4226f7439e45d04236ee25ce Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 25 Apr 2022 09:39:59 -0700 Subject: [PATCH 11/65] [VarExporter] Fix exporting DateTime objects on PHP 8.2 --- .../VarExporter/Internal/Exporter.php | 7 +- .../VarExporter/Tests/Fixtures/datetime.php | 70 ++++++++++++++++--- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/VarExporter/Internal/Exporter.php b/src/Symfony/Component/VarExporter/Internal/Exporter.php index 078359af55309..8e03755d87078 100644 --- a/src/Symfony/Component/VarExporter/Internal/Exporter.php +++ b/src/Symfony/Component/VarExporter/Internal/Exporter.php @@ -110,12 +110,7 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount $arrayValue = (array) $value; } elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class - || $value instanceof \DatePeriod - || (\PHP_VERSION_ID >= 80200 && ( - $value instanceof \DateTimeInterface - || $value instanceof \DateTimeZone - || $value instanceof \DateInterval - )) + || PHP_VERSION_ID < 80200 && $value instanceof \DatePeriod ) { ++$objectsCount; $objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0]; diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/datetime.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/datetime.php index e9f41f9ade34c..6429f10efe9f1 100644 --- a/src/Symfony/Component/VarExporter/Tests/Fixtures/datetime.php +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/datetime.php @@ -1,13 +1,15 @@ '1970-01-01 00:00:00.000000', + 'timezone_type' => 1, + 'timezone' => '+00:00', + ], + -1 => [ + 'date' => '1970-01-01 00:00:00.000000', + 'timezone_type' => 1, + 'timezone' => '+00:00', + ], + -2 => [ + 'timezone_type' => 3, + 'timezone' => 'Europe/Paris', + ], + -3 => [ + 'y' => 0, + 'm' => 0, + 'd' => 7, + 'h' => 0, + 'i' => 0, + 's' => 0, + 'f' => 0.0, + 'invert' => 0, + 'days' => 7, + 'from_string' => false, + ], + -5 => [ + 'date' => '2009-10-11 00:00:00.000000', + 'timezone_type' => 3, + 'timezone' => 'Europe/Paris', + ], + -6 => [ + 'y' => 0, + 'm' => 0, + 'd' => 7, + 'h' => 0, + 'i' => 0, + 's' => 0, + 'f' => 0.0, + 'invert' => 0, + 'days' => 7, + 'from_string' => false, + ], + -4 => [ + 'start' => $o[5], + 'current' => null, + 'end' => null, + 'interval' => $o[6], + 'recurrences' => 5, + 'include_start_date' => true, + ], + ] ); From 87bc78ee36e85ae3cda76d6e470f13949f42cf79 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 Apr 2022 09:36:42 -0700 Subject: [PATCH 12/65] Fix merge --- CHANGELOG-6.0.md | 644 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 644 insertions(+) create mode 100644 CHANGELOG-6.0.md diff --git a/CHANGELOG-6.0.md b/CHANGELOG-6.0.md new file mode 100644 index 0000000000000..6917e182fc50e --- /dev/null +++ b/CHANGELOG-6.0.md @@ -0,0 +1,644 @@ +CHANGELOG for 6.0.x +=================== + +This changelog references the relevant changes (bug and security fixes) done +in 6.0 minor versions. + +To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash +To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.0.0...v6.0.1 + +* 6.0.8 (2022-04-27) + + * bug #46154 [Mailer] Restore X-Transport after failure (zenas1210) + * bug #46178 [DependencyInjection] Properly declare #[When] as allowed on functions (nicolas-grekas) + * bug #46171 [VarDumper] Fix dumping floats on PHP8 (nicolas-grekas) + * bug #46170 Fix dumping enums on PHP 8.2 (nicolas-grekas) + * bug #46143 [Cache] Prevent fatal errors on php 8 when running concurrently with TagAwareAdapter v6.1 (sbelyshkin) + * bug #46149 Modify processing of uploaded files to be compatible with PHP 8.1 (p-golovin) + * bug #46125 [FrameworkBundle] Always add CacheCollectorPass (fancyweb) + * bug #46121 Fix "Notice: Undefined index: headers" in messenger with Oracle (rjd22) + * bug #46106 [String] Fix ansi escape sequences regex (fancyweb) + * bug #46097 [Routing] fix router base url when default uri has trailing slash (Tobion) + * bug #46054 [SecurityBundle] Use config's secret in remember-me signatures (jderusse) + * bug #46051 Don't replace symfony/security-guard (derrabus) + * bug #45980 [Finder] Add support of no-capture regex modifier in MultiplePcreFilterIterator (available from PHP 8.2) (alexandre-daubois) + * bug #45394 [HttpKernel] Use the existing session id if available. (trsteel88) + * bug #46008 [Workflow] Catch error when trying to get an uninitialized marking (lyrixx) + * bug #45171 [Translation] Allow usage of Provider domains if possible (welcoMattic) + * bug #40998 [Form] Use reference date in reverse transform (KDederichs) + * bug #46012 [HttpKernel] Fix Symfony not working on SMB share (qinshuze) + * bug #45983 [Messenger] DoctrineTransportFactory works with notify and decorated PostgreSQL driver (alamirault) + * bug #45992 [Mailer] Return-Path has higher priority for envelope address than From address (tpetry) + * bug #45998 [HttpClient] Fix sending content-length when streaming the body (nicolas-grekas) + * bug #45565 Fix table header seperator wrapping (alamirault) + * bug #45969 [Intl] Update the ICU data to 71.1 - 5.4 (jderusse) + * bug #45968 [Intl] Update the ICU data to 71.1 - 4.4 (jderusse) + * bug #45964 Fix use_cookies framework session configuration (alexander-schranz) + * bug #45947 [FrameworkBundle] [Command] Fix `debug:router --no-interaction` error … (WilliamBoulle) + * bug #45948 [RateLimiter] Adding default empty string value on Security::LAST_USERNAME (David-Crty) + * bug #45931 [Process] Fix Process::getEnv() when setEnv() hasn't been called before (asika32764) + * bug #45928 [ExpressionLanguage] Fix matching null against a regular expression (ausi) + * bug #45925 [RateLimiter] Add typecase to SlidingWindow::getExpirationTime (georgringer) + * bug #45910 [Messenger] reset connection on worker shutdown (SanderHagen) + * bug #45909 [Form][TwigBundle] reset Twig form theme resources between requests (xabbuh) + +* 6.0.7 (2022-04-02) + + * bug #45906 [HttpClient] on redirections don't send content related request headers (xabbuh) + * bug #45714 [Messenger] Fix cannot select FOR UPDATE from view on Oracle (rjd22) + * bug #45905 [TwigBridge] Fix the build (wouterj) + * bug #45888 [Messenger] Add mysql indexes back and work around deadlocks using soft-delete (nicolas-grekas) + * bug #45890 [PropertyInfo] PhpStanExtractor namespace missmatch issue (Korbeil) + * bug #45897 [TwigBridge] fix bootstrap_3_layout ChoiceType's expanded label_html (ytilotti) + * bug #45891 [HttpClient] Fix exporting objects with readonly properties (nicolas-grekas) + * bug #45875 [ExpressionLanguage] Fix matches when the regexp is not valid (fabpot) + * bug #44996 [RateLimiter] Always store SlidingWindows with an expiration set (Seldaek) + * bug #45870 [Validator] Fix File constraint invalid max size exception message (fancyweb) + * bug #45851 [Console] Fix exit status on uncaught exception with negative code (acoulton) + * bug #45733 [Validator] fix #43345 @Assert\DivisibleBy (CharlyPoppins) + * bug #45791 [Translation] [LocoProvider] Add content-type for POST translations (Tomasz Kusy) + * bug #45840 [Translation] Fix locales format in CrowdinProvider (ossinkine) + * bug #45491 [DoctrineBridge] Allow to use a middleware instead of DbalLogger (l-vo) + * bug #45839 [Translation] Fix intersect in TranslatorBag (ossinkine) + * bug #45838 [Serializer] Fix denormalizing union types (T-bond) + * bug #45804 Fix compatibility of ldap 6.0 with security 5.x (jderusse) + * bug #45808 [Security] Fixed TOCTOU in RememberMe cache token verifier (Ivan Kurnosov) + * bug #45816 [Mailer] Preserve case of headers (nicolas-grekas) + * bug #45787 [FrameworkBundle] Fix exit codes in debug:translation command (gndk) + * bug #45789 [Config] Fix using null values with config builders (HypeMC) + * bug #45814 [HttpClient] Let curl handle Content-Length headers (nicolas-grekas) + * bug #45813 [HttpClient] Move Content-Type after Content-Length (nicolas-grekas) + * bug #45737 [Lock] SemaphoreStore catching exception from sem_get (Triplkrypl) + * bug #45690 [Mailer] Use recipients in sendmail transport (HypeMC) + * bug #45720 [PropertyInfo] strip only leading `\` when unknown docType (EmilMassey) + * bug #45764 [RateLimiter] Fix rate serialization for long intervals (monthly and yearly) (smelesh) + * bug #45684 [Serializer] Fix nested deserialization_path computation when there is no metadata for the attribute (fancyweb) + * bug #44915 [Console] Fix compact table style to avoid outputting a leading space (Seldaek) + * bug #45691 [Mailer] fix: stringify from address for ses+api transport (everyx) + * bug #45696 Make FormErrorIterator generic (VincentLanglet) + * bug #45676 [Process] Don't return executable directories in PhpExecutableFinder (fancyweb) + * bug #45564 [symfony/mailjet-mailer] Fix invalid mailjet error managment (alamirault, fancyweb) + * bug #45697 [Security] Fix return value of `NullToken::getUser()` (chalasr) + * bug #45719 typehint of DkimOptions algorithm wrong (markusramsak) + * bug #45702 [Form] Fix the usage of the Valid constraints in array-based forms (stof) + * bug #45677 [DependencyInjection] fix `ServiceSubscriberTrait` bug where parent has `__call()` (kbond) + * bug #45678 [HttpClient] Fix reading proxy settings from dotenv when curl is used (nicolas-grekas) + * bug #45675 [Runtime] Fix passing $debug parameter to `ErrorHandler` (Kocal) + * bug #45629 [FrameworkBundle] Fix container:lint and #[Autoconfigure(binds: ...)] failing (LANGERGabrielle) + * bug #45671 [FrameworkBundle] Ensure container is reset between tests (nicolas-grekas) + * bug #45572 [HttpKernel] fix using Target attribute with controller arguments (kbond) + +* 6.0.6 (2022-03-05) + + * bug #45619 [redis-messenger] remove undefined array key warnings (PhilETaylor) + * bug #45637 [Cache] do not pass DBAL connections to PDO adapters (xabbuh) + * bug #45631 [HttpFoundation] Fix PHP 8.1 deprecation in `Response::isNotModified` (HypeMC) + * bug #45610 [HttpKernel] Guard against bad profile data (nicolas-grekas) + * bug #45532 Fix deprecations on PHP 8.2 (nicolas-grekas) + * bug #45595 [FrameworkBundle] Fix resetting container between tests (nicolas-grekas) + * bug #45590 [Console] Revert StringInput bc break from #45088 (bobthecow) + * bug #45585 [HttpClient] fix checking for unset property on PHP <= 7.1.4 (nicolas-grekas) + * bug #45583 [WebProfilerBundle] Fixes HTML syntax regression introduced by #44570 (xavismeh) + +* 6.0.5 (2022-02-28) + + * bug #45351 [WebProfilerBundle] Log section minor fixes (missing "notice" filter, log priority, accessibility) (Amunak) + * bug #44967 [Validator] Multi decimal to alpha for CssColor validator (tilimac) + * bug #45546 [Console] Fix null handling in formatAndWrap() (derrabus) + * bug #44570 [WebProfilerBundle] add nonces to profiler (garak) + * bug #44839 MailerInterface: failed exception contract when enabling messenger (Giorgio Premi) + * bug #45526 [Lock] Release Locks from Internal Store on Postgres waitAndSave* (chrisguitarguy) + * bug #45529 [DependencyInjection] Don't reset env placeholders during compilation (nicolas-grekas) + * bug #45527 [HttpClient] Fix overriding default options with null (nicolas-grekas) + * bug #45531 [Serializer] Fix passing null to str_contains() (Erwin Dirks) + * bug #42458 [Validator][Tests] Fix AssertingContextualValidator not throwing on remaining expectations (fancyweb) + * bug #45279 [Messenger] Fix dealing with unexpected payload in Redis transport (nicoalonso) + * bug #45496 [VarDumper] Fix dumping mysqli_driver instances (nicolas-grekas) + * bug #45495 [HttpFoundation] Fix missing ReturnTypeWillChange attributes (luxemate) + * bug #45482 [Cache] Add missing log when saving namespace (developer-av) + * bug #45479 [HttpKernel] Reset services between requests performed by KernelBrowser (nicolas-grekas) + * bug #44650 [Serializer] Make document type nodes ignorable (boenner) + * bug #45469 [SecurityBundle] fix autoconfiguring Monolog's ProcessorInterface (nicolas-grekas) + * bug #45414 [FrameworkBundle] KernelTestCase resets internal state on tearDown (core23) + * bug #45430 [Dotenv] Fix reading config for symfony/runtime when running dump command (nicolas-grekas) + * bug #45460 [Intl] fix wrong offset timezone PHP 8.1 (Lenny4) + * bug #45462 [HttpKernel] Fix extracting controller name from closures (nicolas-grekas) + * bug #45463 [Security/Http] Fix getting password-upgrader when user-loader is a closure (nicolas-grekas) + * bug #45424 [DependencyInjection] Fix type binding (sveneld) + * bug #45426 [Runtime] Fix dotenv_overload with commands (fancyweb) + * bug #44259 [Security] AccountStatusException::$user should be nullable (Cantepie) + * bug #45391 [Serializer] Ensuring end of line character apply with constructor settings in CSV encoder (bizley) + * bug #45323 [Serializer] Fix ignored callbacks in denormalization (benjaminmal) + * bug #45399 [FrameworkBundle] Fix sorting bug in sorting of tagged services by priority (Ahummeling) + * bug #45338 [Mailer] Fix string-cast of exceptions thrown by authenticator in EsmtpTransport (wikando-ck) + * bug #45339 [Cache] fix error handling when using Redis (nicolas-grekas) + * bug #45331 [Security]  Fix wrong authenticator class in debug logs (chalasr) + * bug #45322 Fix generic type for FormErrorIterator (akalineskou) + * bug #45281 [Cache] Fix connecting to Redis via a socket file (alebedev80) + * bug #45289 [FrameworkBundle] Fix log channel of TagAwareAdapter (fancyweb) + * bug #45306 [PropertyAccessor] Add missing TypeError catch (b1rdex) + * bug #44868 [DependencyInjection][FrameworkBundle] Fix using PHP 8.1 enum as parameters (ogizanagi) + * bug #45298 [HttpKernel] Fix FileLinkFormatter with empty xdebug.file_link_format (fancyweb) + * bug #45299 [DependencyInjection] Fix AsEventListener not working on decorators (LANGERGabrielle) + * bug #45302 [HttpKernel][WebProfilerBundle] Fixed error count by log not displayed in WebProfilerBundle (SVillette) + * bug #45219 [WebProfilerBundle] Fixes weird spacing in log message context/trace output (jennevdmeer) + * bug #45290 [Notifier] fix Microsoft Teams webhook url (christophkoenig) + * bug #45274 [Mailer] allow Mailchimp to handle multiple TagHeader's (kbond) + * bug #45275 [Mailer] ensure only a single tag can be used with Postmark (kbond) + * bug #45261 [HttpClient] Fix Content-Length header when possible (nicolas-grekas) + * bug #45263 [Routing] AnnotationDirectoryLoader::load() may return null (mhujer) + * bug #45258 [DependencyInjection] Don't dump polyfilled classes in preload script (nicolas-grekas) + * bug #38534 [Serializer] make XmlEncoder stateless thus reentrant (connorhu) + * bug #42253 [Form] Do not fix URL protocol for relative URLs (bogkonstantin) + * bug #45256 [DomCrawler] ignore bad charsets (nicolas-grekas) + * bug #45255 [PropertyAccess] Fix handling of uninitialized property of parent class (filiplikavcan) + * bug #45204 [Validator] Fix minRatio and maxRatio when getting rounded (alexander-schranz) + * bug #45240 [Console] Revert StringInput bc break from #45088 (bobthecow) + * bug #45243 [DoctrineBridge] Fix compatibility with doctrine/orm 3 in Id generators (ostrolucky) + +* 6.0.4 (2022-01-29) + + * security #cve-2022-xxxx [FrameworkBundle] Enable CSRF in FORM by default (jderusse) + +* 6.0.3 (2022-01-28) + + * bug #45193 [FrameworkBundle] Fix missing arguments when a serialization default context is bound (ArnoudThibaut) + * bug #44997 [Runtime] Fix --env and --no-debug with dotenv_overload (fancyweb) + * bug #45188 [Dotenv] Fix bootEnv() override with .env.local.php when the env key already exists (fancyweb) + * bug #45095 [Finder] Fix finding VCS re-included files in excluded directory (julienfalque) + * bug #44987 [DoctrineBridge] Fix automapping (mbabker) + * bug #44860 [Validator] Fix Choice constraint with associative choices array (derrabus) + * bug #44939 [Form] UrlType should not add protocol to emails (GromNaN) + * bug #43149 Silence warnings during tty detection (neclimdul) + * bug #45154 [Serializer] Fix AbstractObjectNormalizer not considering pseudo type false (Thomas Nunninger) + * bug #45185 [Notifier] Fix encoding of messages with FreeMobileTransport (94noni) + * bug #45181 [Console] Fix PHP 8.1 deprecation in ChoiceQuestion (BrokenSourceCode) + * bug #44634 [HttpKernel] Fix compatibility with php bridge and already started php sessions (alexander-schranz) + * bug #45174 [Notifier] Use the UTF-8 encoding in smsapi-notifier (marphi) + * bug #45140 [Yaml] Making the parser stateless (mamazu) + * bug #45109 [Console] fix restoring stty mode on CTRL+C (nicolas-grekas) + * bug #45103 [Process] Avoid calling fclose on an already closed resource (Seldaek) + * bug #44941 [RateLimiter] Resolve crash on near-round timestamps (xesxen) + * bug #45088 [Console] fix parsing escaped chars in StringInput (nicolas-grekas) + * bug #45096 [Cache] Throw exception if incompatible version of psr/simple-cache is used (colinodell) + * bug #45067 [RateLimiter] Implicit conversion fix (brian978) + * bug #45063 [DependencyInjection] remove arbitratry limitation to exclude inline services from bindings (nicolas-grekas) + * bug #44986 [DependencyInjection] copy synthetic status when resolving child definitions (kbond) + * bug #45073 [HttpClient] Fix Failed to open stream: Too many open files (adrienfr) + * bug #45053 [Console] use STDOUT/ERR in ConsoleOutput to save opening too many file descriptors (nicolas-grekas) + * bug #45029 [Cache] Set mtime of cache files 1 year into future if they do not expire (Blacksmoke16) + * bug #45012 [DoctrineBridge] Fix invalid guess with enumType (jderusse) + * bug #45015 [HttpClient] fix resetting DNS/etc when calling CurlHttpClient::reset() (nicolas-grekas) + * bug #45004 [HttpClient] Remove deprecated usage of GuzzleHttp\Promise\promise_for (plozmun) + * bug #44998 [FrameworkBundle] Allow default cache pools to be overwritten by user (Seldaek) + * bug #44890 [HttpClient] Remove deprecated usage of `GuzzleHttp\Promise\queue` (GrahamCampbell) + * bug #45002 [PropertyAccess] Fix handling of uninitialized property of anonymous class (filiplikavcan) + * bug #44979 [DependencyInjection] Add iterable to possible binding type (vladimir.panivko) + * bug #44908 [Serializer] Fix AbstractObjectNormalizer TypeError on denormalization (JustDylan23) + * bug #44976 [FrameworkBundle] Avoid calling rtrim(null, '/') in AssetsInstallCommand (pavol-tk, GromNaN) + * bug #44879 [DependencyInjection] Ignore argument type check in CheckTypeDeclarationsPass if it's a Definition with a factory (fancyweb) + * bug #44920 Use correct tag for ExpoTransportFactory service (jschaedl) + * bug #44931 Allow a zero time-limit for messenger:consume (fritzmg) + * bug #44932 [DependencyInjection] Fix nested env var with resolve processor (Laurent Moreau) + * bug #44912 [Console] Allow OutputFormatter::escape() to be used for escaping URLs used in (Seldaek) + * bug #44877 [Validator] Error using CssColor with doctrine annotations (sormes) + * bug #44878 [HttpClient] Turn negative timeout to a very long timeout (fancyweb) + * bug #44854 [Validator] throw when Constraint::_construct() has not been called (nicolas-grekas) + * bug #44857 [Translation] [LocoProvider] Fix use of asset ids (danut007ro) + +* 6.0.2 (2021-12-29) + + * bug #44828 [Lock] Release DoctrineDbalPostgreSqlStore connection lock on failure (simon-watiau) + * bug #44838 [DependencyInjection][HttpKernel] Fix enum typed bindings (ogizanagi) + * bug #44723 [Lock] Release PostgreSqlStore connection lock on failure (simon-watiau) * commit 'e5b2f9efba': [Lock] Release PostgreSqlStore connection lock on failure + * bug #44826 [HttpKernel] Do not attempt to register enum arguments in controller service locator (ogizanagi) + * bug #44822 [Mime][Security] Fix missing sprintf and add tests (alamirault) + * bug #44824 [Mime] Fix missing sprintf in DkimSigner (alamirault) + * bug #44816 [Translation] [LocoProvider] Use rawurlencode and separate tag setting (danut007ro) + * bug #44805 [Security] fix unserializing session payloads from v4 (nicolas-grekas) + * bug #44820 [Cache] Don't lock when doing nested computations (nicolas-grekas) + * bug #44807 [Messenger] fix Redis support on 32b arch (nicolas-grekas) + * bug #44759 [HttpFoundation] Fix notice when HTTP_PHP_AUTH_USER passed without pass (Vitali Tsyrkin) + * bug #44809 [WebProfilerBundle] relax return type for memory data collector (94noni) + * bug #44799 [Cache] fix compat with apcu < 5.1.10 (nicolas-grekas) + * bug #44764 [Form] Expand FormView key to include int (biozshock) + * bug #44730 [Console] Fix autocompletion of argument with default value (GromNaN) + * bug #44637 [PropertyInfo] PhpStan extractor nested object fix (rmikalkenas) + * bug #44085 [Translation] Fix TranslationPullCommand with ICU translations (Kocal) + * bug #44578 [PropertyInfo] Fix phpstan extractor issues (ostrolucky) + * bug #44771 [Notifier] Use correct factory for the msteams transport (veewee) + * bug #44618 [HttpKernel] Fix SessionListener without session in request (shyim) + * bug #44743 [HttpClient] fix checking for recent curl consts (nicolas-grekas) + * bug #44752 [Security/Http] Fix cookie clearing on logout (maxhelias) + * bug #44745 [EventDispatcher][HttpFoundation] Restore return type to covariant IteratorAggregate implementations (derrabus) + * bug #44732 [Mime] Relaxing in-reply-to header validation (ThomasLandauer) + * bug #44714 [WebProfilerBundle] fix Email HTML preview (94noni) + * bug #44737 Fix Psr16Cache not being compatible with non-Symfony cache pools (colinodell) + * bug #44728 [Mime] Fix encoding filenames in multipart/form-data (nicolas-grekas) + * bug #44602 [Serializer] Improve UidNormalizer denormalize error message (fancyweb) + * bug #44383 [Lock] Create tables in transaction only if supported by driver (martinssipenko) + * bug #44518 [HttpFoundation] Take php session.cookie settings into account (simonchrz) + * bug #44719 [ErrorHandler] fix on patching return types on Windows (nicolas-grekas) + * bug #44710 [DependencyInjection] fix linting callable classes (nicolas-grekas) + * bug #44639 [DependencyInjection] Cast tag attribute value to string (ruudk) + * bug #44473 [Validator] Restore default locale in ConstraintValidatorTestCase (rodnaph) + * bug #44682 [FrameworkBundle] alias `cache.app.taggable` to `cache.app` if using `cache.adapter.redis_tag_aware` (kbond) + * bug #44649 [HttpKernel] fix how configuring log-level and status-code by exception works (nicolas-grekas) + * bug #44667 [Cache] Revert "feature #41989 make `LockRegistry` use semaphores when possible" (nicolas-grekas) + * bug #44671 [HttpClient] Fix tracing requests made after calling withOptions() (nicolas-grekas) + * bug #44577 [Cache] Fix proxy no expiration to the Redis (Sergey Belyshkin) + * bug #44669 [Cache] disable lock on CLI (nicolas-grekas) + * bug #44598 [Translation] Handle the blank-translation in Loco Adapter (kgonella) + * bug #44448 [Validator] Allow Sequence constraint to be applied onto class as an attribute (sidz) + * bug #44354 [RateLimiter] Make RateLimiter resilient to timeShifting (jderusse) + * bug #44600 [Serializer] Fix denormalizing custom class in UidNormalizer (fancyweb) + * bug #44537 [Config] In XmlUtils, avoid converting from octal every string starting with a 0 (alexandre-daubois) + * bug #44510 [Workflow] Fix eventsToDispatch parameter setup for StateMachine (Olexandr Kalaidzhy) + * bug #44625 [HttpClient] fix monitoring responses issued before reset() (nicolas-grekas) + * bug #44623 [HttpClient] Fix dealing with "HTTP/1.1 000 " responses (nicolas-grekas) + * bug #44430 [PropertyInfo] Fix aliased namespace matching (Korbeil) + * bug #44601 [HttpClient] Fix closing curl-multi handle too early on destruct (nicolas-grekas) + * bug #44554 Make enable_authenticator_manager true as there is no other way in Symfony 6 (alexander-schranz) + * bug #44571 [HttpClient] Don't reset timeout counter when initializing requests (nicolas-grekas) + * bug #44479 [HttpClient] Double check if handle is complete (Nyholm) + * bug #44418 [DependencyInjection] Resolve ChildDefinition in AbstractRecursivePass (fancyweb) + * bug #44474 [Translation] [Bridge] [Lokalise] Fix push keys to lokalise. Closes #… (olegmifle) + * bug #43164 [FrameworkBundle] Fix cache pool configuration with one adapter and one provider (fancyweb) + * bug #44419 [PropertyAccess] Fix accessing public property on Object (kevcomparadise) + * bug #44565 [FrameworkBundle] Use correct cookie domain in loginUser() (wouterj) + * bug #44538 [Process] fixed uppercase ARGC and ARGV should also be skipped (rbaarsma) + * bug #44438 [HttpClient] Fix handling thrown \Exception in \Generator in MockResponse (fancyweb) + * bug #44469 [String] Fix requiring wcswitch table several times (fancyweb) + * bug #44428 [HttpClient] Fix response id property check in MockResponse (fancyweb) + * bug #44539 [Lock] Fix missing argument in PostgreSqlStore::putOffExpiration with DBAL connection (GromNaN) + +* 6.0.1 (2021-12-09) + + * bug #44494 Remove FQCN type hints on properties (fabpot) + * bug #44490 [DependencyInjection][Messenger] Add auto-registration for BatchHandlerInterface (GaryPEGEOT) + * bug #44523 [Console] Fix polyfill-php73 requirement (Seldaek) + * bug #44514 Don't access uninitialized typed property ChromePhpHandler::$response (Philipp91) + * bug #44502 [HttpFoundation] do not call preg_match() on null (xabbuh) + * bug #44475 [Console] Handle alias in completion script (GromNaN) + * bug #44481 [FrameworkBundle] Fix loginUser() causing deprecation (wouterj) + * bug #44416 [Translation] Make http requests synchronous when reading the Loco API (Kocal) + * bug #44437 [HttpKernel] Fix wrong usage of SessionUtils::popSessionCookie (simonchrz) + * bug #44350 [Translation] Fix TranslationTrait (Tomasz Kusy) + * bug #44460 [SecurityBundle] Fix ambiguous deprecation message on missing provider (chalasr) + * bug #44467 [Console] Fix parameter types for `ProcessHelper::mustRun()` (derrabus) + * bug #44427 [FrameworkBundle] Fix compatibility with symfony/security-core 6.x (deps=high tests) (wouterj) + * bug #44424 [SecurityBundle] Don't rely on deprecated strategy constants (derrabus) + * bug #44399 Prevent infinite nesting of lazy `ObjectManager` instances when `ObjectManager` is reset (Ocramius) + * bug #44402 [HttpKernel] Fix using FileLinkFormatter after serialization (derrabus) + * bug #44395 [HttpKernel] fix sending Vary: Accept-Language when appropriate (nicolas-grekas) + * bug #44385 [DependencyInjection] Skip parameter attribute configurators in AttributeAutoconfigurationPass if we can't get the constructor reflector (fancyweb) + * bug #44359 Avoid duplicated session listener registration in tests (alexander-schranz) + * bug #44375 [DoctrineBridge] fix calling get_class on non-object (kbond) + * bug #44378 [HttpFoundation] fix SessionHandlerFactory using connections (dmaicher) + * bug #44365 [SecurityBundle]  Fix invalid reference with `always_authenticate_before_granting` (chalasr) + * bug #44361 [HttpClient] Fix handling error info in MockResponse (fancyweb) + * bug #44370 [Lock] create lock table if it does not exist (martinssipenko) + +* 6.0.0 (2021-11-29) + + * bug #44309 [Messenger] Leverage DBAL's getNativeConnection() method (derrabus) + * bug #44300 [FrameworkBundle] Fix property-info phpstan extractor discovery (1ed) + * feature #44271 [Notifier] add Vonage bridge to replace the Nexmo one (nicolas-grekas) + * bug #44187 [Translation] [Loco] Fix idempotency of LocoProvider write method (welcoMattic) + * bug #43992 [Security] Do not overwrite already stored tokens for REMOTE_USER authentication (stlrnz) + * bug #43876 [Validator] Fix validation for single level domains (HypeMC) + * bug #44327 [Debug][ErrorHandler] Increased the reserved memory from 10k to 32k (sakalys) + * bug #44261 [Process] intersect with getenv() in case-insensitive manner to get default envs (stable-staple) + * bug #44295 [Serializer] fix support for lazy/unset properties (nicolas-grekas) + * bug #44277 [Notifier] Fix AllMySms bridge body content (afiocre) + * bug #44269 [DoctrineBridge] Revert " add support for the JSON type" (dunglas) + +* 6.0.0-RC1 (2021-11-24) + + * security #cve-2021-41268 [SecurityBundle] Default signature_properties to the previous behavior (wouterj) + * security #cve-2021-41267 [HttpKernel] Fix missing extra trusted header in sub-request (jderusse) + * security #cve-2021-41270 [Serializer] Use single quote to escape formulas (jderusse) + * bug #44230 [Console] Add Suggestion class for more advanced completion suggestion (wouterj) + * bug #44232 [Cache] fix connecting to local Redis sockets (nicolas-grekas) + * bug #44204 [HttpClient] fix closing curl multi handle when destructing client (nicolas-grekas) + * bug #44208 [Process] exclude argv/argc from possible default env vars (nicolas-grekas) + * bug #44188 [VarExporter] fix exporting declared but unset properties when __sleep() is implemented (nicolas-grekas) + * bug #44176 [Console] Default ansi option to null (jderusse) + * bug #44179 [WebProfilerBundle] Fix JS error when toolbar is reloaded (jderusse) + * bug #44177 [SecurityBundle] Remove Guard (derrabus) + * bug #44172 [Security] Guard is incompatible with Symfony 6 (derrabus) + * bug #44119 [HttpClient][Mime] Add correct IDN flags for IDNA2008 compliance (j-bernard) + * bug #44139 [WebProfilerBundle] Prevent installation of incompatible mailer component versions (Anne-Julia Seitz) + * bug #43917 Allow autodetecting mapping type for any object (franmomu) + * bug #44130 [SecurityBundle] Remove outdated conditions based on authenticatorManagerEnabled (chalasr) + * bug #44131 [Yaml] properly parse quoted strings tagged with !!str (xabbuh) + * bug #42323 [TwigBridge] do not merge label classes into expanded choice labels (xabbuh) + +* 6.0.0-BETA3 (2021-11-18) + + * feature #44125 Add a setter on DateTimeNormalizer to change the default context at runtime (Seldaek) + * bug #44110 [FrameworkBundle] Fix default PHP attributes support in validation and serializer configuration when doctrine/annotations is not installed with PHP 8 (fancyweb) + * bug #44115 [WebProfilerBundle] Tweak the colors of the security panel (javiereguiluz) + * bug #44121 [Serializer] fix support for lazy properties (nicolas-grekas) + * bug #44108 [FrameworkBundle][Messenger] remove `FlattenExceptionNormalizer` definition if serializer not available (kbond) + * bug #44111 [Serializer] fix support for unset properties on PHP < 7.4 (nicolas-grekas) + * bug #44098 [DependencyInjection] fix preloading (nicolas-grekas) + * bug #44065 [FrameworkBundle] Add framework config for DBAL cache adapter (GromNaN) + * bug #44096 Make ExpressionVoter Cacheable (jderusse) + * bug #44070 [Process] intersect with getenv() to populate default envs (nicolas-grekas) + * feature #43181 Allow AbstractDoctrineExtension implementations to support the newer bundle structure (mbabker) + * bug #44060 [Cache] Fix calculate ttl in couchbase sdk 3.0 (ajcerezo) + * bug #43990 [Translation] [Loco] Generate id parameter instead of letting Loco do it (welcoMattic) + * bug #44043 [Cache] fix dbindex Redis (a1812) + * feature #44015 [Cache] Decrease the probability of invalidation loss on tag eviction (nicolas-grekas) + * bug #44064 [Cache] fix releasing not acquired locks (nicolas-grekas) + * bug #44063 [DependencyInjection] fix creating 2nd container instances (nicolas-grekas) + * bug #44056 [DependencyInjection] Fix YamlFileLoader return type (1ed) + +* 6.0.0-BETA2 (2021-11-14) + + * bug #44051 [Notifier] Fix package name (fabpot) + * bug #44050 [Notifier] Fix package names (fabpot) + * bug #44042 Fix DateIntervalToStringTransformer::transform() doc (BenMorel) + * bug #44034 [Yaml] don't try to replace references in quoted strings (xabbuh) + * bug #44013 [ErrorHandler] fix parsing ``@param`` with dollars in the description (nicolas-grekas) + * bug #44010 [DependencyInjection] fix auto-refresh when inline_factories is enabled (nicolas-grekas) + * bug #44028 [ErrorHandler] Fix FlattenException::setPrevious argument typing (welcoMattic) + * bug #44016 [SecurityBundle] Fix listing listeners in profiler when authenticator manager is disabled (94noni) + * bug #44012 [DependencyInjection] fix inlining when non-shared services are involved (nicolas-grekas) + * bug #44002 [Cache] Fix Memory leak (a1812) + * bug #43993 [FrameworkBundle] fix deprecation message (nicolas-grekas) + * feature #43985 [HttpClient] Implement ResetInterface for all http clients (rmikalkenas) + * bug #43981 [FrameworkBundle] fix registering late resettable services (nicolas-grekas) + * bug #43988 [DoctrineBridge] add support for the JSON type (dunglas) + * bug #43987 [PhpUnitBridge] Fix Uncaught ValueError (dunglas) + * feature #43983 [HttpKernel] allow ignoring kernel.reset methods that don't exist (nicolas-grekas) + * bug #43967 [Loco] Fix Loco Provider ID and pull & push local messages reading (welcoMattic) + * bug #43961 [HttpClient] Curl http client has to reinit curl multi handle on reset (rmikalkenas) + * bug #43930 [DependencyInjection] Fix support for unions/intersections together with `ServiceSubscriberInterface` (kbond) + * bug #43948 [Asset][Security] Fixed leftover deprecations PHP 8.1 (michaljusiega) + * bug #43944 [Yaml] revert using functions provided by polyfill packages (xabbuh) + * bug #43940 [FrameworkBundle] Fix logic in workflow:dump between workflow name and workflow id (noniagriconomie) + * bug #43947 [HttpKernel] Make sure FileLinkFormatter can be serialized (derrabus) + * bug #43945 [Runtime] fix defining APP_DEBUG when Dotenv is not enabled (nicolas-grekas) + * bug #43946 [HttpKernel] Make sure a serialized DumpDataCollector can be unserialized (derrabus) + +* 6.0.0-BETA1 (2021-11-05) + + * feature #43916 [PropertyInfo] Support the list pseudo-type (derrabus) + * feature #43850 Add completion for DebugConfig name and path arguments (eclairia, Adrien Jourdier) + * feature #43838 feat: add completion for DebugAutowiring search argument (eclairia, Adrien Jourdier) + * feature #38464 [Routing] Add support for aliasing routes (Lctrs) + * feature #43923 [Console] Open CompleteCommand for custom outputs (wouterj) + * feature #43663 [Messenger] Add command completion for failed messages (scyzoryck) + * feature #43857 [Framework] Add completion to debug:container (GromNaN) + * feature #43891 [Messenger] Add completion to command messenger:consume (GromNaN) + * feature #42471 Add generic types to traversable implementations (derrabus) + * feature #43898 [Security] Make the abstract Voter class implement CacheableVoterInterface (javiereguiluz) + * feature #43848 [FrameworkBundle] Add completion for workflow:dump (StaffNowa) + * feature #43837 [Finder] Add .gitignore nested negated patterns support (julienfalque) + * feature #43754 Determine attribute or annotation type for directories (cinamo) + * feature #43846 Add completion for debug:twig (StaffNowa) + * feature #43138 [FrameworkBundle][HttpKernel] Add the ability to enable the profiler using a parameter (dunglas) + * feature #40457 [PropertyInfo] Add `PhpStanExtractor` (Korbeil) + * feature #40262 [DoctrineBridge] Param as connection in `*.event_subscriber/listener` tags (wbloszyk) + * feature #43354 [Messenger] allow processing messages in batches (nicolas-grekas) + * feature #43788 [DependencyInjection][FrameworkBundle][SecurityBundle][TwigBundle] Require Composer's runtime API to be present (derrabus) + * feature #43835 [SecurityBundle] Deprecate not configuring explicitly a provider for custom_authenticators when there is more than one registered provider (lyrixx) + * feature #43598 [Console] add suggestions for debug commands: firewall, form, messenger, router (IonBazan) + * feature #41993 [Security] Prevent `FormLoginAuthenticator` from responding to requests that should be handled by `JsonLoginAuthenticator` (abunch) + * feature #43751 [WebProfilerBundle] Add a "preview" tab in mailer profiler for HTML email (lyrixx) + * feature #43644 [FrameworkBundle] Add completion to debug:translation command (alexandre-daubois) + * feature #43653 [PasswordHasher] Add autocompletion for security commands (noniagriconomie) + * feature #43676 [FrameworkBundle] Add completion feature on translation:update command (stephenkhoo) + * feature #43672 [Translation] Add completion feature on translation pull and push commands (welcoMattic) + * feature #43060 [RateLimiter] Add support for long intervals (months and years) (alexandre-daubois) + * feature #42177 [Security][SecurityBundle] Implement ADM strategies as dedicated classes (derrabus) + * feature #43804 [DependencyInjection][FrameworkBundle][SecurityBundle][TwigBundle] Deprecate Composer 1 (derrabus) + * feature #43796 [Filesystem] Add third argument `$lockFile` to `Filesystem::appendToFile()` (fwolfsjaeger) + * feature #42414 [Notifier] Add Expo bridge (zairigimad) + * feature #43066 [Security] Cache voters that will always abstain (jderusse) + * feature #43758 [FrameworkBundle] Rename translation:update to translation:extract (welcoMattic) + * feature #41414 Support `statusCode` default param when loading template directly via route (dayallnash) + * feature #42238 [DependencyInjection] Add `SubscribedService` attribute, deprecate current `ServiceSubscriberTrait` usage (kbond) + * feature #38542 [FrameworkBundle][Serializer] Allow serializer default context configuration (soyuka) + * feature #43755 [Dotenv] Add $overrideExistingVars to bootEnv() and loadEnv() and dotenv_overload to SymfonyRuntime (fancyweb) + * feature #43671 add ResponseIsUnprocessable (garak) + * feature #43682 [FrameworkBundle] Add completion for config:dump-reference (StaffNowa) + * feature #43588 [Messenger] Autoconfigurable attributes (alirezamirsepassi) + * feature #43593 [Validator] Add CidrValidator to allow validation of CIDR notations (popsorin) + * feature #43683 [VarDumper] Add completion to server:dump command (alexandre-daubois) + * feature #43677 [RateLimiter] bug #42194 fix: sliding window policy to use microtime (jlekowski) + * feature #43679 [VarDumper] Add support for Fiber (lyrixx) + * feature #43680 Add suggestions for the option 'format' of lints commands: twig, yaml and xliff (makraz) + * feature #43621 Add completion for cache:pool:clear and cache:pool:delete commands (andyexeter) + * feature #43639 [Uid] Allow use autocompletion (StaffNowa) + * feature #43626 [Console] [Framework] Add completion to secrets:set and fix secrets:remove (GromNaN) + * feature #43640 [Console] Add completion to messenger:setup-transports command (Tayfun74) + * feature #43615 feat: add completion for CompletionCommand "shell" argument (dkarlovi) + * feature #43595 [Console] `SymfonyStyle` enhancements (kbond) + * feature #41268 [HttpFoundation] Allow setting session options via DSN (makraz) + * feature #43596 [Console] Add completion to help & list commands (GromNaN) + * feature #43587 [Lock] Remove support of Doctrine DBAL in PostgreSqlStore (GromNaN) + * feature #43576 [Messenger] subtract handling time from sleep time in worker (nicolas-grekas) + * feature #43585 [Lock] Remove support of Doctrine DBAL in PdoStore (GromNaN) + * feature #43386 [DependencyInjection] Extend TaggedIterator and TaggedLocator Attributes with able to specify defaultIndexMethod for #[TaggerIterator] and #[TaggedLocator] (fractalzombie) + * feature #42251 [Console] Bash completion integration (wouterj) + * feature #39402 [Notifier] Add push channel to notifier (norkunas) + * feature #43332 [Lock] Split PdoStore into DoctrineDbalStore (GromNaN) + * feature #43362 [Cache] Split PdoAdapter into DoctrineDbalAdapter (GromNaN) + * feature #43550 [HttpFoundation] Remove possibility to pass null as $requestIp in IpUtils (W0rma) + * feature #42580 [Console][FrameworkBundle] Add DotenvDebugCommand (chr-hertel) + * feature #43411 [HttpFoundation] Deprecate passing null as $requestIp in IpUtils (W0rma) + * feature #43526 Add a warning in WDT when using symfony/symfony (fabpot) + * feature #43481 [String] Add `trimSuffix()` and `trimPrefix()` methods (nicolas-grekas) + * feature #43497 [Notifier] [Twilio] Ensure from/sender is valid via regex (OskarStark) + * feature #43492 Lower log level in case of retry (jderusse) + * feature #43479 [DependencyInjection] autowire union and intersection types (nicolas-grekas) + * feature #43134 [Notifier] Add sms77 Notifier Bridge (matthiez) + * feature #43378 [HttpFoundation] Deprecate upload_progress.* and url_rewriter.tags session options (Matthew Covey) + * feature #43405 [Bridge][Monolog] Remove ResetLoggersWorkerSubscriber (lyrixx) + * feature #42582 [Security] Add authenticators info to the profiler (chalasr) + * feature #42723 [Messenger] Log when worker should stop and when `SIGTERM` is received (ruudk) + * feature #40168 [Validator] Added `CssColor` constraint (welcoMattic) + * feature #43328 [MonologBridge] Deprecate the Swiftmailer handler (fabpot) + * feature #43322 [MonologBridge] Deprecates ResetLoggersWorkerSubscriber (lyrixx) + * feature #43108 [HttpKernel] Add basic support for language negotiation (GregoireHebert) + * feature #41265 [Messenger] Add a middleware to log when transaction has been left open (lyrixx) + * feature #43280 [HttpClient] Add method to set response factory in mock client (greeflas) + * feature #42610 [Dotenv] Reimplementing symfony/flex' dump-env as a Symfony command (abdielcs, nicolas-grekas) + * feature #42244 [HttpKernel] Add support for configuring log level, and status code by exception class (lyrixx) + * feature #43236 [Security] Add alias for FirewallMapInterface to `@security`.firewall.map (lyrixx) + * feature #43150 [Finder] Add recursive .gitignore files support (julienfalque) + * feature #41608 [Runtime] Possibility to define the env and/or debug key (maxhelias) + * feature #42257 [Messenger] Allow using user's serializer for message do not fit the expected JSON structure (welcoMattic) + * feature #43148 [Cache] Throw ValueError in debug mode when serialization fails (nicolas-grekas) + * feature #43139 [Notifier] Mattermost Notifier option to post in an other channel (nathanaelmartel) + * feature #42335 [Messenger] Add `WorkerMetadata` to `Worker` class. (okwinza) + * feature #42712 [Serializer] Save missing arguments in MissingConstructorArgumentsException (BafS) + * feature #43004 [Serializer] Throw NotNormalizableValueException when type is not known or not in body in discriminator map (lyrixx) + * feature #43118 [FrameworkBundle] Remove deprecated code (IonBazan) + * feature #43121 [Notifier] [GoogleChat] remove support for deprecated "threadKey" parameter (IonBazan) + * feature #42338 [DomCrawler] Added Crawler::innerText() method (Bilge) + * feature #43095 [Form] Add the EnumType (derrabus) + * feature #43094 [Console] Add support of RGB functional notation (alexandre-daubois) + * feature #43098 [Validator] Add error's uid to `Count` and `Length` constraints with "exactly" option enabled (VladGapanovich) + * feature #42668 [Yaml] Use more concise float representation in dump (dev97) + * feature #43017 [HttpFoundation] Map `multipart/form-data` as `form` Content-Type (keichinger) + * feature #43015 [DependencyInjection] Allow injecting tagged iterator as service locator arguments (IonBazan) + * feature #42991 [FrameworkBundle] Add configureContainer(), configureRoutes() and getConfigDir() to MicroKernelTrait (nicolas-grekas) + * feature #43018 [Mailer] Adding support for TagHeader and MetadataHeader to the Sendgrid API transport (gnito-org) + * feature #43010 Remove remaining support for Doctrine Cache (derrabus) + * feature #42988 [ErrorHandler] Add helper script to patch type declarations (wouterj) + * feature #42982 Add Session Token to Amazon Mailer (Jubeki) + * feature #42959 [DependencyInjection] Make auto-aliases private by default (nicolas-grekas) + * feature #42957 [RateLimiter][Runtime][Translation] remove ``@experimental`` flag (nicolas-grekas) + * feature #41163 [Mesenger] Add support for reseting container services between 2 messages (lyrixx) + * feature #42967 [Cache] Remove support for Doctrine Cache (derrabus) + * feature #41858 [Translation] Translate translatable parameters (kylekatarnls) + * feature #42941 Implement Message Stream for Postmark Mailer (driesvints) + * feature #42532 [DependencyInjection] Sort services in service locator according to priority (BoShurik) + * feature #42502 [Serializer] Add support for collecting type error during denormalization (lyrixx) + * feature #40120 [Cache] Add CouchbaseCollectionAdapter compatibility with sdk 3.0.0 (ajcerezo) + * feature #42965 [Cache] Deprecate support for Doctrine Cache (derrabus) + * feature #41615 [Serializer] Add option to skip uninitialized typed properties (vuryss) + * feature #41566 [FrameworkBundle] Introduced new method for getting bundles config path (a-menshchikov) + * feature #42925 [DoctrineBridge] Remove DoctrineTestHelper and TestRepositoryFactory (derrabus) + * feature #42881 [Console] Add more context when CommandIsSuccessful fails (yoannrenard) + * feature #41321 [FrameworkBundle] Remove deprecate session service (jderusse) + * feature #42900 [HttpFoundation] Add a flag to hasSession to distinguished session from factory (jderusse) + * feature #41390 [HttpKernel] Add session cookie handling in cli context (alexander-schranz, Nyholm) + * feature #42800 Display the roles of the logged-in user in the Web Debug Toolbar (NicoHaase) + * feature #42872 [Mime] Update mime types (fabpot) + * feature #42039 [DependencyInjection] Autoconfigurable attributes on methods, properties and parameters (ruudk) + * feature #42710 [Mailer] Added OhMySMTP Bridge (paul-oms) + * feature #40987 [Config] Handle ignoreExtraKeys in config builder (HypeMC) + * feature #42426 [Notifier] Autoconfigure chatter.transport_factory (ismail1432) + * feature #42748 [Notifier] Add Esendex message ID to SentMessage object (benr77) + * feature #42526 [FrameworkBundle] Add BrowserKitAssertionsTrait::assertThatForBrowser (koenreiniers) + * feature #41527 [Ldap] Fixing the behaviour of getting LDAP Attributes (mr-sven) + * feature #42623 [ErrorHandler] Turn return-type annotations into deprecations by default + add mode to turn them into native types (nicolas-grekas) + * feature #42695 [Mailer] Restore Transport signatures (derrabus) + * feature #42698 Notifier final transport (fabpot) + * feature #42696 [Notifier] Mark Transport as final (fabpot) + * feature #42433 [Notifier] Add more explicit error if a SMSChannel doesn't have a Recipient (ismail1432) + * feature #42619 [Serializer] Deprecate support for returning empty, iterable, countable, raw object when normalizing (lyrixx) + * feature #42662 [Mailer] Consume a PSR-14 event dispatcher (derrabus) + * feature #42625 [DependencyInjection] Add service_closure() to the PHP-DSL (HypeMC) + * feature #42650 [Security] make TokenInterface::getUser() nullable to tell about unauthenticated tokens (nicolas-grekas) + * feature #42644 [Security] Make `AuthenticationTrustResolverInterface::isAuthenticated()` non-virtual (chalasr) + * feature #42634 [Console] Remove `HelperSet::setCommand()` and `getCommand()` (derrabus) + * feature #42632 [Console] Deprecate `HelperSet::setCommand()` and `getCommand()` (derrabus) + * feature #41994 [Validator] Add support of nested attributes (alexandre-daubois) + * feature #41613 [Security] Remove everything related to the deprecated authentication manager (wouterj) + * feature #42595 Fix incompatibilities with upcoming security 6.0 (wouterj) + * feature #42578 [Security] Deprecate legacy remember me services (wouterj) + * feature #42516 [Security] Deprecate built-in authentication entry points (wouterj) + * feature #42387 [Form] Deprecate calling FormErrorIterator::children() if the current element is not iterable (W0rma) + * feature #39641 [Yaml] Add --exclude and negatable --parse-tags option to lint:yaml command (christingruber) + * feature #42510 [Security] Deprecate remaining anonymous checks (wouterj) + * feature #42423 [Security] Deprecate AnonymousToken, non-UserInterface users, and token credentials (wouterj) + * feature #41954 [Filesystem] Add the Path class (theofidry) + * feature #42442 [FrameworkBundle] Deprecate AbstractController::get() and has() (fabpot) + * feature #42422 Clarify goals of AbstractController (fabpot) + * feature #42420 [Security] Deprecate legacy signatures (wouterj) + * feature #41754 [SecurityBundle] Create a smooth upgrade path for security factories (wouterj) + * feature #42198 [Security] Deprecate `PassportInterface` (chalasr) + * feature #42332 [HttpFoundation] Add `litespeed_finish_request` to `Response` (thomas2411) + * feature #42286 [HttpFoundation] Add `SessionFactoryInterface` (kbond) + * feature #42392 [HttpFoundation] Mark Request::get() internal (ro0NL) + * feature #39601 [Notifier] add `SentMessageEvent` and `FailedMessageEvent` (ismail1432) + * feature #42188 [Notifier] Add FakeChat Logger transport (noniagriconomie) + * feature #41522 [Notifier] Add TurboSms Bridge (fre5h) + * feature #42337 [Validator] Remove internal from `ConstraintViolationAssertion` (jordisala1991) + * feature #42333 [Security] Remove deprecated logout handlers (chalasr) + * feature #42123 [Notifier] Add FakeSMS Logger transport (noniagriconomie) + * feature #42297 [Serializer] Add support for serializing empty array as object (lyrixx) + * feature #42326 [Security] Deprecate remaining `LogoutHandlerInterface` implementations (chalasr) + * feature #42219 [Mailer] Add support of ping_threshold to SesTransportFactory (Tyraelqp) + * feature #40052 [ErrorHandler] Add button to copy the path where error is thrown (lmillucci) + * feature #38495 [Asset] [DX] Option to make asset manifests strict on missing item (GromNaN) + * feature #39828 [Translation] XliffLintCommand supports Github Actions annotations (YaFou) + * feature #39826 [TwigBridge] LintCommand supports Github Actions annotations (YaFou) + * feature #39141 [Notifier] Add Amazon SNS bridge (adrien-chinour) + * feature #42240 [Serializer] Add support for preserving empty object in object property (lyrixx) + * feature #42239 [Notifier] Add Yunpian Notifier Bridge (welcoMattic) + * feature #42195 [WebProfilerBundle] Redesigned the log section (javiereguiluz) + * feature #42176 [Console][HttpKernel] Implement `psr/log` 3 (derrabus) + * feature #42163 [Messenger] [Redis] Prepare turning `delete_after_ack` to `true` in 6.0 (chalasr) + * feature #42180 [Notifier] Add bridge for smsc.ru (kozlice) + * feature #42172 [Finder] Remove deprecated code (derrabus) + * feature #42137 [Finder] Make Comparator immutable (derrabus) + * feature #42142 [Security] Remove CSRF deprecations (derrabus) + * feature #42133 [FrameworkBundle] Remove deprecated options in translation:update command (javiereguiluz) + * feature #42127 [ExpressionLanguage] Store compiler and evaluator as closures (derrabus) + * feature #42088 [Contracts] add return types and bump to v3 (nicolas-grekas) + * feature #42094 [Notifier] [Slack] Throw error if maximum block limit is reached for slack message options (norkunas) + * feature #42050 [Security] Deprecate `TokenInterface::isAuthenticated()` (chalasr) + * feature #42090 [Notifier] [Slack] Include additional errors to slack notifier error message (norkunas) + * feature #41319 [Messenger] Removed deprecated code (Nyholm) + * feature #41982 [Security] Remove getPassword() and getSalt() from UserInterface (chalasr) + * feature #41989 [Cache] make `LockRegistry` use semaphores when possible (nicolas-grekas) + * feature #41965 [Security] Deprecate "always authenticate" and "exception on no token" (wouterj) + * feature #41290 [Cache] Implement psr/cache 3 (derrabus) + * feature #41962 add ability to style doubles and integers independently (1ma) + * feature #40830 [Serializer] Add support of PHP backed enumerations (alexandre-daubois) + * feature #41976 [Cache] Remove DoctrineProvider (derrabus) + * feature #40908 [Cache] Deprecate DoctrineProvider (derrabus) + * feature #41717 Allow TranslatableMessage object in form option 'help' (scuben) + * feature #41963 [HttpKernel] remove deprecated features (nicolas-grekas) + * feature #41960 [PasswordHasher][Security] Remove legacy password encoders (chalasr) + * feature #41705 [Notifier] add Mailjet SMS bridge (jnadaud) + * feature #41657 [Serializer] Remove deprecation layer (derrabus) + * feature #41937 [EventDispatcher] Remove ability to configure tags on RegisterListenersPass (derrabus) + * feature #41932 [DependencyInjection] Remove deprecated code (derrabus) + * feature #41851 Add TesterTrait::assertCommandIsSuccessful() helper (yoannrenard) + * feature #39623 [Messenger] Added StopWorkerException (lyrixx) + * feature #41292 [Workflow] Add support for getting updated context after a transition (lyrixx) + * feature #41154 [Validator] Add support for `ConstraintViolationList::createFromMessage()` (lyrixx) + * feature #41874 [SecurityBundle] Hide security toolbar if no firewall matched (wouterj) + * feature #41375 [Notifier] Add MessageMedia Bridge (vuphuong87) + * feature #41923 [EventDispatcher] Deprecate configuring tags on RegisterListenersPass (derrabus) + * feature #41802 [Uid] Add NilUlid (fancyweb) + * feature #40738 [Notifier] Add options to Microsoft Teams notifier (OskarStark) + * feature #41172 [Notifier] Add Telnyx notifier bridge (StaffNowa) + * feature #41770 [HttpClient] Add default base_uri to MockHttpClient (nicolas-grekas) + * feature #41205 [TwigBridge] Add `encore_entry_*_tags()` to UndefinedCallableHandler, as no-op (nicolas-grekas) + * feature #41786 [FrameworkBundle] Add commented base64 version of secrets' keys (nicolas-grekas) + * feature #41432 [WebProfilerBundle] Improved the light/dark theme switching (javiereguiluz) + * feature #41743 [Form] remove remaining deprecation layers (xabbuh) + * feature #41692 [Form] remove deprecated constants (xabbuh) + * feature #41540 [VarDumper] Add casters for Symfony UUIDs and ULIDs (fancyweb) + * feature #41530 [FrameworkBundle] Deprecate the public `profiler` service to private (nicolas-grekas) + * feature #41392 [Validator] Remove deprecated code (jschaedl) + * feature #41318 [Form] Remove deprecated code (yceruto) + * feature #41308 [Mailer] Remove deprecated code (jderusse) + * feature #41299 Remove Serializable implementations (derrabus) + * feature #41350 [Inflector] Remove the component (fancyweb) + * feature #41361 [Intl] Removed deprecated code (malteschlueter) + * feature #41365 [PropertyAccess] Remove deprecated code (malteschlueter) + * feature #41371 [Routing] Remove deprecation layer (derrabus) + * feature #41199 [FrameworkBundle] Deprecate the `AdapterInterface` autowiring alias, use `CacheItemPoolInterface` instead (nicolas-grekas) + * feature #41304 [EventDispatcher] Remove LegacyEventDispatcherProxy (derrabus) + * feature #41302 [PhpUnitBridge] Remove SetUpTearDownTrait (derrabus) + * feature #41363 [Ldap] Removed deprecated code (malteschlueter) + * feature #41364 [Mime] Remove deprecated code (malteschlueter) + * feature #41359 [HttpClient] Removed deprecated code (malteschlueter) + * feature #41360 [Yaml] Remove deprecated code (fancyweb) + * feature #41358 [EventDispatcher] Removed deprecated code (malteschlueter) + * feature #41357 [Dotenv] Remove deprecated code (malteschlueter) + * feature #41355 [DomCrawler] Removed deprecated code (malteschlueter) + * feature #41353 [Cache] Removed depreacted code (malteschlueter) + * feature #41351 [FrameworkBundle][SecurityBundle][TwigBundle] Turn deprecated public services to private (fancyweb) + * feature #41334 [HttpFoundation] remove deprecated code (azjezz) + * feature #41316 [OptionsResolver] Remove deprecated code (yceruto) + * feature #41314 [Messenger] Remove dependency on bridge packages (Nyholm) + * feature #41284 [Lock] Remove deprecated classes in Lock (jderusse) + * feature #41312 [Console] Remove console deprecations (jschaedl) + * feature #41303 [Config] Remove deprecated code (derrabus) + * feature #41301 [MonologBridge] Remove deprecated code (derrabus) + * feature #41300 [Asset] Remove deprecated RemoteJsonManifestVersionStrategy (mbabker) + * feature #41298 [Notifier] Remove deprecation in slack-notifier (jschaedl) + * feature #41203 [FrameworkBundle] Add autowiring alias for `HttpCache\StoreInterface` (nicolas-grekas) + * feature #41282 Bump Symfony 6 to PHP 8 (nicolas-grekas) + From 0d1b9802af15da35dffe83f8739b840b0c9a917f Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 30 Apr 2022 13:54:53 +0200 Subject: [PATCH 13/65] [Console] Fix fish completion script --- .../Console/Command/DumpCompletionCommand.php | 18 ++++++++----- .../Console/Resources/completion.fish | 2 +- .../Descriptor/AbstractDescriptorTest.php | 3 +++ .../Console/Tests/Fixtures/application_1.json | 2 +- .../Console/Tests/Fixtures/application_1.md | 27 +------------------ .../Console/Tests/Fixtures/application_1.xml | 27 +------------------ .../Console/Tests/Fixtures/application_2.json | 2 +- .../Console/Tests/Fixtures/application_2.md | 27 +------------------ .../Console/Tests/Fixtures/application_2.xml | 27 +------------------ .../Tests/Fixtures/application_mbstring.md | 27 +------------------ 10 files changed, 23 insertions(+), 139 deletions(-) diff --git a/src/Symfony/Component/Console/Command/DumpCompletionCommand.php b/src/Symfony/Component/Console/Command/DumpCompletionCommand.php index 7597a9e2cc651..0b059f3eddcdf 100644 --- a/src/Symfony/Component/Console/Command/DumpCompletionCommand.php +++ b/src/Symfony/Component/Console/Command/DumpCompletionCommand.php @@ -45,34 +45,40 @@ protected function configure() $commandName = basename($fullCommand); $fullCommand = realpath($fullCommand) ?: $fullCommand; + $shell = $this->guessShell(); + [$rcFile, $completionFile] = match ($shell) { + 'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"], + default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"], + }; + $this ->setHelp(<<%command.name% command dumps the shell completion script required -to use shell autocompletion (currently only bash completion is supported). +to use shell autocompletion (currently, bash and fish completion is supported). Static installation ------------------- Dump the script to a global completion file and restart your shell: - %command.full_name% bash | sudo tee /etc/bash_completion.d/${commandName} + %command.full_name% {$shell} | sudo tee {$completionFile} Or dump the script to a local file and source it: - %command.full_name% bash > completion.sh + %command.full_name% {$shell} > completion.sh # source the file whenever you use the project source completion.sh - # or add this line at the end of your "~/.bashrc" file: + # or add this line at the end of your "{$rcFile}" file: source /path/to/completion.sh Dynamic installation -------------------- -Add this to the end of your shell configuration file (e.g. "~/.bashrc"): +Add this to the end of your shell configuration file (e.g. "{$rcFile}"): - eval "$(${fullCommand} completion bash)" + eval "$({$fullCommand} completion {$shell})" EOH ) ->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, $this->getSupportedShells(...)) diff --git a/src/Symfony/Component/Console/Resources/completion.fish b/src/Symfony/Component/Console/Resources/completion.fish index 6566c58a3f9ea..680d180e03843 100644 --- a/src/Symfony/Component/Console/Resources/completion.fish +++ b/src/Symfony/Component/Console/Resources/completion.fish @@ -7,7 +7,7 @@ function _sf_{{ COMMAND_NAME }} set sf_cmd (commandline -o) - set c (math (count (commandline -oc))) - 1) + set c (count (commandline -oc)) set completecmd "$sf_cmd[1]" "_complete" "-sfish" "-S{{ VERSION }}" diff --git a/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php index 97199fb34573e..2095266965ef7 100644 --- a/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Component/Console/Tests/Descriptor/AbstractDescriptorTest.php @@ -48,6 +48,9 @@ public function testDescribeCommand(Command $command, $expectedDescription) /** @dataProvider getDescribeApplicationTestData */ public function testDescribeApplication(Application $application, $expectedDescription) { + // the "completion" command has dynamic help information depending on the shell + $application->find('completion')->setHelp(''); + $this->assertDescription($expectedDescription, $application); } diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json index c4e98a957ba0d..db3c250fff003 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json @@ -120,7 +120,7 @@ "completion [--debug] [--] []" ], "description": "Dump the shell completion script", - "help": "The completion command dumps the shell completion script required\nto use shell autocompletion (currently only bash completion is supported).\n\nStatic installation\n-------------------\n\nDump the script to a global completion file and restart your shell:\n\n %%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%%\n\nOr dump the script to a local file and source it:\n\n %%PHP_SELF%% completion bash > completion.sh\n\n # source the file whenever you use the project\n source completion.sh\n\n # or add this line at the end of your \"~/.bashrc\" file:\n source /path/to/completion.sh\n\nDynamic installation\n--------------------\n\nAdd this to the end of your shell configuration file (e.g. \"~/.bashrc\"):\n\n eval \"$(%%PHP_SELF_FULL%% completion bash)\"", + "help": "Dump the shell completion script", "definition": { "arguments": { "shell": { diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.md b/src/Symfony/Component/Console/Tests/Fixtures/application_1.md index 0bef4ce3148e0..bb722c07704b5 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.md @@ -14,32 +14,7 @@ Dump the shell completion script * `completion [--debug] [--] []` -The completion command dumps the shell completion script required -to use shell autocompletion (currently only bash completion is supported). - -Static installation -------------------- - -Dump the script to a global completion file and restart your shell: - - %%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%% - -Or dump the script to a local file and source it: - - %%PHP_SELF%% completion bash > completion.sh - - # source the file whenever you use the project - source completion.sh - - # or add this line at the end of your "~/.bashrc" file: - source /path/to/completion.sh - -Dynamic installation --------------------- - -Add this to the end of your shell configuration file (e.g. "~/.bashrc"): - - eval "$(%%PHP_SELF_FULL%% completion bash)" +Dump the shell completion script ### Arguments diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml b/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml index d56164ef875f5..9010a68a17a36 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml @@ -53,32 +53,7 @@ completion [--debug] [--] [<shell>] Dump the shell completion script - The <info>completion</> command dumps the shell completion script required - to use shell autocompletion (currently only bash completion is supported). - - <comment>Static installation - -------------------</> - - Dump the script to a global completion file and restart your shell: - - <info>%%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%%</> - - Or dump the script to a local file and source it: - - <info>%%PHP_SELF%% completion bash > completion.sh</> - - <comment># source the file whenever you use the project</> - <info>source completion.sh</> - - <comment># or add this line at the end of your "~/.bashrc" file:</> - <info>source /path/to/completion.sh</> - - <comment>Dynamic installation - --------------------</> - - Add this to the end of your shell configuration file (e.g. <info>"~/.bashrc"</>): - - <info>eval "$(%%PHP_SELF_FULL%% completion bash)"</> + Dump the shell completion script The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_2.json b/src/Symfony/Component/Console/Tests/Fixtures/application_2.json index 7cd6deddcec4d..0938b3ed3c535 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_2.json +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_2.json @@ -124,7 +124,7 @@ "completion [--debug] [--] []" ], "description": "Dump the shell completion script", - "help": "The completion command dumps the shell completion script required\nto use shell autocompletion (currently only bash completion is supported).\n\nStatic installation\n-------------------\n\nDump the script to a global completion file and restart your shell:\n\n %%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%%\n\nOr dump the script to a local file and source it:\n\n %%PHP_SELF%% completion bash > completion.sh\n\n # source the file whenever you use the project\n source completion.sh\n\n # or add this line at the end of your \"~/.bashrc\" file:\n source /path/to/completion.sh\n\nDynamic installation\n--------------------\n\nAdd this to the end of your shell configuration file (e.g. \"~/.bashrc\"):\n\n eval \"$(%%PHP_SELF_FULL%% completion bash)\"", + "help": "Dump the shell completion script", "definition": { "arguments": { "shell": { diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_2.md b/src/Symfony/Component/Console/Tests/Fixtures/application_2.md index 2fa9a220836fb..d4802c7470937 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_2.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_2.md @@ -27,32 +27,7 @@ Dump the shell completion script * `completion [--debug] [--] []` -The completion command dumps the shell completion script required -to use shell autocompletion (currently only bash completion is supported). - -Static installation -------------------- - -Dump the script to a global completion file and restart your shell: - - %%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%% - -Or dump the script to a local file and source it: - - %%PHP_SELF%% completion bash > completion.sh - - # source the file whenever you use the project - source completion.sh - - # or add this line at the end of your "~/.bashrc" file: - source /path/to/completion.sh - -Dynamic installation --------------------- - -Add this to the end of your shell configuration file (e.g. "~/.bashrc"): - - eval "$(%%PHP_SELF_FULL%% completion bash)" +Dump the shell completion script ### Arguments diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_2.xml b/src/Symfony/Component/Console/Tests/Fixtures/application_2.xml index 801390ef5bd54..075aacc7b5399 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_2.xml +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_2.xml @@ -53,32 +53,7 @@ completion [--debug] [--] [<shell>] Dump the shell completion script - The <info>completion</> command dumps the shell completion script required - to use shell autocompletion (currently only bash completion is supported). - - <comment>Static installation - -------------------</> - - Dump the script to a global completion file and restart your shell: - - <info>%%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%%</> - - Or dump the script to a local file and source it: - - <info>%%PHP_SELF%% completion bash > completion.sh</> - - <comment># source the file whenever you use the project</> - <info>source completion.sh</> - - <comment># or add this line at the end of your "~/.bashrc" file:</> - <info>source /path/to/completion.sh</> - - <comment>Dynamic installation - --------------------</> - - Add this to the end of your shell configuration file (e.g. <info>"~/.bashrc"</>): - - <info>eval "$(%%PHP_SELF_FULL%% completion bash)"</> + Dump the shell completion script The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md b/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md index 740ea5c202050..e7bc69c71019d 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md @@ -18,32 +18,7 @@ Dump the shell completion script * `completion [--debug] [--] []` -The completion command dumps the shell completion script required -to use shell autocompletion (currently only bash completion is supported). - -Static installation -------------------- - -Dump the script to a global completion file and restart your shell: - - %%PHP_SELF%% completion bash | sudo tee /etc/bash_completion.d/%%COMMAND_NAME%% - -Or dump the script to a local file and source it: - - %%PHP_SELF%% completion bash > completion.sh - - # source the file whenever you use the project - source completion.sh - - # or add this line at the end of your "~/.bashrc" file: - source /path/to/completion.sh - -Dynamic installation --------------------- - -Add this to the end of your shell configuration file (e.g. "~/.bashrc"): - - eval "$(%%PHP_SELF_FULL%% completion bash)" +Dump the shell completion script ### Arguments From 26fbc969808e66759bd83038fefd2be7cf9a5e59 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 Apr 2022 11:34:00 -0700 Subject: [PATCH 14/65] [DomCrawler][VarDumper] Fix html-encoding emojis --- src/Symfony/Component/DomCrawler/Crawler.php | 4 ++-- .../Component/DomCrawler/Tests/AbstractCrawlerTest.php | 7 +++++++ src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 462b6b1129d9e..4f89eec75a74b 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -1214,11 +1214,11 @@ private function convertToHtmlEntities(string $htmlContent, string $charset = 'U set_error_handler(function () { throw new \Exception(); }); try { - return mb_encode_numericentity($htmlContent, [0x80, 0xFFFF, 0, 0xFFFF], $charset); + return mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], $charset); } catch (\Exception|\ValueError $e) { try { $htmlContent = iconv($charset, 'UTF-8', $htmlContent); - $htmlContent = mb_encode_numericentity($htmlContent, [0x80, 0xFFFF, 0, 0xFFFF], 'UTF-8'); + $htmlContent = mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8'); } catch (\Exception|\ValueError $e) { } diff --git a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php index 96d9177673c25..6bfd9256165c4 100644 --- a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php @@ -379,6 +379,13 @@ public function testHtml() $this->assertSame('my value', $this->createTestCrawler(null)->filterXPath('//ol')->html('my value')); } + public function testEmojis() + { + $crawler = $this->createCrawler('

Hey 👋

'); + + $this->assertSame('

Hey 👋

', $crawler->html()); + } + public function testExtract() { $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li'); diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index 4db0f08efbc17..7fe31ef4918ab 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -978,7 +978,7 @@ protected function dumpLine($depth, $endOfValue = false) } $this->lastDepth = $depth; - $this->line = mb_encode_numericentity($this->line, [0x80, 0xFFFF, 0, 0xFFFF], 'UTF-8'); + $this->line = mb_encode_numericentity($this->line, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8'); if (-1 === $depth) { AbstractDumper::dumpLine(0); From 430f7c4600d78d137f0c238cee391003b76c7279 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 29 Apr 2022 17:34:57 +0200 Subject: [PATCH 15/65] [Form] fix populating single widget time view data with different timezones --- .../DateTimeToStringTransformer.php | 6 +- .../Form/Extension/Core/Type/TimeType.php | 6 +- .../Extension/Core/Type/TimeTypeTest.php | 70 +++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php index 52565f3879455..51d42494d1def 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php @@ -47,12 +47,14 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer * @param string|null $inputTimezone The name of the input timezone * @param string|null $outputTimezone The name of the output timezone * @param string $format The date format + * @param string|null $parseFormat The parse format when different from $format */ - public function __construct(string $inputTimezone = null, string $outputTimezone = null, string $format = 'Y-m-d H:i:s') + public function __construct(string $inputTimezone = null, string $outputTimezone = null, string $format = 'Y-m-d H:i:s', string $parseFormat = null) { parent::__construct($inputTimezone, $outputTimezone); - $this->generateFormat = $this->parseFormat = $format; + $this->generateFormat = $format; + $this->parseFormat = $parseFormat ?? $format; // See https://php.net/datetime.createfromformat // The character "|" in the format makes sure that the parts of a date diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php index 85b00db57c091..e5953bf9edc85 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -73,8 +73,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) } }); + $parseFormat = null; + if (null !== $options['reference_date']) { - $format = 'Y-m-d '.$format; + $parseFormat = 'Y-m-d '.$format; $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) { $data = $event->getData(); @@ -85,7 +87,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) }); } - $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format)); + $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format, $parseFormat)); } else { $hourOptions = $minuteOptions = $secondOptions = [ 'error_bubbling' => true, diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php index 8da1e2dd5c35e..8fa764f6f76f6 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php @@ -279,6 +279,76 @@ public function testSubmitWithSecondsAndBrowserOmissionSeconds() $this->assertEquals('03:04:00', $form->getViewData()); } + public function testPreSetDataDifferentTimezones() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'Europe/Berlin', + 'input' => 'datetime', + 'with_seconds' => true, + 'reference_date' => new \DateTimeImmutable('2019-01-01', new \DateTimeZone('UTC')), + ]); + $form->setData(new \DateTime('2022-01-01 15:09:10', new \DateTimeZone('UTC'))); + + $this->assertSame('15:09:10', $form->getData()->format('H:i:s')); + $this->assertSame([ + 'hour' => '16', + 'minute' => '9', + 'second' => '10', + ], $form->getViewData()); + } + + public function testPreSetDataDifferentTimezonesDuringDaylightSavingTime() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'Europe/Berlin', + 'input' => 'datetime', + 'with_seconds' => true, + 'reference_date' => new \DateTimeImmutable('2019-07-12', new \DateTimeZone('UTC')), + ]); + $form->setData(new \DateTime('2022-04-29 15:09:10', new \DateTimeZone('UTC'))); + + $this->assertSame('15:09:10', $form->getData()->format('H:i:s')); + $this->assertSame([ + 'hour' => '17', + 'minute' => '9', + 'second' => '10', + ], $form->getViewData()); + } + + public function testPreSetDataDifferentTimezonesUsingSingleTextWidget() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'Europe/Berlin', + 'input' => 'datetime', + 'with_seconds' => true, + 'reference_date' => new \DateTimeImmutable('2019-01-01', new \DateTimeZone('UTC')), + 'widget' => 'single_text', + ]); + $form->setData(new \DateTime('2022-01-01 15:09:10', new \DateTimeZone('UTC'))); + + $this->assertSame('15:09:10', $form->getData()->format('H:i:s')); + $this->assertSame('16:09:10', $form->getViewData()); + } + + public function testPreSetDataDifferentTimezonesDuringDaylightSavingTimeUsingSingleTextWidget() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'Europe/Berlin', + 'input' => 'datetime', + 'with_seconds' => true, + 'reference_date' => new \DateTimeImmutable('2019-07-12', new \DateTimeZone('UTC')), + 'widget' => 'single_text', + ]); + $form->setData(new \DateTime('2022-04-29 15:09:10', new \DateTimeZone('UTC'))); + + $this->assertSame('15:09:10', $form->getData()->format('H:i:s')); + $this->assertSame('17:09:10', $form->getViewData()); + } + public function testSubmitDifferentTimezones() { $form = $this->factory->create(static::TESTED_TYPE, null, [ From a48ecb69ba9c7037142e12ebc27e0fcef258e0a6 Mon Sep 17 00:00:00 2001 From: Michael Babker Date: Wed, 27 Apr 2022 19:44:43 -0500 Subject: [PATCH 16/65] Handle previously converted DateTime arguments --- .../ArgumentResolver/DateTimeValueResolver.php | 6 ++++++ .../DateTimeValueResolverTest.php | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php index 54477b011bc99..55007bef7bc87 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php @@ -40,6 +40,12 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable { $value = $request->attributes->get($argument->getName()); + if ($value instanceof \DateTimeInterface) { + yield $value; + + return; + } + if ($argument->isNullable() && !$value) { yield null; diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php index a62a512129fe8..e1c3d662c6ece 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php @@ -113,6 +113,21 @@ public function testNullableWithEmptyAttribute() $this->assertNull($results[0]); } + public function testPreviouslyConvertedAttribute() + { + $resolver = new DateTimeValueResolver(); + + $argument = new ArgumentMetadata('dummy', \DateTime::class, false, false, null, true); + $request = self::requestWithAttributes(['dummy' => $datetime = new \DateTime()]); + + /** @var \Generator $results */ + $results = $resolver->resolve($request, $argument); + $results = iterator_to_array($results); + + $this->assertCount(1, $results); + $this->assertSame($datetime, $results[0]); + } + public function testCustomClass() { date_default_timezone_set('UTC'); From 886f93becd25c0e87c43f2dc44809b4ea9eac22f Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 2 May 2022 13:56:02 +0200 Subject: [PATCH 17/65] Remove former core members from code owners --- .github/CODEOWNERS | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0870dcfdd5cc4..f6d70f0581cc3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -24,13 +24,8 @@ /src/Symfony/Component/Form/ @xabbuh @yceruto # HttpKernel /src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas -# LDAP -/src/Symfony/Component/Ldap/ @csarrazi # Lock /src/Symfony/Component/Lock/ @jderusse -# Messenger -/src/Symfony/Bridge/Doctrine/Messenger/ @sroze -/src/Symfony/Component/Messenger/ @sroze # OptionsResolver /src/Symfony/Component/OptionsResolver/ @yceruto # PropertyInfo From 15fa4c5406964778eb89e2faed449807abcf094a Mon Sep 17 00:00:00 2001 From: Yoann Renard Date: Wed, 9 Jun 2021 15:23:10 +0200 Subject: [PATCH 18/65] Console Table vertical rendering Using an enum instead of 2 separated booleans Rephrase changelog for better consistency --- src/Symfony/Component/Console/CHANGELOG.md | 1 + .../Component/Console/Helper/Table.php | 68 +++- .../Console/Tests/Helper/TableTest.php | 370 ++++++++++++++++++ 3 files changed, 431 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 22c404363aa54..4444b26ef7eb6 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 6.1 --- + * Add support to display table vertically when calling setVertical() * Add method `__toString()` to `InputInterface` * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead * Add suggested values for arguments and options in input definition, for input completion diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 7102c0817b701..3eef6e24ff8b8 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -35,12 +35,14 @@ class Table private const SEPARATOR_BOTTOM = 3; private const BORDER_OUTSIDE = 0; private const BORDER_INSIDE = 1; + private const DISPLAY_ORIENTATION_DEFAULT = 'default'; + private const DISPLAY_ORIENTATION_HORIZONTAL = 'horizontal'; + private const DISPLAY_ORIENTATION_VERTICAL = 'vertical'; private ?string $headerTitle = null; private ?string $footerTitle = null; private array $headers = []; private array $rows = []; - private bool $horizontal = false; private array $effectiveColumnWidths = []; private int $numberOfColumns; private OutputInterface $output; @@ -49,6 +51,7 @@ class Table private array $columnWidths = []; private array $columnMaxWidths = []; private bool $rendered = false; + private string $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT; private static array $styles; @@ -277,7 +280,17 @@ public function setFooterTitle(?string $title): static */ public function setHorizontal(bool $horizontal = true): static { - $this->horizontal = $horizontal; + $this->displayOrientation = $horizontal ? self::DISPLAY_ORIENTATION_HORIZONTAL : self::DISPLAY_ORIENTATION_DEFAULT; + + return $this; + } + + /** + * @return $this + */ + public function setVertical(bool $vertical = true): static + { + $this->displayOrientation = $vertical ? self::DISPLAY_ORIENTATION_VERTICAL : self::DISPLAY_ORIENTATION_DEFAULT; return $this; } @@ -298,8 +311,13 @@ public function setHorizontal(bool $horizontal = true): static public function render() { $divider = new TableSeparator(); - if ($this->horizontal) { - $rows = []; + $isCellWithColspan = static fn ($cell): bool => $cell instanceof TableCell && $cell->getColspan() >= 2; + + $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation; + $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation; + + $rows = []; + if ($horizontal) { foreach ($this->headers[0] ?? [] as $i => $header) { $rows[$i] = [$header]; foreach ($this->rows as $row) { @@ -308,13 +326,42 @@ public function render() } if (isset($row[$i])) { $rows[$i][] = $row[$i]; - } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) { + } elseif ($isCellWithColspan($rows[$i][0])) { // Noop, there is a "title" } else { $rows[$i][] = null; } } } + } elseif ($vertical) { + $maxHeaderLength = array_reduce($this->headers[0] ?? [], static fn (int $max, string $header) => max($max, mb_strlen($header)), 0); + + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + + if (0 < \count($rows)) { + $rows[] = [$divider]; + } + + $containsColspan = 0 < \count(array_filter($row, $isCellWithColspan)); + + $headers = $this->headers[0] ?? []; + $maxRows = max(\count($headers), \count($row)); + for ($i = 0; $i < $maxRows; ++$i) { + $cell = (string) ($row[$i] ?? ''); + if ([] !== $headers && !$containsColspan) { + $rows[] = [sprintf( + '%s: %s', + str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), + $cell + )]; + } elseif (!empty($cell)) { + $rows[] = [$cell]; + } + } + } } else { $rows = array_merge($this->headers, [$divider], $this->rows); } @@ -324,8 +371,8 @@ public function render() $rowGroups = $this->buildTableRows($rows); $this->calculateColumnsWidth($rowGroups); - $isHeader = !$this->horizontal; - $isFirstRow = $this->horizontal; + $isHeader = !$horizontal; + $isFirstRow = $horizontal; $hasTitle = (bool) $this->headerTitle; foreach ($rowGroups as $rowGroup) { @@ -369,7 +416,12 @@ public function render() $hasTitle = false; } - if ($this->horizontal) { + if ($vertical) { + $isHeader = false; + $isFirstRow = false; + } + + if ($horizontal) { $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); } else { $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 8465c51dc7417..236506996ca28 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -1579,4 +1579,374 @@ public function testWithColspanAndMaxWith() $this->assertSame($expected, $this->getOutputContent($output)); } + + public function provideRenderVerticalTests(): \Traversable + { + $books = [ + ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'], + ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'], + ]; + + yield 'With header for all' => [ + << [ + << [ + << [ + << [ + << [ + << [ + <<99921-58-10-7
', 'Divine Comedy', 'Dante Alighieri'], + ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'], + ], + ]; + + yield 'With colspan' => [ + << 3])], + ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'], + ], + ]; + + yield 'With colspans but no header' => [ + <<consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])], + new TableSeparator(), + [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])], + new TableSeparator(), + [new TableCell('Lorem ipsum dolor sit amet, consectetur ', ['colspan' => 2]), 'hello world'], + new TableSeparator(), + ['hello world', new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit', ['colspan' => 2])], + new TableSeparator(), + ['hello ', new TableCell('world', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'], + new TableSeparator(), + ['Symfony ', new TableCell('Test', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'], + ], + ]; + + yield 'Borderless style' => [ + << [ + << [ + << [ + << [ + << [ + <<getOutputStream()); + $table + ->setHeaders($headers) + ->setRows($rows) + ->setVertical() + ->setStyle($style); + + if (!empty($headerTitle)) { + $table->setHeaderTitle($headerTitle); + } + if (!empty($footerTitle)) { + $table->setFooterTitle($footerTitle); + } + + $table->render(); + + $this->assertEquals($expectedOutput, $this->getOutputContent($output)); + } } From 720444c6bf1f5e613f8f5b7aaecee7318b1cc147 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Apr 2022 14:21:35 +0200 Subject: [PATCH 19/65] [MonologBridge] Add support for Monolog 3 --- src/Symfony/Bridge/Monolog/CHANGELOG.md | 5 ++ .../Formatter/CompatibilityFormatter.php | 57 ++++++++++++++++++ .../Monolog/Formatter/ConsoleFormatter.php | 13 +++-- .../Monolog/Formatter/VarDumperFormatter.php | 14 +++-- .../Monolog/Handler/CompatibilityHandler.php | 57 ++++++++++++++++++ .../CompatibilityProcessingHandler.php | 57 ++++++++++++++++++ .../Bridge/Monolog/Handler/ConsoleHandler.php | 58 +++++++++++++++++-- .../Handler/ElasticsearchLogstashHandler.php | 11 +++- .../HttpCodeActivationStrategy.php | 3 +- .../NotFoundActivationStrategy.php | 3 +- .../Bridge/Monolog/Handler/MailerHandler.php | 31 +++++++--- .../Monolog/Handler/NotifierHandler.php | 9 ++- .../Monolog/Handler/ServerLogHandler.php | 26 ++++++--- .../Processor/AbstractTokenProcessor.php | 7 ++- .../Processor/CompatibilityProcessor.php | 51 ++++++++++++++++ .../Processor/ConsoleCommandProcessor.php | 13 +++-- .../Monolog/Processor/DebugProcessor.php | 5 +- .../Monolog/Processor/RouteProcessor.php | 9 +-- .../Processor/SwitchUserTokenProcessor.php | 2 + .../Monolog/Processor/TokenProcessor.php | 2 + .../Tests/Formatter/ConsoleFormatterTest.php | 29 +++++----- .../Tests/Handler/ConsoleHandlerTest.php | 29 +++------- .../ElasticsearchLogstashHandlerTest.php | 44 ++++---------- .../HttpCodeActivationStrategyTest.php | 21 +++---- .../NotFoundActivationStrategyTest.php | 22 +++---- .../Tests/Handler/MailerHandlerTest.php | 14 ++--- .../Tests/Handler/ServerLogHandlerTest.php | 13 +---- .../Processor/ConsoleCommandProcessorTest.php | 9 +-- .../Tests/Processor/DebugProcessorTest.php | 52 ++++------------- .../SwitchUserTokenProcessorTest.php | 3 +- .../Tests/Processor/TokenProcessorTest.php | 3 +- .../Tests/Processor/WebProcessorTest.php | 14 ++--- .../Bridge/Monolog/Tests/RecordFactory.php | 45 ++++++++++++++ src/Symfony/Bridge/Monolog/composer.json | 2 +- 34 files changed, 519 insertions(+), 214 deletions(-) create mode 100644 src/Symfony/Bridge/Monolog/Formatter/CompatibilityFormatter.php create mode 100644 src/Symfony/Bridge/Monolog/Handler/CompatibilityHandler.php create mode 100644 src/Symfony/Bridge/Monolog/Handler/CompatibilityProcessingHandler.php create mode 100644 src/Symfony/Bridge/Monolog/Processor/CompatibilityProcessor.php create mode 100644 src/Symfony/Bridge/Monolog/Tests/RecordFactory.php diff --git a/src/Symfony/Bridge/Monolog/CHANGELOG.md b/src/Symfony/Bridge/Monolog/CHANGELOG.md index 14c0e5882d015..0da84bd616c93 100644 --- a/src/Symfony/Bridge/Monolog/CHANGELOG.md +++ b/src/Symfony/Bridge/Monolog/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.1 +--- + + * Add support for Monolog 3 + 6.0 --- diff --git a/src/Symfony/Bridge/Monolog/Formatter/CompatibilityFormatter.php b/src/Symfony/Bridge/Monolog/Formatter/CompatibilityFormatter.php new file mode 100644 index 0000000000000..08cd70983b3ba --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Formatter/CompatibilityFormatter.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Formatter; + +use Monolog\Logger; +use Monolog\LogRecord; + +if (Logger::API >= 3) { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityFormatter + { + abstract private function doFormat(array|LogRecord $record): mixed; + + /** + * {@inheritdoc} + */ + public function format(LogRecord $record): mixed + { + return $this->doFormat($record); + } + } +} else { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityFormatter + { + abstract private function doFormat(array|LogRecord $record): mixed; + + /** + * {@inheritdoc} + */ + public function format(array $record): mixed + { + return $this->doFormat($record); + } + } +} diff --git a/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php b/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php index 5b04c4a62434f..b8ed640e9c4aa 100644 --- a/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php +++ b/src/Symfony/Bridge/Monolog/Formatter/ConsoleFormatter.php @@ -13,6 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; @@ -24,9 +25,13 @@ * * @author Tobias Schultze * @author Grégoire Pineau + * + * @final since Symfony 6.1 */ class ConsoleFormatter implements FormatterInterface { + use CompatibilityFormatter; + public const SIMPLE_FORMAT = "%datetime% %start_tag%%level_name%%end_tag% [%channel%] %message%%context%%extra%\n"; public const SIMPLE_DATE = 'H:i:s'; @@ -98,11 +103,11 @@ public function formatBatch(array $records): mixed return $records; } - /** - * {@inheritdoc} - */ - public function format(array $record): mixed + private function doFormat(array|LogRecord $record): mixed { + if ($record instanceof LogRecord) { + $record = $record->toArray(); + } $record = $this->replacePlaceHolder($record); if (!$this->options['ignore_empty_context_and_extra'] || !empty($record['context'])) { diff --git a/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php b/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php index e745afec13650..92cf6c3e887b4 100644 --- a/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php +++ b/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php @@ -12,13 +12,18 @@ namespace Symfony\Bridge\Monolog\Formatter; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; use Symfony\Component\VarDumper\Cloner\VarCloner; /** * @author Grégoire Pineau + * + * @final since Symfony 6.1 */ class VarDumperFormatter implements FormatterInterface { + use CompatibilityFormatter; + private VarCloner $cloner; public function __construct(VarCloner $cloner = null) @@ -26,11 +31,12 @@ public function __construct(VarCloner $cloner = null) $this->cloner = $cloner ?? new VarCloner(); } - /** - * {@inheritdoc} - */ - public function format(array $record): mixed + private function doFormat(array|LogRecord $record): mixed { + if ($record instanceof LogRecord) { + $record = $record->toArray(); + } + $record['context'] = $this->cloner->cloneVar($record['context']); $record['extra'] = $this->cloner->cloneVar($record['extra']); diff --git a/src/Symfony/Bridge/Monolog/Handler/CompatibilityHandler.php b/src/Symfony/Bridge/Monolog/Handler/CompatibilityHandler.php new file mode 100644 index 0000000000000..dbeb59e4feb3b --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Handler/CompatibilityHandler.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler; + +use Monolog\Logger; +use Monolog\LogRecord; + +if (Logger::API >= 3) { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityHandler + { + abstract private function doHandle(array|LogRecord $record): bool; + + /** + * {@inheritdoc} + */ + public function handle(LogRecord $record): bool + { + return $this->doHandle($record); + } + } +} else { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityHandler + { + abstract private function doHandle(array|LogRecord $record): bool; + + /** + * {@inheritdoc} + */ + public function handle(array $record): bool + { + return $this->doHandle($record); + } + } +} diff --git a/src/Symfony/Bridge/Monolog/Handler/CompatibilityProcessingHandler.php b/src/Symfony/Bridge/Monolog/Handler/CompatibilityProcessingHandler.php new file mode 100644 index 0000000000000..c84c457859d52 --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Handler/CompatibilityProcessingHandler.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler; + +use Monolog\Logger; +use Monolog\LogRecord; + +if (Logger::API >= 3) { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityProcessingHandler + { + abstract private function doWrite(array|LogRecord $record): void; + + /** + * {@inheritdoc} + */ + protected function write(LogRecord $record): void + { + $this->doWrite($record); + } + } +} else { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityProcessingHandler + { + abstract private function doWrite(array|LogRecord $record): void; + + /** + * {@inheritdoc} + */ + protected function write(array $record): void + { + $this->doWrite($record); + } + } +} diff --git a/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php b/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php index 3c911f3cfa91d..88936ff2bfbd8 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php @@ -15,6 +15,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleCommandEvent; @@ -24,6 +25,48 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\VarDumper\Dumper\CliDumper; +if (Logger::API >= 3) { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityIsHandlingHandler + { + abstract private function doIsHandling(array|LogRecord $record): bool; + + /** + * {@inheritdoc} + */ + public function isHandling(LogRecord $record): bool + { + return $this->doIsHandling($record); + } + } +} else { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityIsHandlingHandler + { + abstract private function doIsHandling(array|LogRecord $record): bool; + + /** + * {@inheritdoc} + */ + public function isHandling(array $record): bool + { + return $this->doIsHandling($record); + } + } +} + /** * Writes logs to the console output depending on its verbosity setting. * @@ -40,9 +83,15 @@ * This mapping can be customized with the $verbosityLevelMap constructor parameter. * * @author Tobias Schultze + * + * @final since Symfony 6.1 */ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscriberInterface { + use CompatibilityHandler; + use CompatibilityIsHandlingHandler; + use CompatibilityProcessingHandler; + private ?OutputInterface $output; private array $verbosityLevelMap = [ OutputInterface::VERBOSITY_QUIET => Logger::ERROR, @@ -75,7 +124,7 @@ public function __construct(OutputInterface $output = null, bool $bubble = true, /** * {@inheritdoc} */ - public function isHandling(array $record): bool + private function doIsHandling(array|LogRecord $record): bool { return $this->updateLevel() && parent::isHandling($record); } @@ -83,7 +132,7 @@ public function isHandling(array $record): bool /** * {@inheritdoc} */ - public function handle(array $record): bool + private function doHandle(array|LogRecord $record): bool { // we have to update the logging level each time because the verbosity of the // console output might have changed in the meantime (it is not immutable) @@ -141,10 +190,7 @@ public static function getSubscribedEvents(): array ]; } - /** - * {@inheritdoc} - */ - protected function write(array $record): void + private function doWrite(array|LogRecord $record): void { // at this point we've determined for sure that we want to output the record, so use the output's own verbosity $this->output->write((string) $record['formatted'], false, $this->output->getVerbosity()); diff --git a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php index 86af1d21bd02d..18e64d23e1584 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php @@ -16,7 +16,10 @@ use Monolog\Handler\AbstractHandler; use Monolog\Handler\FormattableHandlerTrait; use Monolog\Handler\ProcessableHandlerTrait; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Component\HttpClient\HttpClient; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -39,9 +42,13 @@ * stack is recommended. * * @author Grégoire Pineau + * + * @final since Symfony 6.1 */ class ElasticsearchLogstashHandler extends AbstractHandler { + use CompatibilityHandler; + use FormattableHandlerTrait; use ProcessableHandlerTrait; @@ -54,7 +61,7 @@ class ElasticsearchLogstashHandler extends AbstractHandler */ private \SplObjectStorage $responses; - public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, string|int $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, string|int|Level|LevelName $level = Logger::DEBUG, bool $bubble = true) { if (!interface_exists(HttpClientInterface::class)) { throw new \LogicException(sprintf('The "%s" handler needs an HTTP client. Try running "composer require symfony/http-client".', __CLASS__)); @@ -67,7 +74,7 @@ public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $ $this->responses = new \SplObjectStorage(); } - public function handle(array $record): bool + private function doHandle(array|LogRecord $record): bool { if (!$this->isHandling($record)) { return false; diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php index fc78f2dc32c49..da48f08933289 100644 --- a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Monolog\Handler\FingersCrossed; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; +use Monolog\LogRecord; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -41,7 +42,7 @@ public function __construct( } } - public function isHandlerActivated(array $record): bool + public function isHandlerActivated(array|LogRecord $record): bool { $isActivated = $this->inner->isHandlerActivated($record); diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php index 808d863cec663..b825ef81164f9 100644 --- a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Monolog\Handler\FingersCrossed; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; +use Monolog\LogRecord; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -34,7 +35,7 @@ public function __construct( $this->exclude = '{('.implode('|', $excludedUrls).')}i'; } - public function isHandlerActivated(array $record): bool + public function isHandlerActivated(array|LogRecord $record): bool { $isActivated = $this->inner->isHandlerActivated($record); diff --git a/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php b/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php index f0446b09f3169..25a0e1d04f176 100644 --- a/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php @@ -15,19 +15,26 @@ use Monolog\Formatter\HtmlFormatter; use Monolog\Formatter\LineFormatter; use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Email; /** * @author Alexander Borisov + * + * @final since Symfony 6.1 */ class MailerHandler extends AbstractProcessingHandler { + use CompatibilityProcessingHandler; + private MailerInterface $mailer; private \Closure|Email $messageTemplate; - public function __construct(MailerInterface $mailer, callable|Email $messageTemplate, string|int $level = Logger::DEBUG, bool $bubble = true) + public function __construct(MailerInterface $mailer, callable|Email $messageTemplate, string|int|Level|LevelName $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); @@ -42,11 +49,21 @@ public function handleBatch(array $records): void { $messages = []; - foreach ($records as $record) { - if ($record['level'] < $this->level) { - continue; + if (Logger::API >= 3) { + /** @var LogRecord $record */ + foreach ($records as $record) { + if ($record->level->isLowerThan($this->level)) { + continue; + } + $messages[] = $this->processRecord($record); + } + } else { + foreach ($records as $record) { + if ($record['level'] < $this->level) { + continue; + } + $messages[] = $this->processRecord($record); } - $messages[] = $this->processRecord($record); } if (!empty($messages)) { @@ -57,7 +74,7 @@ public function handleBatch(array $records): void /** * {@inheritdoc} */ - protected function write(array $record): void + private function doWrite(array|LogRecord $record): void { $this->send((string) $record['formatted'], [$record]); } @@ -125,7 +142,7 @@ protected function buildMessage(string $content, array $records): Email return $message; } - protected function getHighestRecord(array $records): array + protected function getHighestRecord(array $records): array|LogRecord { $highestRecord = null; foreach ($records as $record) { diff --git a/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php b/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php index a129085c905e5..ecffbef254dc8 100644 --- a/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php @@ -13,6 +13,7 @@ use Monolog\Handler\AbstractHandler; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Component\Notifier\Notification\Notification; use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\NotifierInterface; @@ -21,19 +22,23 @@ * Uses Notifier as a log handler. * * @author Fabien Potencier + * + * @final since Symfony 6.1 */ class NotifierHandler extends AbstractHandler { + use CompatibilityHandler; + private NotifierInterface $notifier; - public function __construct(NotifierInterface $notifier, string|int $level = Logger::ERROR, bool $bubble = true) + public function __construct(NotifierInterface $notifier, string|int|Level|LevelName $level = Logger::ERROR, bool $bubble = true) { $this->notifier = $notifier; parent::__construct(Logger::toMonologLevel($level) < Logger::ERROR ? Logger::ERROR : $level, $bubble); } - public function handle(array $record): bool + private function doHandle(array|LogRecord $record): bool { if (!$this->isHandling($record)) { return false; diff --git a/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php b/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php index b14d8e241cf13..c06828cac0b93 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php @@ -14,12 +14,20 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\FormattableHandlerTrait; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter; if (trait_exists(FormattableHandlerTrait::class)) { + /** + * @final since Symfony 6.1 + */ class ServerLogHandler extends AbstractProcessingHandler { + use CompatibilityHandler; + use CompatibilityProcessingHandler; use ServerLogHandlerTrait; /** @@ -31,8 +39,13 @@ protected function getDefaultFormatter(): FormatterInterface } } } else { + /** + * @final since Symfony 6.1 + */ class ServerLogHandler extends AbstractProcessingHandler { + use CompatibilityHandler; + use CompatibilityProcessingHandler; use ServerLogHandlerTrait; /** @@ -47,6 +60,8 @@ protected function getDefaultFormatter() /** * @author Grégoire Pineau + * + * @internal since Symfony 6.1 */ trait ServerLogHandlerTrait { @@ -62,7 +77,7 @@ trait ServerLogHandlerTrait */ private $socket; - public function __construct(string $host, string|int $level = Logger::DEBUG, bool $bubble = true, array $context = []) + public function __construct(string $host, string|int|Level|LevelName $level = Logger::DEBUG, bool $bubble = true, array $context = []) { parent::__construct($level, $bubble); @@ -74,10 +89,7 @@ public function __construct(string $host, string|int $level = Logger::DEBUG, boo $this->context = stream_context_create($context); } - /** - * {@inheritdoc} - */ - public function handle(array $record): bool + private function doHandle(array|LogRecord $record): bool { if (!$this->isHandling($record)) { return false; @@ -96,7 +108,7 @@ public function handle(array $record): bool return parent::handle($record); } - protected function write(array $record): void + private function doWrite(array|LogRecord $record): void { $recordFormatted = $this->formatRecord($record); @@ -139,7 +151,7 @@ private function createSocket() return $socket; } - private function formatRecord(array $record): string + private function formatRecord(array|LogRecord $record): string { $recordFormatted = $record['formatted']; diff --git a/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php b/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php index f98969700bcab..c455be29a33ec 100644 --- a/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/AbstractTokenProcessor.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Monolog\Processor; +use Monolog\LogRecord; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -19,9 +20,13 @@ * * @author Dany Maillard * @author Igor Timoshenko + * + * @internal since Symfony 6.1 */ abstract class AbstractTokenProcessor { + use CompatibilityProcessor; + /** * @var TokenStorageInterface */ @@ -36,7 +41,7 @@ abstract protected function getKey(): string; abstract protected function getToken(): ?TokenInterface; - public function __invoke(array $record): array + private function doInvoke(array|LogRecord $record): array|LogRecord { $record['extra'][$this->getKey()] = null; diff --git a/src/Symfony/Bridge/Monolog/Processor/CompatibilityProcessor.php b/src/Symfony/Bridge/Monolog/Processor/CompatibilityProcessor.php new file mode 100644 index 0000000000000..2f337b29febcf --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Processor/CompatibilityProcessor.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Monolog\Logger; +use Monolog\LogRecord; + +if (Logger::API >= 3) { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityProcessor + { + abstract private function doInvoke(array|LogRecord $record): array|LogRecord; + + public function __invoke(LogRecord $record): LogRecord + { + return $this->doInvoke($record); + } + } +} else { + /** + * The base class for compatibility between Monolog 3 LogRecord and Monolog 1/2 array records. + * + * @author Jordi Boggiano + * + * @internal + */ + trait CompatibilityProcessor + { + abstract private function doInvoke(array|LogRecord $record): array|LogRecord; + + public function __invoke(array $record): array + { + return $this->doInvoke($record); + } + } +} diff --git a/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php b/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php index a1e1c144379ba..a5b26eacbae83 100644 --- a/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Monolog\Processor; +use Monolog\LogRecord; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -20,9 +21,13 @@ * Adds the current console command information to the log entry. * * @author Piotr Stankowski + * + * @final since Symfony 6.1 */ class ConsoleCommandProcessor implements EventSubscriberInterface, ResetInterface { + use CompatibilityProcessor; + private array $commandData; private bool $includeArguments; private bool $includeOptions; @@ -33,13 +38,13 @@ public function __construct(bool $includeArguments = true, bool $includeOptions $this->includeOptions = $includeOptions; } - public function __invoke(array $records) + private function doInvoke(array|LogRecord $record): array|LogRecord { - if (isset($this->commandData) && !isset($records['extra']['command'])) { - $records['extra']['command'] = $this->commandData; + if (isset($this->commandData) && !isset($record['extra']['command'])) { + $record['extra']['command'] = $this->commandData; } - return $records; + return $record; } public function reset() diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php index bca5b948c6b9b..a033d73c3b187 100644 --- a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Monolog\Processor; use Monolog\Logger; +use Monolog\LogRecord; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; @@ -19,6 +20,8 @@ class DebugProcessor implements DebugLoggerInterface, ResetInterface { + use CompatibilityProcessor; + private array $records = []; private array $errorCount = []; private ?RequestStack $requestStack; @@ -28,7 +31,7 @@ public function __construct(RequestStack $requestStack = null) $this->requestStack = $requestStack; } - public function __invoke(array $record) + private function doInvoke(array|LogRecord $record): array|LogRecord { $hash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; diff --git a/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php b/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php index 0bb738f378532..c9f28af084068 100644 --- a/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Monolog\Processor; +use Monolog\LogRecord; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; @@ -35,13 +36,13 @@ public function __construct(bool $includeParams = true) $this->reset(); } - public function __invoke(array $records): array + public function __invoke(array|LogRecord $record): array|LogRecord { - if ($this->routeData && !isset($records['extra']['requests'])) { - $records['extra']['requests'] = array_values($this->routeData); + if ($this->routeData && !isset($record['extra']['requests'])) { + $record['extra']['requests'] = array_values($this->routeData); } - return $records; + return $record; } public function reset() diff --git a/src/Symfony/Bridge/Monolog/Processor/SwitchUserTokenProcessor.php b/src/Symfony/Bridge/Monolog/Processor/SwitchUserTokenProcessor.php index 76aa7e479d0e5..bb3f6ff73d0cd 100644 --- a/src/Symfony/Bridge/Monolog/Processor/SwitchUserTokenProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/SwitchUserTokenProcessor.php @@ -18,6 +18,8 @@ * Adds the original security token to the log entry. * * @author Igor Timoshenko + * + * @final since Symfony 6.1 */ class SwitchUserTokenProcessor extends AbstractTokenProcessor { diff --git a/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php b/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php index 7ca212eb29770..c824ea1761efd 100644 --- a/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php @@ -18,6 +18,8 @@ * * @author Dany Maillard * @author Igor Timoshenko + * + * @final since Symfony 6.1 */ class TokenProcessor extends AbstractTokenProcessor { diff --git a/src/Symfony/Bridge/Monolog/Tests/Formatter/ConsoleFormatterTest.php b/src/Symfony/Bridge/Monolog/Tests/Formatter/ConsoleFormatterTest.php index 89d5bee454548..8e847c522642e 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Formatter/ConsoleFormatterTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Formatter/ConsoleFormatterTest.php @@ -12,15 +12,17 @@ namespace Symfony\Bridge\Monolog\Tests\Formatter; use Monolog\Logger; +use Monolog\LogRecord; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter; +use Symfony\Bridge\Monolog\Tests\RecordFactory; class ConsoleFormatterTest extends TestCase { /** * @dataProvider providerFormatTests */ - public function testFormat(array $record, $expectedMessage) + public function testFormat(array|LogRecord $record, $expectedMessage) { $formatter = new ConsoleFormatter(); self::assertSame($expectedMessage, $formatter->format($record)); @@ -28,25 +30,20 @@ public function testFormat(array $record, $expectedMessage) public function providerFormatTests(): array { - $currentDateTime = new \DateTime(); + $currentDateTime = new \DateTimeImmutable(); - return [ + $tests = [ 'record with DateTime object in datetime field' => [ - 'record' => [ - 'message' => 'test', - 'context' => [], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => $currentDateTime, - 'extra' => [], - ], + 'record' => RecordFactory::create(datetime: $currentDateTime), 'expectedMessage' => sprintf( "%s WARNING [test] test\n", $currentDateTime->format(ConsoleFormatter::SIMPLE_DATE) ), ], - 'record with string in datetime field' => [ + ]; + + if (Logger::API < 3) { + $tests['record with string in datetime field'] = [ 'record' => [ 'message' => 'test', 'context' => [], @@ -57,7 +54,9 @@ public function providerFormatTests(): array 'extra' => [], ], 'expectedMessage' => "2019-01-01T00:42:00+00:00 WARNING [test] test\n", - ], - ]; + ]; + } + + return $tests; } } diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/ConsoleHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/ConsoleHandlerTest.php index d61692ed76466..f7f09c389f8a4 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/ConsoleHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/ConsoleHandlerTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter; use Symfony\Bridge\Monolog\Handler\ConsoleHandler; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleCommandEvent; @@ -41,7 +42,7 @@ public function testConstructor() public function testIsHandling() { $handler = new ConsoleHandler(); - $this->assertFalse($handler->isHandling([]), '->isHandling returns false when no output is set'); + $this->assertFalse($handler->isHandling(RecordFactory::create()), '->isHandling returns false when no output is set'); } /** @@ -56,7 +57,7 @@ public function testVerbosityMapping($verbosity, $level, $isHandling, array $map ->willReturn($verbosity) ; $handler = new ConsoleHandler($output, true, $map); - $this->assertSame($isHandling, $handler->isHandling(['level' => $level]), + $this->assertSame($isHandling, $handler->isHandling(RecordFactory::create($level)), '->isHandling returns correct value depending on console verbosity and log level' ); @@ -77,15 +78,7 @@ public function testVerbosityMapping($verbosity, $level, $isHandling, array $map ->with($log, false); $handler = new ConsoleHandler($realOutput, true, $map); - $infoRecord = [ - 'message' => 'My info message', - 'context' => [], - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'app', - 'datetime' => new \DateTime('2013-05-29 16:21:54'), - 'extra' => [], - ]; + $infoRecord = RecordFactory::create($level, 'My info message', 'app', datetime: new \DateTimeImmutable('2013-05-29 16:21:54')); $this->assertFalse($handler->handle($infoRecord), 'The handler finished handling the log.'); } @@ -123,10 +116,10 @@ public function testVerbosityChanged() ) ; $handler = new ConsoleHandler($output); - $this->assertFalse($handler->isHandling(['level' => Logger::NOTICE]), + $this->assertFalse($handler->isHandling(RecordFactory::create(Logger::NOTICE)), 'when verbosity is set to quiet, the handler does not handle the log' ); - $this->assertTrue($handler->isHandling(['level' => Logger::NOTICE]), + $this->assertTrue($handler->isHandling(RecordFactory::create(Logger::NOTICE)), 'since the verbosity of the output increased externally, the handler is now handling the log' ); } @@ -157,15 +150,7 @@ public function testWritingAndFormatting() $handler = new ConsoleHandler(null, false); $handler->setOutput($output); - $infoRecord = [ - 'message' => 'My info message', - 'context' => [], - 'level' => Logger::INFO, - 'level_name' => Logger::getLevelName(Logger::INFO), - 'channel' => 'app', - 'datetime' => new \DateTime('2013-05-29 16:21:54'), - 'extra' => [], - ]; + $infoRecord = RecordFactory::create(Logger::INFO, 'My info message', 'app', datetime: new \DateTimeImmutable('2013-05-29 16:21:54')); $this->assertTrue($handler->handle($infoRecord), 'The handler finished handling the log as bubble is false.'); } diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php index 2940f0440ff8f..1074ca47d32ee 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/ElasticsearchLogstashHandlerTest.php @@ -16,6 +16,7 @@ use Monolog\Logger; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Handler\ElasticsearchLogstashHandler; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\MockResponse; @@ -47,24 +48,17 @@ public function testHandle() return new MockResponse(); }; - $handler = new ElasticsearchLogstashHandlerWithHardCodedHostname('http://es:9200', 'log', new MockHttpClient($responseFactory)); + $handler = new ElasticsearchLogstashHandler('http://es:9200', 'log', new MockHttpClient($responseFactory)); + $handler->setFormatter($this->getDefaultFormatter()); - $record = [ - 'message' => 'My info message', - 'context' => [], - 'level' => Logger::INFO, - 'level_name' => Logger::getLevelName(Logger::INFO), - 'channel' => 'app', - 'datetime' => new \DateTime('2020-01-01T00:00:00+01:00'), - 'extra' => [], - ]; + $record = RecordFactory::create(Logger::INFO, 'My info message', 'app', datetime: new \DateTimeImmutable('2020-01-01T00:00:00+01:00')); $handler->handle($record); $this->assertSame(1, $callCount); } - public function testBandleBatch() + public function testHandleBatch() { $callCount = 0; $responseFactory = function ($method, $url, $options) use (&$callCount) { @@ -93,38 +87,20 @@ public function testBandleBatch() return new MockResponse(); }; - $handler = new ElasticsearchLogstashHandlerWithHardCodedHostname('http://es:9200', 'log', new MockHttpClient($responseFactory)); + $handler = new ElasticsearchLogstashHandler('http://es:9200', 'log', new MockHttpClient($responseFactory)); + $handler->setFormatter($this->getDefaultFormatter()); $records = [ - [ - 'message' => 'My info message', - 'context' => [], - 'level' => Logger::INFO, - 'level_name' => Logger::getLevelName(Logger::INFO), - 'channel' => 'app', - 'datetime' => new \DateTime('2020-01-01T00:00:00+01:00'), - 'extra' => [], - ], - [ - 'message' => 'My second message', - 'context' => [], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'php', - 'datetime' => new \DateTime('2020-01-01T00:00:01+01:00'), - 'extra' => [], - ], + RecordFactory::create(Logger::INFO, 'My info message', 'app', datetime: new \DateTimeImmutable('2020-01-01T00:00:00+01:00')), + RecordFactory::create(Logger::WARNING, 'My second message', 'php', datetime: new \DateTimeImmutable('2020-01-01T00:00:01+01:00')), ]; $handler->handleBatch($records); $this->assertSame(1, $callCount); } -} -class ElasticsearchLogstashHandlerWithHardCodedHostname extends ElasticsearchLogstashHandler -{ - protected function getDefaultFormatter(): FormatterInterface + private function getDefaultFormatter(): FormatterInterface { // Monolog 1.X if (\defined(LogstashFormatter::class.'::V1')) { diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php index ea6931670d863..81613fe21e0e0 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php @@ -15,6 +15,7 @@ use Monolog\Logger; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -58,16 +59,16 @@ public function testIsActivated($url, $record, $expected) public function isActivatedProvider(): array { return [ - ['/test', ['level' => Logger::ERROR], true], - ['/400', ['level' => Logger::ERROR, 'context' => $this->getContextException(400)], true], - ['/400/a', ['level' => Logger::ERROR, 'context' => $this->getContextException(400)], false], - ['/400/b', ['level' => Logger::ERROR, 'context' => $this->getContextException(400)], false], - ['/400/c', ['level' => Logger::ERROR, 'context' => $this->getContextException(400)], true], - ['/401', ['level' => Logger::ERROR, 'context' => $this->getContextException(401)], true], - ['/403', ['level' => Logger::ERROR, 'context' => $this->getContextException(403)], false], - ['/404', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], false], - ['/405', ['level' => Logger::ERROR, 'context' => $this->getContextException(405)], false], - ['/500', ['level' => Logger::ERROR, 'context' => $this->getContextException(500)], true], + ['/test', RecordFactory::create(Logger::ERROR), true], + ['/400', RecordFactory::create(Logger::ERROR, context: $this->getContextException(400)), true], + ['/400/a', RecordFactory::create(Logger::ERROR, context: $this->getContextException(400)), false], + ['/400/b', RecordFactory::create(Logger::ERROR, context: $this->getContextException(400)), false], + ['/400/c', RecordFactory::create(Logger::ERROR, context: $this->getContextException(400)), true], + ['/401', RecordFactory::create(Logger::ERROR, context: $this->getContextException(401)), true], + ['/403', RecordFactory::create(Logger::ERROR, context: $this->getContextException(403)), false], + ['/404', RecordFactory::create(Logger::ERROR, context: $this->getContextException(404)), false], + ['/405', RecordFactory::create(Logger::ERROR, context: $this->getContextException(405)), false], + ['/500', RecordFactory::create(Logger::ERROR, context: $this->getContextException(500)), true], ]; } diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php index 95590186d55f3..f58e9afa7164e 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php @@ -13,8 +13,10 @@ use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Logger; +use Monolog\LogRecord; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -24,7 +26,7 @@ class NotFoundActivationStrategyTest extends TestCase /** * @dataProvider isActivatedProvider */ - public function testIsActivated(string $url, array $record, bool $expected) + public function testIsActivated(string $url, array|LogRecord $record, bool $expected) { $requestStack = new RequestStack(); $requestStack->push(Request::create($url)); @@ -37,15 +39,15 @@ public function testIsActivated(string $url, array $record, bool $expected) public function isActivatedProvider(): array { return [ - ['/test', ['level' => Logger::DEBUG], false], - ['/foo', ['level' => Logger::DEBUG, 'context' => $this->getContextException(404)], false], - ['/baz/bar', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], false], - ['/foo', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], false], - ['/foo', ['level' => Logger::ERROR, 'context' => $this->getContextException(500)], true], - - ['/test', ['level' => Logger::ERROR], true], - ['/baz', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], true], - ['/baz', ['level' => Logger::ERROR, 'context' => $this->getContextException(500)], true], + ['/test', RecordFactory::create(Logger::DEBUG), false], + ['/foo', RecordFactory::create(Logger::DEBUG, context: $this->getContextException(404)), false], + ['/baz/bar', RecordFactory::create(Logger::ERROR, context: $this->getContextException(404)), false], + ['/foo', RecordFactory::create(Logger::ERROR, context: $this->getContextException(404)), false], + ['/foo', RecordFactory::create(Logger::ERROR, context: $this->getContextException(500)), true], + + ['/test', RecordFactory::create(Logger::ERROR), true], + ['/baz', RecordFactory::create(Logger::ERROR, context: $this->getContextException(404)), true], + ['/baz', RecordFactory::create(Logger::ERROR, context: $this->getContextException(500)), true], ]; } diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/MailerHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/MailerHandlerTest.php index daec7676c9e99..43d5ef3cfab72 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/MailerHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/MailerHandlerTest.php @@ -13,10 +13,12 @@ use Monolog\Formatter\HtmlFormatter; use Monolog\Formatter\LineFormatter; +use Monolog\LogRecord; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Handler\MailerHandler; use Symfony\Bridge\Monolog\Logger; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Email; @@ -91,17 +93,9 @@ public function testHtmlContent() $handler->handle($this->getRecord(Logger::WARNING, 'message')); } - protected function getRecord($level = Logger::WARNING, $message = 'test', $context = []): array + protected function getRecord($level = Logger::WARNING, $message = 'test', $context = []): array|LogRecord { - return [ - 'message' => $message, - 'context' => $context, - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'test', - 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true))), - 'extra' => [], - ]; + return RecordFactory::create($level, $message, context: $context); } protected function getMultipleRecords(): array diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/ServerLogHandlerTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/ServerLogHandlerTest.php index f5a4405f645f1..cade0b80ec9fd 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Handler/ServerLogHandlerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/ServerLogHandlerTest.php @@ -17,6 +17,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter; use Symfony\Bridge\Monolog\Handler\ServerLogHandler; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\VarDumper\Cloner\Data; /** @@ -37,7 +38,7 @@ public function testFormatter() public function testIsHandling() { $handler = new ServerLogHandler('tcp://127.0.0.1:9999', Logger::INFO); - $this->assertFalse($handler->isHandling(['level' => Logger::DEBUG]), '->isHandling returns false when no output is set'); + $this->assertFalse($handler->isHandling(RecordFactory::create(Logger::DEBUG)), '->isHandling returns false when no output is set'); } public function testGetFormatter() @@ -54,15 +55,7 @@ public function testWritingAndFormatting() $handler = new ServerLogHandler($host, Logger::INFO, false); $handler->pushProcessor(new ProcessIdProcessor()); - $infoRecord = [ - 'message' => 'My info message', - 'context' => [], - 'level' => Logger::INFO, - 'level_name' => Logger::getLevelName(Logger::INFO), - 'channel' => 'app', - 'datetime' => new \DateTime('2013-05-29 16:21:54'), - 'extra' => [], - ]; + $infoRecord = RecordFactory::create(Logger::INFO, 'My info message', 'app', datetime: new \DateTimeImmutable('2013-05-29 16:21:54')); $socket = stream_socket_server($host, $errno, $errstr); $this->assertIsResource($socket, sprintf('Server start failed on "%s": %s %s.', $host, $errstr, $errno)); diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php index 424f9ce10d597..c824721217ca5 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Processor\ConsoleCommandProcessor; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Input\InputInterface; @@ -29,7 +30,7 @@ public function testProcessor() $processor = new ConsoleCommandProcessor(); $processor->addCommandData($this->getConsoleEvent()); - $record = $processor(['extra' => []]); + $record = $processor(RecordFactory::create()); $this->assertArrayHasKey('command', $record['extra']); $this->assertEquals( @@ -43,7 +44,7 @@ public function testProcessorWithOptions() $processor = new ConsoleCommandProcessor(true, true); $processor->addCommandData($this->getConsoleEvent()); - $record = $processor(['extra' => []]); + $record = $processor(RecordFactory::create()); $this->assertArrayHasKey('command', $record['extra']); $this->assertEquals( @@ -56,8 +57,8 @@ public function testProcessorDoesNothingWhenNotInConsole() { $processor = new ConsoleCommandProcessor(true, true); - $record = $processor(['extra' => []]); - $this->assertEquals(['extra' => []], $record); + $record = $processor(RecordFactory::create()); + $this->assertEquals([], $record['extra']); } private function getConsoleEvent(): ConsoleEvent diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php index c576462d0abfe..8de9a956e7282 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php @@ -12,59 +12,35 @@ namespace Symfony\Bridge\Monolog\Tests\Processor; use Monolog\Logger; +use Monolog\LogRecord; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Processor\DebugProcessor; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; class DebugProcessorTest extends TestCase { - /** - * @dataProvider providerDatetimeFormatTests - */ - public function testDatetimeFormat(array $record, $expectedTimestamp) + public function testDatetimeFormat() { + $record = RecordFactory::create(datetime: new \DateTimeImmutable('2019-01-01T00:01:00+00:00')); $processor = new DebugProcessor(); $processor($record); $records = $processor->getLogs(); self::assertCount(1, $records); - self::assertSame($expectedTimestamp, $records[0]['timestamp']); + self::assertSame(1546300860, $records[0]['timestamp']); } - public function providerDatetimeFormatTests(): array - { - $record = $this->getRecord(); - - return [ - [array_merge($record, ['datetime' => new \DateTime('2019-01-01T00:01:00+00:00')]), 1546300860], - [array_merge($record, ['datetime' => '2019-01-01T00:01:00+00:00']), 1546300860], - [array_merge($record, ['datetime' => 'foo']), false], - ]; - } - - /** - * @dataProvider providerDatetimeRfc3339FormatTests - */ - public function testDatetimeRfc3339Format(array $record, $expectedTimestamp) + public function testDatetimeRfc3339Format() { + $record = RecordFactory::create(datetime: new \DateTimeImmutable('2019-01-01T00:01:00+00:00')); $processor = new DebugProcessor(); $processor($record); $records = $processor->getLogs(); self::assertCount(1, $records); - self::assertSame($expectedTimestamp, $records[0]['timestamp_rfc3339']); - } - - public function providerDatetimeRfc3339FormatTests(): array - { - $record = $this->getRecord(); - - return [ - [array_merge($record, ['datetime' => new \DateTime('2019-01-01T00:01:00+00:00')]), '2019-01-01T00:01:00.000+00:00'], - [array_merge($record, ['datetime' => '2019-01-01T00:01:00+00:00']), '2019-01-01T00:01:00.000+00:00'], - [array_merge($record, ['datetime' => 'foo']), false], - ]; + self::assertSame('2019-01-01T00:01:00.000+00:00', $records[0]['timestamp_rfc3339']); } public function testDebugProcessor() @@ -123,16 +99,8 @@ public function testInheritedClassCallCountErrorsWithoutArgument() $this->assertEquals(0, $debugProcessorChild->countErrors()); } - private function getRecord($level = Logger::WARNING, $message = 'test'): array + private function getRecord($level = Logger::WARNING, $message = 'test'): array|LogRecord { - return [ - 'message' => $message, - 'context' => [], - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'test', - 'datetime' => new \DateTime(), - 'extra' => [], - ]; + return RecordFactory::create($level, $message); } } diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/SwitchUserTokenProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/SwitchUserTokenProcessorTest.php index 602e9db61a82d..03706d7680e11 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/SwitchUserTokenProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/SwitchUserTokenProcessorTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; @@ -33,7 +34,7 @@ public function testProcessor() $tokenStorage->method('getToken')->willReturn($switchUserToken); $processor = new SwitchUserTokenProcessor($tokenStorage); - $record = ['extra' => []]; + $record = RecordFactory::create(); $record = $processor($record); $expected = [ diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php index 249757d562e01..603b6f2ce131e 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Processor\TokenProcessor; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\User\InMemoryUser; @@ -31,7 +32,7 @@ public function testProcessor() $tokenStorage->method('getToken')->willReturn($token); $processor = new TokenProcessor($tokenStorage); - $record = ['extra' => []]; + $record = RecordFactory::create(); $record = $processor($record); $this->assertArrayHasKey('token', $record['extra']); diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php index 9b70b4bbfbc25..3ae74658097de 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php @@ -12,8 +12,10 @@ namespace Symfony\Bridge\Monolog\Tests\Processor; use Monolog\Logger; +use Monolog\LogRecord; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Monolog\Processor\WebProcessor; +use Symfony\Bridge\Monolog\Tests\RecordFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -94,17 +96,9 @@ private function createRequestEvent(array $additionalServerParameters = []): arr return [$event, $server]; } - private function getRecord(int $level = Logger::WARNING, string $message = 'test'): array + private function getRecord(int $level = Logger::WARNING, string $message = 'test'): array|LogRecord { - return [ - 'message' => $message, - 'context' => [], - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'test', - 'datetime' => new \DateTime(), - 'extra' => [], - ]; + return RecordFactory::create($level, $message); } private function isExtraFieldsSupported() diff --git a/src/Symfony/Bridge/Monolog/Tests/RecordFactory.php b/src/Symfony/Bridge/Monolog/Tests/RecordFactory.php new file mode 100644 index 0000000000000..8f7b5a1f78357 --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Tests/RecordFactory.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Tests; + +use Monolog\Logger; +use Monolog\LogRecord; + +class RecordFactory +{ + public static function create(int|string $level = 'warning', string|\Stringable $message = 'test', string $channel = 'test', array $context = [], \DateTimeImmutable $datetime = new \DateTimeImmutable(), array $extra = []): LogRecord|array + { + $level = Logger::toMonologLevel($level); + + if (Logger::API >= 3) { + return new LogRecord( + message: (string) $message, + context: $context, + level: $level, + channel: $channel, + datetime: $datetime, + extra: $extra, + ); + } + + return [ + 'message' => $message, + 'context' => $context, + 'level' => $level, + 'level_name' => Logger::getLevelName($level), + 'channel' => $channel, + // Monolog 1 had no support for DateTimeImmutable + 'datetime' => Logger::API >= 2 ? $datetime : \DateTime::createFromImmutable($datetime), + 'extra' => $extra, + ]; + } +} diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index 040ec44353576..025d54a48398d 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.1", - "monolog/monolog": "^1.25.1|^2", + "monolog/monolog": "^1.25.1|^2|^3", "symfony/service-contracts": "^1.1|^2|^3", "symfony/http-kernel": "^5.4|^6.0" }, From 8d2283916826bde7d653732c84653934613dd77b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 4 May 2022 16:16:30 +0200 Subject: [PATCH 20/65] [RateLimiter] Fix CI on PHP 8.2 --- src/Symfony/Component/RateLimiter/Tests/Policy/RateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/RateLimiter/Tests/Policy/RateTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/RateTest.php index 39a859f587555..a780d34fdb82f 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Policy/RateTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Policy/RateTest.php @@ -26,7 +26,7 @@ public function testFromString(Rate $rate) public function provideRate(): iterable { - yield [new Rate(\DateInterval::createFromDateString('15 seconds'), 10)]; + yield [new Rate(new \DateInterval('PT15S'), 10)]; yield [Rate::perSecond(10)]; yield [Rate::perMinute(10)]; yield [Rate::perHour(10)]; From 8bfb80bd333a58c5b954bf1876b0acde0b8111ae Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 4 May 2022 17:59:37 +0200 Subject: [PATCH 21/65] [WebProfilerBundle] Update the icon of the Serializer profiler panel --- .../Resources/views/Collector/serializer.html.twig | 2 +- .../WebProfilerBundle/Resources/views/Icon/serializer.svg | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/serializer.svg diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/serializer.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/serializer.html.twig index c9197742f065a..7e5ed850c1329 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/serializer.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/serializer.html.twig @@ -4,7 +4,7 @@ {% block menu %} - {{ include('@WebProfiler/Icon/validator.svg') }} + {{ include('@WebProfiler/Icon/serializer.svg') }} Serializer {% endblock %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/serializer.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/serializer.svg new file mode 100644 index 0000000000000..332ed031cec08 --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/serializer.svg @@ -0,0 +1,6 @@ + + + + + + From 884c8cde00b8bdaec1d63f1cf2681bc8e0a71d22 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 5 May 2022 15:04:15 +0200 Subject: [PATCH 22/65] [WebProfilerBundle] Fix tests about web profiler icons --- .../Bundle/WebProfilerBundle/Tests/Resources/IconTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php index a690721ebc018..95b9b153084aa 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Resources/IconTest.php @@ -20,7 +20,7 @@ class IconTest extends TestCase */ public function testIconFileContents($iconFilePath) { - $this->assertMatchesRegularExpression('~.*~s', file_get_contents($iconFilePath), sprintf('The SVG metadata of the %s icon is different than expected (use the same as the other icons).', $iconFilePath)); + $this->assertMatchesRegularExpression('~]*+>.*~s', file_get_contents($iconFilePath), sprintf('The SVG metadata of the %s icon is different than expected (use the same as the other icons).', $iconFilePath)); } public function provideIconFilePaths() From df4c003f406e9f3012b0f3a6b4c53d7440018191 Mon Sep 17 00:00:00 2001 From: javer Date: Thu, 5 May 2022 14:00:32 +0300 Subject: [PATCH 23/65] [EventDispatcher] Fix removing listeners when using first-class callable syntax --- .../Debug/TraceableEventDispatcher.php | 6 ++-- .../EventDispatcher/EventDispatcher.php | 4 +-- .../Tests/EventDispatcherTest.php | 29 +++++++++++++++++++ .../Tests/Firewall/ContextListenerTest.php | 24 +++++++++++++++ .../Tests/Firewall/ExceptionListenerTest.php | 13 +++++++++ 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index e79d1a8e304cc..56116cf44f5cc 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -75,7 +75,7 @@ public function removeListener($eventName, $listener) { if (isset($this->wrappedListeners[$eventName])) { foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { - if ($wrappedListener->getWrappedListener() === $listener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { $listener = $wrappedListener; unset($this->wrappedListeners[$eventName][$index]); break; @@ -110,8 +110,8 @@ public function getListenerPriority($eventName, $listener) // we might have wrapped listeners for the event (if called while dispatching) // in that case get the priority by wrapper if (isset($this->wrappedListeners[$eventName])) { - foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { - if ($wrappedListener->getWrappedListener() === $listener) { + foreach ($this->wrappedListeners[$eventName] as $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { return $this->dispatcher->getListenerPriority($eventName, $wrappedListener); } } diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 8b62227189624..4a8f6c6f121de 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -122,7 +122,7 @@ public function getListenerPriority($eventName, $listener) $v[0] = $v[0](); $v[1] = $v[1] ?? '__invoke'; } - if ($v === $listener) { + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { return $priority; } } @@ -178,7 +178,7 @@ public function removeListener($eventName, $listener) $v[0] = $v[0](); $v[1] = $v[1] ?? '__invoke'; } - if ($v === $listener) { + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); } } diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index 67e78ac25ffa1..9f4a43a33d278 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -421,6 +421,35 @@ public function testMutatingWhilePropagationIsStopped() $this->assertTrue($testLoaded); } + /** + * @requires PHP 8.1 + */ + public function testNamedClosures() + { + $listener = new TestEventListener(); + + $callback1 = \Closure::fromCallable($listener); + $callback2 = \Closure::fromCallable($listener); + $callback3 = \Closure::fromCallable(new TestEventListener()); + + $this->assertNotSame($callback1, $callback2); + $this->assertNotSame($callback1, $callback3); + $this->assertNotSame($callback2, $callback3); + $this->assertTrue($callback1 == $callback2); + $this->assertFalse($callback1 == $callback3); + + $this->dispatcher->addListener('foo', $callback1, 3); + $this->dispatcher->addListener('foo', $callback2, 2); + $this->dispatcher->addListener('foo', $callback3, 1); + + $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', $callback1)); + $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', $callback2)); + + $this->dispatcher->removeListener('foo', $callback1); + + $this->assertSame(['foo' => [$callback3]], $this->dispatcher->getListeners()); + } + /** * @group legacy * @expectedDeprecation Calling the "Symfony\Component\EventDispatcher\EventDispatcherInterface::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead. diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index 7c60132bc055d..f3d9793c72de6 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -342,6 +342,30 @@ public function testWithPreviousNotStartedSession() $this->assertSame($usageIndex, $session->getUsageIndex()); } + public function testOnKernelResponseRemoveListener() + { + $tokenStorage = new TokenStorage(); + $tokenStorage->setToken(new UsernamePasswordToken('test1', 'pass1', 'phpunit', ['ROLE_USER'])); + + $request = new Request(); + $request->attributes->set('_security_firewall_run', '_security_session'); + + $session = new Session(new MockArraySessionStorage()); + $request->setSession($session); + + $dispatcher = new EventDispatcher(); + $httpKernel = $this->createMock(HttpKernelInterface::class); + + $listener = new ContextListener($tokenStorage, [], 'session', null, $dispatcher, null, \Closure::fromCallable([$tokenStorage, 'getToken'])); + $this->assertEmpty($dispatcher->getListeners()); + + $listener(new RequestEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST)); + $this->assertNotEmpty($dispatcher->getListeners()); + + $listener->onKernelResponse(new ResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, new Response())); + $this->assertEmpty($dispatcher->getListeners()); + } + protected function runSessionOnKernelResponse($newToken, $original = null) { $session = new Session(new MockArraySessionStorage()); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 27ad9897ea485..4f1f729ac944d 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Http\Tests\Firewall; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; @@ -170,6 +171,18 @@ public function testLogoutException() $this->assertEquals(403, $event->getThrowable()->getStatusCode()); } + public function testUnregister() + { + $listener = $this->createExceptionListener(); + $dispatcher = new EventDispatcher(); + + $listener->register($dispatcher); + $this->assertNotEmpty($dispatcher->getListeners()); + + $listener->unregister($dispatcher); + $this->assertEmpty($dispatcher->getListeners()); + } + public function getAccessDeniedExceptionProvider() { return [ From c12b7f0fa0c5f79a627b08e08ce0a964b97e269d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 5 May 2022 18:31:39 +0200 Subject: [PATCH 24/65] [DependencyInjection] Fix resolving parameters found in #[Autowire] --- .../Component/DependencyInjection/Compiler/AutowirePass.php | 1 + .../DependencyInjection/Tests/Compiler/AutowirePassTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index b8634eafe4a41..9fde89d142f9a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -263,6 +263,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a if (Autowire::class === $attribute->getName()) { $value = $attribute->newInstance()->value; + $value = $this->container->getParameterBag()->resolveValue($value); if ($value instanceof Reference && $parameter->allowsNull()) { $value = new Reference($value, ContainerInterface::NULL_ON_INVALID_REFERENCE); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index c9422d98b26e1..eac1ec023d7a9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -1145,7 +1145,7 @@ public function testAutowireAttribute() $this->assertCount(8, $definition->getArguments()); $this->assertEquals(new Reference('some.id'), $definition->getArgument(0)); $this->assertEquals(new Expression("parameter('some.parameter')"), $definition->getArgument(1)); - $this->assertSame('%some.parameter%/bar', $definition->getArgument(2)); + $this->assertSame('foo/bar', $definition->getArgument(2)); $this->assertEquals(new Reference('some.id'), $definition->getArgument(3)); $this->assertEquals(new Expression("parameter('some.parameter')"), $definition->getArgument(4)); $this->assertSame('bar', $definition->getArgument(5)); From 89dd2bb2495c67a71a77a88b358f67f9fb9bb7f4 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij Date: Thu, 5 May 2022 14:54:11 +0200 Subject: [PATCH 25/65] [Console] Better required argument check in InputArgument --- src/Symfony/Component/Console/Input/InputArgument.php | 2 +- .../Component/Console/Tests/Input/InputArgumentTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Input/InputArgument.php b/src/Symfony/Component/Console/Input/InputArgument.php index 085aca5a7443e..accd4d0c5b4d7 100644 --- a/src/Symfony/Component/Console/Input/InputArgument.php +++ b/src/Symfony/Component/Console/Input/InputArgument.php @@ -92,7 +92,7 @@ public function isArray() */ public function setDefault($default = null) { - if (self::REQUIRED === $this->mode && null !== $default) { + if ($this->isRequired() && null !== $default) { throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); } diff --git a/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php b/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php index 4e583888a6b86..9dae4e2cace7e 100644 --- a/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php +++ b/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php @@ -88,6 +88,14 @@ public function testSetDefaultWithRequiredArgument() $argument->setDefault('default'); } + public function testSetDefaultWithRequiredArrayArgument() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Cannot set a default value except for InputArgument::OPTIONAL mode.'); + $argument = new InputArgument('foo', InputArgument::REQUIRED | InputArgument::IS_ARRAY); + $argument->setDefault([]); + } + public function testSetDefaultWithArrayArgument() { $this->expectException(\LogicException::class); From 15ca7a5433ae8717d200d3c2fa28aec73837598d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 5 May 2022 18:51:07 +0200 Subject: [PATCH 26/65] cs fix --- .../Component/EventDispatcher/Tests/EventDispatcherTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index f51a1ec804870..291d5b85a0dcd 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -406,9 +406,6 @@ public function testMutatingWhilePropagationIsStopped() $this->assertTrue($testLoaded); } - /** - * @requires PHP 8.1 - */ public function testNamedClosures() { $listener = new TestEventListener(); From b0be8020838a7395e448e1427d2612d500aece53 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 5 May 2022 18:53:12 +0200 Subject: [PATCH 27/65] fix merge --- .../Security/Http/Tests/Firewall/ContextListenerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index bc553c13ea073..101e162289cd5 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -336,7 +336,7 @@ public function testOnKernelResponseRemoveListener() $dispatcher = new EventDispatcher(); $httpKernel = $this->createMock(HttpKernelInterface::class); - $listener = new ContextListener($tokenStorage, [], 'session', null, $dispatcher, null, $tokenStorage->getToken(...))); + $listener = new ContextListener($tokenStorage, [], 'session', null, $dispatcher, null, $tokenStorage->getToken(...)); $this->assertEmpty($dispatcher->getListeners()); $listener(new RequestEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST)); From 0e7a5925a14ee4bcfa7152c091ff947776b2670e Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 5 May 2022 18:59:41 +0200 Subject: [PATCH 28/65] [Notifier] Allow symfony/mercure 0.6 in Mercure bridge --- src/Symfony/Component/Notifier/Bridge/Mercure/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json b/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json index 54137dd9d3cc3..ed13323a28166 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=7.2.5", "ext-json": "*", - "symfony/mercure": "^0.5.2", + "symfony/mercure": "^0.5.2|^0.6", "symfony/notifier": "^5.3|^6.0", "symfony/service-contracts": "^1.10|^2|^3" }, From 29c3e56f15ca245976fe334e7d0570dee8a41a5d Mon Sep 17 00:00:00 2001 From: omniError Date: Thu, 5 May 2022 12:18:14 -0500 Subject: [PATCH 29/65] [HtmlSanitizer] Fix node renderer handling of self-closing (void) elements --- .../Tests/HtmlSanitizerAllTest.php | 14 +++++++++++-- .../HtmlSanitizer/Visitor/Node/Node.php | 21 ++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerAllTest.php b/src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerAllTest.php index 7e53d8c3a3207..18c175ba296e8 100644 --- a/src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerAllTest.php +++ b/src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerAllTest.php @@ -237,16 +237,21 @@ public function provideSanitizeBody() ], [ '', - '', + '', ], [ '', - '', + '', ], [ '
', '
', ], + [ + '

', + '

', + ], + [ '', '', @@ -445,6 +450,11 @@ public function provideSanitizeBody() 'Lorem ipsum', 'Lorem ipsum', ], + [ + '', + '', + ], + [ '
  • Lorem ipsum
  • ', '
  • Lorem ipsum
  • ', diff --git a/src/Symfony/Component/HtmlSanitizer/Visitor/Node/Node.php b/src/Symfony/Component/HtmlSanitizer/Visitor/Node/Node.php index 76838028dbc0d..8a4e5c32aa7ac 100644 --- a/src/Symfony/Component/HtmlSanitizer/Visitor/Node/Node.php +++ b/src/Symfony/Component/HtmlSanitizer/Visitor/Node/Node.php @@ -20,6 +20,25 @@ */ final class Node implements NodeInterface { + // HTML5 elements which are self-closing + private const VOID_ELEMENTS = [ + 'area' => true, + 'base' => true, + 'br' => true, + 'col' => true, + 'embed' => true, + 'hr' => true, + 'img' => true, + 'input' => true, + 'keygen' => true, + 'link' => true, + 'meta' => true, + 'param' => true, + 'source' => true, + 'track' => true, + 'wbr' => true, + ]; + private NodeInterface $parent; private string $tagName; private array $attributes = []; @@ -56,7 +75,7 @@ public function addChild(NodeInterface $node): void public function render(): string { - if (!$this->children) { + if (isset(self::VOID_ELEMENTS[$this->tagName])) { return '<'.$this->tagName.$this->renderAttributes().' />'; } From aa06f58b1a69e2803f681df7753bebe8a25307d4 Mon Sep 17 00:00:00 2001 From: Eduard Morcinek Date: Thu, 5 May 2022 18:33:21 +0200 Subject: [PATCH 30/65] [HttpKernel] Fix SessionListener without session in request #46268 --- .../EventListener/AbstractSessionListener.php | 2 +- .../EventListener/SessionListenerTest.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php index 76c2064d18bf7..5f657bfbdf809 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php @@ -74,7 +74,7 @@ public function onKernelResponse(FilterResponseEvent $event) // Always remove the internal header if present $response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER); - if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : $event->getRequest()->getSession()) { + if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : ($event->getRequest()->hasSession() ? $event->getRequest()->getSession() : null)) { return; } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php index d6ff42f926247..9b49936f468b2 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php @@ -139,6 +139,24 @@ public function testUninitializedSession() $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER)); } + public function testUninitializedSessionWithoutInitializedSession() + { + $kernel = $this->createMock(HttpKernelInterface::class); + $response = new Response(); + $response->setSharedMaxAge(60); + $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true'); + + $container = new ServiceLocator([]); + + $listener = new SessionListener($container); + $listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); + $this->assertFalse($response->headers->has('Expires')); + $this->assertTrue($response->headers->hasCacheControlDirective('public')); + $this->assertFalse($response->headers->hasCacheControlDirective('private')); + $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate')); + $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage')); + } + public function testSurrogateMasterRequestIsPublic() { $session = $this->createMock(Session::class); From 00cea614093308c09afe10ba6397e0bbef1658a9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 6 May 2022 10:09:42 +0200 Subject: [PATCH 31/65] [DependencyInjection] Fix lazyness of AutowiringFailedException --- .../Exception/AutowiringFailedException.php | 2 +- .../AutowiringFailedExceptionTest.php | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php index 88fa9e3506f33..a3d4d9dda9f57 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php @@ -39,7 +39,7 @@ public function __construct(string $serviceId, string|\Closure $message = '', in parent::__construct('', $code, $previous); $this->message = new class($this->message, $this->messageCallback) { - private string $message; + private string|self $message; private ?\Closure $messageCallback; public function __construct(&$message, &$messageCallback) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Exception/AutowiringFailedExceptionTest.php b/src/Symfony/Component/DependencyInjection/Tests/Exception/AutowiringFailedExceptionTest.php index 996b891016956..f94f9a4eb8c16 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Exception/AutowiringFailedExceptionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Exception/AutowiringFailedExceptionTest.php @@ -25,4 +25,25 @@ public function testGetMessageCallbackWhenMessageIsNotANotClosure() self::assertNull($exception->getMessageCallback()); } + + public function testLazyness() + { + $counter = 0; + $exception = new AutowiringFailedException( + 'App\DummyService', + function () use (&$counter) { + ++$counter; + + throw new \Exception('boo'); + } + ); + + $this->assertSame(0, $counter); + + $this->assertSame('boo', $exception->getMessage()); + $this->assertSame(1, $counter); + + $this->assertSame('boo', $exception->getMessage()); + $this->assertSame(1, $counter); + } } From 00b59f606b634bf115a264631dce5f7a3e58f09d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 6 May 2022 10:33:13 +0200 Subject: [PATCH 32/65] [Workflow] Fix deprecated syntax for interpolated strings --- src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php index 76273c01d1ff7..6e75c3c820048 100644 --- a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php @@ -103,8 +103,8 @@ public function dump(Definition $definition, Marking $marking = null, array $opt } $lines = [ - "$fromEscaped -${transitionColor}-> ${transitionEscaped}${transitionLabel}", - "$transitionEscaped -${transitionColor}-> ${toEscaped}${transitionLabel}", + "{$fromEscaped} -{$transitionColor}-> {$transitionEscaped}{$transitionLabel}", + "{$transitionEscaped} -{$transitionColor}-> {$toEscaped}{$transitionLabel}", ]; foreach ($lines as $line) { if (!\in_array($line, $code)) { @@ -112,7 +112,7 @@ public function dump(Definition $definition, Marking $marking = null, array $opt } } } else { - $code[] = "$fromEscaped -${transitionColor}-> $toEscaped: $transitionEscapedWithStyle"; + $code[] = "{$fromEscaped} -{$transitionColor}-> {$toEscaped}: {$transitionEscapedWithStyle}"; } } } From 8b0f7ebd64ff54ecd78f88bb7f45a6a27d7c6915 Mon Sep 17 00:00:00 2001 From: Florian Bogey Date: Tue, 3 May 2022 16:46:45 +0200 Subject: [PATCH 33/65] [Translation] Refresh local translations if the provider has domains --- .../Translation/Command/TranslationPushCommand.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Translation/Command/TranslationPushCommand.php b/src/Symfony/Component/Translation/Command/TranslationPushCommand.php index 973ed5fe12b4d..bf6e8c948b8ed 100644 --- a/src/Symfony/Component/Translation/Command/TranslationPushCommand.php +++ b/src/Symfony/Component/Translation/Command/TranslationPushCommand.php @@ -131,16 +131,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int $force = $input->getOption('force'); $deleteMissing = $input->getOption('delete-missing'); + if (!$domains && $provider instanceof FilteringProvider) { + $domains = $provider->getDomains(); + } + + // Reading local translations must be done after retrieving the domains from the provider + // in order to manage only translations from configured domains $localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths); if (!$domains) { - if ($provider instanceof FilteringProvider) { - $domains = $provider->getDomains(); - } - - if (!$domains) { - $domains = $this->getDomainsFromTranslatorBag($localTranslations); - } + $domains = $this->getDomainsFromTranslatorBag($localTranslations); } if (!$deleteMissing && $force) { From 2fef871bc13a03180d52cf7edf8992a599de6a33 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 6 May 2022 15:16:22 +0200 Subject: [PATCH 34/65] [DoctrineBridge] Treat firstResult === 0 like null --- .../Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php index a96a543a60a12..e53fa3366e953 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php @@ -50,7 +50,7 @@ public function getEntities() */ public function getEntitiesByIds($identifier, array $values) { - if (null !== $this->queryBuilder->getMaxResults() || null !== $this->queryBuilder->getFirstResult()) { + if (null !== $this->queryBuilder->getMaxResults() || 0 < (int) $this->queryBuilder->getFirstResult()) { // an offset or a limit would apply on results including the where clause with submitted id values // that could make invalid choices valid $choices = []; From 923df03df4904ea4e881984113a7dddbafd9d81d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 6 May 2022 17:18:34 +0200 Subject: [PATCH 35/65] [HtmlSanitizer] Bump minimum version of masterminds/html5 --- composer.json | 2 +- src/Symfony/Component/HtmlSanitizer/composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 085cdcdbd9e13..fa7956cde65d5 100644 --- a/composer.json +++ b/composer.json @@ -126,7 +126,7 @@ "doctrine/dbal": "^2.13.1|^3.0", "doctrine/orm": "^2.7.4", "guzzlehttp/promises": "^1.4", - "masterminds/html5": "^2.6", + "masterminds/html5": "^2.7.2", "monolog/monolog": "^1.25.1|^2", "nyholm/psr7": "^1.0", "pda/pheanstalk": "^4.0", diff --git a/src/Symfony/Component/HtmlSanitizer/composer.json b/src/Symfony/Component/HtmlSanitizer/composer.json index bdb15b0a158f7..97a51940143e5 100644 --- a/src/Symfony/Component/HtmlSanitizer/composer.json +++ b/src/Symfony/Component/HtmlSanitizer/composer.json @@ -19,7 +19,7 @@ "php": ">=8.1", "ext-dom": "*", "league/uri": "^6.5", - "masterminds/html5": "^2.4" + "masterminds/html5": "^2.7.2" }, "autoload": { "psr-4": { "Symfony\\Component\\HtmlSanitizer\\": "" }, From 5e1447781caa1088d4137ccb7c74abd89ae5e092 Mon Sep 17 00:00:00 2001 From: BafS Date: Fri, 6 May 2022 22:04:05 +0200 Subject: [PATCH 36/65] [BrowserKit] Use strict comparison when possible --- src/Symfony/Component/BrowserKit/AbstractBrowser.php | 8 ++++---- src/Symfony/Component/BrowserKit/Cookie.php | 2 +- src/Symfony/Component/BrowserKit/CookieJar.php | 2 +- src/Symfony/Component/BrowserKit/History.php | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php index 697e34cb77375..ac25bdf4be261 100644 --- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php @@ -87,7 +87,7 @@ public function isFollowingRedirects(): bool public function setMaxRedirects(int $maxRedirects) { $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects; - $this->followRedirects = -1 != $this->maxRedirects; + $this->followRedirects = -1 !== $this->maxRedirects; } /** @@ -354,7 +354,7 @@ public function request(string $method, string $uri, array $parameters = [], arr $server['HTTP_HOST'] = $this->extractHost($uri); } - $server['HTTPS'] = 'https' == parse_url($uri, \PHP_URL_SCHEME); + $server['HTTPS'] = 'https' === parse_url($uri, \PHP_URL_SCHEME); $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content); @@ -623,7 +623,7 @@ protected function getAbsoluteUri(string $uri): string } // anchor or query string parameters? - if (!$uri || '#' == $uri[0] || '?' == $uri[0]) { + if (!$uri || '#' === $uri[0] || '?' === $uri[0]) { return preg_replace('/[#?].*?$/', '', $currentUri).$uri; } @@ -654,7 +654,7 @@ private function updateServerFromUri(array $server, string $uri): array { $server['HTTP_HOST'] = $this->extractHost($uri); $scheme = parse_url($uri, \PHP_URL_SCHEME); - $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme; + $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' === $scheme; unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']); return $server; diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php index 6525d0b975b38..72301d46ed364 100644 --- a/src/Symfony/Component/BrowserKit/Cookie.php +++ b/src/Symfony/Component/BrowserKit/Cookie.php @@ -157,7 +157,7 @@ public static function fromString(string $cookie, string $url = null): static if ('secure' === strtolower($part)) { // Ignore the secure flag if the original URI is not given or is not HTTPS - if (!$url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) { + if (!$url || !isset($urlParts['scheme']) || 'https' !== $urlParts['scheme']) { continue; } diff --git a/src/Symfony/Component/BrowserKit/CookieJar.php b/src/Symfony/Component/BrowserKit/CookieJar.php index ffcbee6a4329e..cbee8fc6be063 100644 --- a/src/Symfony/Component/BrowserKit/CookieJar.php +++ b/src/Symfony/Component/BrowserKit/CookieJar.php @@ -180,7 +180,7 @@ public function allValues(string $uri, bool $returnsRawValue = false): array } foreach ($namedCookies as $cookie) { - if ($cookie->isSecure() && 'https' != $parts['scheme']) { + if ($cookie->isSecure() && 'https' !== $parts['scheme']) { continue; } diff --git a/src/Symfony/Component/BrowserKit/History.php b/src/Symfony/Component/BrowserKit/History.php index 4dd81f8b2f35d..dc18665a40d48 100644 --- a/src/Symfony/Component/BrowserKit/History.php +++ b/src/Symfony/Component/BrowserKit/History.php @@ -45,7 +45,7 @@ public function add(Request $request) */ public function isEmpty(): bool { - return 0 == \count($this->stack); + return 0 === \count($this->stack); } /** @@ -83,7 +83,7 @@ public function forward(): Request */ public function current(): Request { - if (-1 == $this->position) { + if (-1 === $this->position) { throw new \LogicException('The page history is empty.'); } From 2aa459ac7fd35a6f1432349cb7dd97a3c72eee7d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 5 May 2022 16:46:11 +0200 Subject: [PATCH 37/65] [Contracts/Service] Add generics to ServiceProviderInterface --- .../Contracts/Service/ServiceProviderInterface.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Symfony/Contracts/Service/ServiceProviderInterface.php b/src/Symfony/Contracts/Service/ServiceProviderInterface.php index c60ad0bd4bf26..e78827ca4a2a0 100644 --- a/src/Symfony/Contracts/Service/ServiceProviderInterface.php +++ b/src/Symfony/Contracts/Service/ServiceProviderInterface.php @@ -18,9 +18,23 @@ * * @author Nicolas Grekas * @author Mateusz Sip + * + * @template T of mixed */ interface ServiceProviderInterface extends ContainerInterface { + /** + * {@inheritdoc} + * + * @return T + */ + public function get(string $id): mixed; + + /** + * {@inheritdoc} + */ + public function has(string $id): bool; + /** * Returns an associative array of service types keyed by the identifiers provided by the current container. * From 1c90d84a262ad0801cbc098b277160b15fd44745 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 7 May 2022 11:30:24 +0200 Subject: [PATCH 38/65] Allow flex plugin + remove travis-ci file --- .github/composer-config.json | 3 + .travis.yml | 123 ----------------------------------- 2 files changed, 3 insertions(+), 123 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/composer-config.json b/.github/composer-config.json index 6e17bc21e4582..bf796b6b3d85a 100644 --- a/.github/composer-config.json +++ b/.github/composer-config.json @@ -7,6 +7,9 @@ "symfony/proxy-manager-bridge": "source", "symfony/validator": "source", "*": "dist" + }, + "allow-plugins": { + "symfony/flex": true } } } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2836521932ddf..0000000000000 --- a/.travis.yml +++ /dev/null @@ -1,123 +0,0 @@ -language: php - -dist: bionic - -git: - depth: 1 - -addons: - apt_packages: - - parallel - - zookeeperd - - libzookeeper-mt-dev - -matrix: - include: - - php: 7.3 - fast_finish: true - -cache: - directories: - - .phpunit - - ~/php-ext - -before_install: - - | - # General configuration - set -e - stty cols 120 - sudo sed -i 's/127\.0\.1\.1 localhost/127.0.0.1 localhost/' /etc/hosts - cp .github/composer-config.json "$(composer config home)/config.json" - - nanoseconds () { - local cmd="date" - local format="+%s%N" - local os=$(uname) - if hash gdate > /dev/null 2>&1; then - cmd="gdate" - elif [[ "$os" = Darwin ]]; then - format="+%s000000000" - fi - $cmd -u $format - } - export -f nanoseconds - - # tfold is a helper to create folded reports - tfold () { - local title="$PHP $1" - local fold=$(echo $title | sed -r 's/[^-_A-Za-z0-9]+/./g') - shift - local id=$(printf %08x $(( RANDOM * RANDOM ))) - local start=$(nanoseconds) - echo -e "travis_fold:start:$fold" - echo -e "travis_time:start:$id" - echo -e "\\e[1;34m$title\\e[0m" - - bash -xc "$*" 2>&1 - local ok=$? - local end=$(nanoseconds) - echo -e "\\ntravis_time:end:$id:start=$start,finish=$end,duration=$(($end-$start))" - (exit $ok) && - echo -e "\\e[32mOK\\e[0m $title\\n\\ntravis_fold:end:$fold" || - echo -e "\\e[41mKO\\e[0m $title\\n" - (exit $ok) - } - export -f tfold - - # tpecl is a helper to compile and cache php extensions - tpecl () { - local ext_name=$1 - local ext_so=$2 - local INI=$3 - local input=${4:-yes} - local ext_dir=$(php -r "echo ini_get('extension_dir');") - local ext_cache=~/php-ext/$(basename $ext_dir)/$ext_name - - if [[ -e $ext_cache/$ext_so ]]; then - echo extension = $ext_cache/$ext_so >> $INI - else - rm ~/.pearrc /tmp/pear 2>/dev/null || true - mkdir -p $ext_cache - echo $input | pecl -q install -f $ext_name && - cp $ext_dir/$ext_so $ext_cache - fi - } - export -f tpecl - - - | - # php.ini configuration - for PHP in $TRAVIS_PHP_VERSION $php_extra; do - INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini - echo date.timezone = Europe/Paris >> $INI - echo memory_limit = -1 >> $INI - echo default_socket_timeout = 10 >> $INI - echo session.gc_probability = 0 >> $INI - echo opcache.enable_cli = 1 >> $INI - echo apc.enable_cli = 1 >> $INI - done - find ~/.phpenv -name xdebug.ini -delete - - composer self-update - composer self-update --2 - - - | - # Install extra PHP extensions - for PHP in $TRAVIS_PHP_VERSION $php_extra; do - export PHP=$PHP - phpenv global $PHP - INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini - if [[ $PHP != 8.* ]]; then - tfold ext.zookeeper tpecl zookeeper-0.7.2 zookeeper.so $INI - fi - done - -install: - - export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort) - - export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev - - composer update --no-progress --ansi - - ./phpunit install - -script: - - echo "$COMPONENTS" | parallel --gnu -j +3 "tfold {} ./phpunit --exclude-group tty,benchmark,intl-data {}" - - tfold src/Symfony/Component/Console.tty ./phpunit src/Symfony/Component/Console --group tty - - tfold src/Symfony/Bridge/Twig.tty ./phpunit src/Symfony/Bridge/Twig --group tty From d60423b10c4ccd9bccc8189541783229e5c53655 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 7 May 2022 12:04:08 +0200 Subject: [PATCH 39/65] [Serializer] fix compatibility with psalm v4 --- .../DataCollector/SerializerDataCollector.php | 2 - .../Serializer/Debug/TraceableEncoder.php | 2 - .../Serializer/Debug/TraceableNormalizer.php | 2 - .../Serializer/Debug/TraceableSerializer.php | 42 +++++++------------ 4 files changed, 14 insertions(+), 34 deletions(-) diff --git a/src/Symfony/Component/Serializer/DataCollector/SerializerDataCollector.php b/src/Symfony/Component/Serializer/DataCollector/SerializerDataCollector.php index 57a8aecab02be..cfea563d0119c 100644 --- a/src/Symfony/Component/Serializer/DataCollector/SerializerDataCollector.php +++ b/src/Symfony/Component/Serializer/DataCollector/SerializerDataCollector.php @@ -21,8 +21,6 @@ /** * @author Mathias Arlaud * - * @final - * * @internal */ class SerializerDataCollector extends DataCollector implements LateDataCollectorInterface diff --git a/src/Symfony/Component/Serializer/Debug/TraceableEncoder.php b/src/Symfony/Component/Serializer/Debug/TraceableEncoder.php index cd4a351c6804a..c2927adf914e8 100644 --- a/src/Symfony/Component/Serializer/Debug/TraceableEncoder.php +++ b/src/Symfony/Component/Serializer/Debug/TraceableEncoder.php @@ -23,8 +23,6 @@ * * @author Mathias Arlaud * - * @final - * * @internal */ class TraceableEncoder implements EncoderInterface, DecoderInterface, SerializerAwareInterface diff --git a/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php b/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php index e32475e3cd859..58a055ecfa90d 100644 --- a/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php +++ b/src/Symfony/Component/Serializer/Debug/TraceableNormalizer.php @@ -25,8 +25,6 @@ * * @author Mathias Arlaud * - * @final - * * @internal */ class TraceableNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, NormalizerAwareInterface, DenormalizerAwareInterface, CacheableSupportsMethodInterface diff --git a/src/Symfony/Component/Serializer/Debug/TraceableSerializer.php b/src/Symfony/Component/Serializer/Debug/TraceableSerializer.php index d98d0017b69fc..557bf91286c28 100644 --- a/src/Symfony/Component/Serializer/Debug/TraceableSerializer.php +++ b/src/Symfony/Component/Serializer/Debug/TraceableSerializer.php @@ -23,15 +23,17 @@ * * @author Mathias Arlaud * - * @final * @internal */ class TraceableSerializer implements SerializerInterface, NormalizerInterface, DenormalizerInterface, EncoderInterface, DecoderInterface { public const DEBUG_TRACE_ID = 'debug_trace_id'; + /** + * @param SerializerInterface&NormalizerInterface&DenormalizerInterface&EncoderInterface&DecoderInterface $serializer + */ public function __construct( - private SerializerInterface&NormalizerInterface&DenormalizerInterface&EncoderInterface&DecoderInterface $serializer, + private SerializerInterface $serializer, private SerializerDataCollector $dataCollector, ) { } @@ -39,7 +41,7 @@ public function __construct( /** * {@inheritdoc} */ - final public function serialize(mixed $data, string $format, array $context = []): string + public function serialize(mixed $data, string $format, array $context = []): string { $context[self::DEBUG_TRACE_ID] = $traceId = uniqid(); @@ -55,7 +57,7 @@ final public function serialize(mixed $data, string $format, array $context = [] /** * {@inheritdoc} */ - final public function deserialize(mixed $data, string $type, string $format, array $context = []): mixed + public function deserialize(mixed $data, string $type, string $format, array $context = []): mixed { $context[self::DEBUG_TRACE_ID] = $traceId = uniqid(); @@ -71,7 +73,7 @@ final public function deserialize(mixed $data, string $type, string $format, arr /** * {@inheritdoc} */ - final public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null + public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null { $context[self::DEBUG_TRACE_ID] = $traceId = uniqid(); @@ -87,7 +89,7 @@ final public function normalize(mixed $object, string $format = null, array $con /** * {@inheritdoc} */ - final public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed + public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed { $context[self::DEBUG_TRACE_ID] = $traceId = uniqid(); @@ -103,7 +105,7 @@ final public function denormalize(mixed $data, string $type, string $format = nu /** * {@inheritdoc} */ - final public function encode(mixed $data, string $format, array $context = []): string + public function encode(mixed $data, string $format, array $context = []): string { $context[self::DEBUG_TRACE_ID] = $traceId = uniqid(); @@ -119,7 +121,7 @@ final public function encode(mixed $data, string $format, array $context = []): /** * {@inheritdoc} */ - final public function decode(string $data, string $format, array $context = []): mixed + public function decode(string $data, string $format, array $context = []): mixed { $context[self::DEBUG_TRACE_ID] = $traceId = uniqid(); @@ -134,49 +136,33 @@ final public function decode(string $data, string $format, array $context = []): /** * {@inheritdoc} - * - * @param array $context */ - final public function supportsNormalization(mixed $data, string $format = null /*, array $context = [] */): bool + public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool { - $context = \func_num_args() > 2 ? \func_get_arg(2) : []; - return $this->serializer->supportsNormalization($data, $format, $context); } /** * {@inheritdoc} - * - * @param array $context */ - final public function supportsDenormalization(mixed $data, string $type, string $format = null /*, array $context = [] */): bool + public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool { - $context = \func_num_args() > 3 ? \func_get_arg(3) : []; - return $this->serializer->supportsDenormalization($data, $type, $format, $context); } /** * {@inheritdoc} - * - * @param array $context */ - final public function supportsEncoding(string $format /*, array $context = [] */): bool + public function supportsEncoding(string $format, array $context = []): bool { - $context = \func_num_args() > 1 ? \func_get_arg(1) : []; - return $this->serializer->supportsEncoding($format, $context); } /** * {@inheritdoc} - * - * @param array $context */ - final public function supportsDecoding(string $format /*, array $context = [] */): bool + public function supportsDecoding(string $format, array $context = []): bool { - $context = \func_num_args() > 1 ? \func_get_arg(1) : []; - return $this->serializer->supportsDecoding($format, $context); } } From e824bd9eaee55c803140971e7b39276facfd3e8a Mon Sep 17 00:00:00 2001 From: Massimiliano Arione Date: Sat, 7 May 2022 12:07:55 +0200 Subject: [PATCH 40/65] fix italian translation for validators --- .../Component/Form/Resources/translations/validators.it.xlf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.it.xlf b/src/Symfony/Component/Form/Resources/translations/validators.it.xlf index 8e4665ce1daf5..1a8eee3ac8e26 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.it.xlf @@ -44,15 +44,15 @@ Please choose a valid date interval. - Per favore, scegli a valid date interval. + Per favore, scegli un intervallo di date valido. Please enter a valid date and time. - Per favore, inserisci a valid date and time. + Per favore, inserisci una data e ora valida. Please enter a valid date. - Per favore, inserisci a valid date. + Per favore, inserisci una data valida. Please select a valid file. From 8a266006a6d4c4a509d1d661e7672f54ff9b75cf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 8 May 2022 12:14:36 +0200 Subject: [PATCH 41/65] [Security/Http] fix conflict with older symfony/event-dispatcher --- src/Symfony/Component/Security/Http/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index 21f66b7dc3eed..13bb3a203ffb2 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -32,7 +32,7 @@ "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/event-dispatcher": "<5.4.9", + "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", "symfony/security-bundle": "<5.4", "symfony/security-csrf": "<5.4" }, From d975ca79150a90059c2c6812e817adadcf568d47 Mon Sep 17 00:00:00 2001 From: Sergei Shitikov Date: Sun, 8 May 2022 14:34:08 +0200 Subject: [PATCH 42/65] Suppress unhandled error in some specific use-cases. --- src/Symfony/Component/Console/Command/DumpCompletionCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Command/DumpCompletionCommand.php b/src/Symfony/Component/Console/Command/DumpCompletionCommand.php index f48aa9637c822..dc0cfaef7b589 100644 --- a/src/Symfony/Component/Console/Command/DumpCompletionCommand.php +++ b/src/Symfony/Component/Console/Command/DumpCompletionCommand.php @@ -41,7 +41,7 @@ protected function configure() { $fullCommand = $_SERVER['PHP_SELF']; $commandName = basename($fullCommand); - $fullCommand = realpath($fullCommand) ?: $fullCommand; + $fullCommand = @realpath($fullCommand) ?: $fullCommand; $this ->setHelp(<< Date: Mon, 9 May 2022 22:12:16 +0200 Subject: [PATCH 43/65] Fix CS in Console Table after #45565 --- src/Symfony/Component/Console/Helper/Table.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index a5f34cb140d82..141e7d4908bc6 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -763,18 +763,18 @@ private function calculateColumnsWidth(iterable $groups) continue; } - foreach ($row as $i => $cell) { - if ($cell instanceof TableCell) { - $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); - $textLength = Helper::strlen($textContent); - if ($textLength > 0) { - $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); - foreach ($contentColumns as $position => $content) { - $row[$i + $position] = $content; + foreach ($row as $i => $cell) { + if ($cell instanceof TableCell) { + $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); + $textLength = Helper::strlen($textContent); + if ($textLength > 0) { + $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); + foreach ($contentColumns as $position => $content) { + $row[$i + $position] = $content; + } } } } - } $lengths[] = $this->getCellWidth($row, $column); } From 32ad59f486082ea021d7e40d5351af5ccd1966b5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 9 May 2022 23:05:45 +0200 Subject: [PATCH 44/65] [ErrorHandler] Fix list of tentative return types --- src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php b/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php index 5707a8355bc90..ee403b3d1b078 100644 --- a/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php +++ b/src/Symfony/Component/ErrorHandler/Internal/TentativeTypes.php @@ -1102,6 +1102,8 @@ class TentativeTypes 'isDot' => 'bool', 'rewind' => 'void', 'valid' => 'bool', + 'key' => 'mixed', + 'current' => 'mixed', 'next' => 'void', 'seek' => 'void', ], From 4187d3fdddc3b6299eb245c6614dce50321a28fe Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 8 Apr 2022 23:30:59 +0200 Subject: [PATCH 45/65] [Serializer][PropertyInfo] Fix support for "false" built-in type on PHP 8.2 --- .../Extractor/ReflectionExtractorTest.php | 15 +++++++++++++++ .../Tests/Fixtures/Php82Dummy.php | 19 +++++++++++++++++++ src/Symfony/Component/PropertyInfo/Type.php | 2 ++ .../Normalizer/AbstractObjectNormalizer.php | 2 +- .../Tests/Fixtures/FalseBuiltInDummy.php | 17 +++++++++++++++++ .../Serializer/Tests/SerializerTest.php | 14 ++++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php82Dummy.php create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/FalseBuiltInDummy.php diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 2f2449cd1112d..3f97527b720da 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -272,6 +272,21 @@ public function php81TypesProvider() ]; } + /** + * @dataProvider php82TypesProvider + * @requires PHP 8.2 + */ + public function testExtractPhp82Type($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php82Dummy', $property, [])); + } + + public function php82TypesProvider() + { + yield ['nil', null]; + yield ['false', [new Type(Type::BUILTIN_TYPE_FALSE)]]; + } + /** * @dataProvider defaultValueProvider */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php82Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php82Dummy.php new file mode 100644 index 0000000000000..b830fabf8842a --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php82Dummy.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\Fixtures; + +class Php82Dummy +{ + public null $nil = null; + + public false $false = false; +} diff --git a/src/Symfony/Component/PropertyInfo/Type.php b/src/Symfony/Component/PropertyInfo/Type.php index 582b98d6411f5..06f8fe6c64a55 100644 --- a/src/Symfony/Component/PropertyInfo/Type.php +++ b/src/Symfony/Component/PropertyInfo/Type.php @@ -28,6 +28,7 @@ class Type public const BUILTIN_TYPE_OBJECT = 'object'; public const BUILTIN_TYPE_ARRAY = 'array'; public const BUILTIN_TYPE_NULL = 'null'; + public const BUILTIN_TYPE_FALSE = 'false'; public const BUILTIN_TYPE_CALLABLE = 'callable'; public const BUILTIN_TYPE_ITERABLE = 'iterable'; @@ -45,6 +46,7 @@ class Type self::BUILTIN_TYPE_OBJECT, self::BUILTIN_TYPE_ARRAY, self::BUILTIN_TYPE_CALLABLE, + self::BUILTIN_TYPE_FALSE, self::BUILTIN_TYPE_NULL, self::BUILTIN_TYPE_ITERABLE, ]; diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index e29a7cd18e6b6..ec103f202bd0c 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -483,7 +483,7 @@ private function validateAndDenormalize(string $currentClass, string $attribute, return (float) $data; } - if (('is_'.$builtinType)($data)) { + if ('false' === $builtinType || ('is_'.$builtinType)($data)) { return $data; } } catch (NotNormalizableValueException $e) { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/FalseBuiltInDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/FalseBuiltInDummy.php new file mode 100644 index 0000000000000..0c9d03a0e7298 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/FalseBuiltInDummy.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class FalseBuiltInDummy +{ + public false $false = false; +} diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index a95811a46f8d9..06eda94f53609 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -51,6 +51,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo; +use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy; use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy; use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer; @@ -572,6 +573,19 @@ public function testUnionTypeDeserializable() $this->assertEquals(new DummyUnionType(), $actual, 'Union type denormalization third case failed.'); } + /** + * @requires PHP 8.2 + */ + public function testFalseBuiltInTypes() + { + $extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]); + $serializer = new Serializer([new ObjectNormalizer(null, null, null, $extractor)], ['json' => new JsonEncoder()]); + + $actual = $serializer->deserialize('{"false":false}', FalseBuiltInDummy::class, 'json'); + + $this->assertEquals(new FalseBuiltInDummy(), $actual); + } + private function serializerWithClassDiscriminator() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); From 4beb3208e2c97c9572bad863a820fcb610d4e8c6 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Mon, 9 May 2022 10:53:19 -0400 Subject: [PATCH 46/65] [HttpClient] "debug" is missing if a request failed to even start --- .../HttpClient/DataCollector/HttpClientDataCollector.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php index 6d80d942b3cee..292cdf3945bcf 100644 --- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php +++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php @@ -171,6 +171,10 @@ private function collectOnClient(TraceableHttpClient $client): array private function getCurlCommand(array $trace): ?string { + if (!isset($trace['info']['debug'])) { + return null; + } + $debug = explode("\n", $trace['info']['debug']); $url = $trace['url']; $command = ['curl', '--compressed']; From 793a2641bb27121ba129eb089226e866e2b4cfbd Mon Sep 17 00:00:00 2001 From: Marvin Feldmann Date: Mon, 9 May 2022 20:19:31 +0200 Subject: [PATCH 47/65] [Serializer] Fix JsonSerializableNormalizer ignores circular reference handler in $context --- .../Normalizer/JsonSerializableNormalizer.php | 2 +- ...JsonSerializableCircularReferenceDummy.php | 25 +++++++++++++++++++ .../JsonSerializableNormalizerTest.php | 18 +++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/JsonSerializableCircularReferenceDummy.php diff --git a/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php index c4a8c7a7b5a6d..509e44c0a2f14 100644 --- a/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/JsonSerializableNormalizer.php @@ -27,7 +27,7 @@ class JsonSerializableNormalizer extends AbstractNormalizer public function normalize($object, $format = null, array $context = []) { if ($this->isCircularReference($object, $context)) { - return $this->handleCircularReference($object); + return $this->handleCircularReference($object, $format, $context); } if (!$object instanceof \JsonSerializable) { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/JsonSerializableCircularReferenceDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/JsonSerializableCircularReferenceDummy.php new file mode 100644 index 0000000000000..6dbed8f98d943 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/JsonSerializableCircularReferenceDummy.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Marvin Feldmann + */ +class JsonSerializableCircularReferenceDummy implements \JsonSerializable +{ + public function jsonSerialize(): array + { + return [ + 'me' => $this, + ]; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php index e0222a5fa0b9c..cf6310a980ade 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php @@ -17,14 +17,19 @@ use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\Tests\Fixtures\JsonSerializableCircularReferenceDummy; use Symfony\Component\Serializer\Tests\Fixtures\JsonSerializableDummy; +use Symfony\Component\Serializer\Tests\Normalizer\Features\CircularReferenceTestTrait; /** * @author Fred Cox */ class JsonSerializableNormalizerTest extends TestCase { + use CircularReferenceTestTrait; + /** * @var JsonSerializableNormalizer */ @@ -96,6 +101,19 @@ private function doTestCircularNormalize(bool $legacy = false) $this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy())); } + protected function getNormalizerForCircularReference(array $defaultContext): JsonSerializableNormalizer + { + $normalizer = new JsonSerializableNormalizer(null, null, $defaultContext); + new Serializer([$normalizer]); + + return $normalizer; + } + + protected function getSelfReferencingModel() + { + return new JsonSerializableCircularReferenceDummy(); + } + public function testInvalidDataThrowException() { $this->expectException(InvalidArgumentException::class); From d7ffaf503bab7d02c8789927054a637e370d1538 Mon Sep 17 00:00:00 2001 From: Thomas Nunninger Date: Mon, 24 Jan 2022 12:56:09 +0100 Subject: [PATCH 48/65] [Serializer] Fix AbstractObjectNormalizer not considering pseudo type false --- .../Normalizer/AbstractObjectNormalizer.php | 6 +++++- .../Tests/Normalizer/ObjectNormalizerTest.php | 20 +++++++++++++++++++ .../Component/Serializer/Tests/Php80Dummy.php | 17 ++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Php80Dummy.php diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index ec103f202bd0c..5977d994987c4 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -483,7 +483,11 @@ private function validateAndDenormalize(string $currentClass, string $attribute, return (float) $data; } - if ('false' === $builtinType || ('is_'.$builtinType)($data)) { + if ('false' === $builtinType && false === $data) { + return $data; + } + + if (('is_'.$builtinType)($data)) { return $data; } } catch (NotNormalizableValueException $e) { diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index c6c02bfb8568e..0e4b2cb00c246 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -52,6 +52,7 @@ use Symfony\Component\Serializer\Tests\Normalizer\Features\ObjectToPopulateTestTrait; use Symfony\Component\Serializer\Tests\Normalizer\Features\SkipNullValuesTestTrait; use Symfony\Component\Serializer\Tests\Normalizer\Features\TypeEnforcementTestTrait; +use Symfony\Component\Serializer\Tests\Php80Dummy; /** * @author Kévin Dunglas @@ -873,6 +874,25 @@ public function testExtractAttributesRespectsContext() $this->assertSame(['foo' => 'bar', 'bar' => 'foo'], $normalizer->normalize($data, null, ['include_foo_and_bar' => true])); } + /** + * @requires PHP 8 + */ + public function testDenormalizeFalsePseudoType() + { + // given a serializer that extracts the attribute types of an object via ReflectionExtractor + $propertyTypeExtractor = new PropertyInfoExtractor([], [new ReflectionExtractor()], [], [], []); + $objectNormalizer = new ObjectNormalizer(null, null, null, $propertyTypeExtractor); + + $serializer = new Serializer([$objectNormalizer]); + + // when denormalizing some data into an object where an attribute uses the false pseudo type + /** @var Php80Dummy $object */ + $object = $serializer->denormalize(['canBeFalseOrString' => false], Php80Dummy::class); + + // then the attribute that declared false was filled correctly + $this->assertFalse($object->canBeFalseOrString); + } + public function testAdvancedNameConverter() { $nameConverter = new class() implements AdvancedNameConverterInterface { diff --git a/src/Symfony/Component/Serializer/Tests/Php80Dummy.php b/src/Symfony/Component/Serializer/Tests/Php80Dummy.php new file mode 100644 index 0000000000000..baa75b1246659 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Php80Dummy.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests; + +final class Php80Dummy +{ + public false|string $canBeFalseOrString; +} From 129a2710e6c884bdbed77eb18760904455633ce7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 10 May 2022 11:28:26 +0200 Subject: [PATCH 49/65] Fix typo --- .../HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php index c22a426d7d31e..69bd7445acfd6 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -155,7 +155,7 @@ public function testExceptionInSubRequestsDoesNotMangleOutputBuffers() $this->assertEquals('Foo', ob_get_clean()); } - public function testLocaleAndFormatAreIsKeptInSubrequest() + public function testLocaleAndFormatAreKeptInSubrequest() { $expectedSubRequest = Request::create('/'); $expectedSubRequest->attributes->set('_format', 'foo'); From 7ba3e1af470d21591dabd7c9c451897be4ed15b0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 10 May 2022 16:43:29 +0200 Subject: [PATCH 50/65] [MonologBridge] Fix LevelName being removed in Monolog 3.0 --- .../Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php | 3 +-- src/Symfony/Bridge/Monolog/Handler/MailerHandler.php | 3 +-- src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php | 3 ++- src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php | 3 +-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php index 18e64d23e1584..4c898572ec5a6 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php @@ -17,7 +17,6 @@ use Monolog\Handler\FormattableHandlerTrait; use Monolog\Handler\ProcessableHandlerTrait; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\LogRecord; use Symfony\Component\HttpClient\HttpClient; @@ -61,7 +60,7 @@ class ElasticsearchLogstashHandler extends AbstractHandler */ private \SplObjectStorage $responses; - public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, string|int|Level|LevelName $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, string|int|Level $level = Logger::DEBUG, bool $bubble = true) { if (!interface_exists(HttpClientInterface::class)) { throw new \LogicException(sprintf('The "%s" handler needs an HTTP client. Try running "composer require symfony/http-client".', __CLASS__)); diff --git a/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php b/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php index 25a0e1d04f176..b75accae76a84 100644 --- a/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/MailerHandler.php @@ -16,7 +16,6 @@ use Monolog\Formatter\LineFormatter; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\LogRecord; use Symfony\Component\Mailer\MailerInterface; @@ -34,7 +33,7 @@ class MailerHandler extends AbstractProcessingHandler private MailerInterface $mailer; private \Closure|Email $messageTemplate; - public function __construct(MailerInterface $mailer, callable|Email $messageTemplate, string|int|Level|LevelName $level = Logger::DEBUG, bool $bubble = true) + public function __construct(MailerInterface $mailer, callable|Email $messageTemplate, string|int|Level $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php b/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php index ecffbef254dc8..8576706080d44 100644 --- a/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/NotifierHandler.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Monolog\Handler; use Monolog\Handler\AbstractHandler; +use Monolog\Level; use Monolog\Logger; use Monolog\LogRecord; use Symfony\Component\Notifier\Notification\Notification; @@ -31,7 +32,7 @@ class NotifierHandler extends AbstractHandler private NotifierInterface $notifier; - public function __construct(NotifierInterface $notifier, string|int|Level|LevelName $level = Logger::ERROR, bool $bubble = true) + public function __construct(NotifierInterface $notifier, string|int|Level $level = Logger::ERROR, bool $bubble = true) { $this->notifier = $notifier; diff --git a/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php b/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php index c06828cac0b93..3b2319fb5812a 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ServerLogHandler.php @@ -15,7 +15,6 @@ use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\FormattableHandlerTrait; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\LogRecord; use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter; @@ -77,7 +76,7 @@ trait ServerLogHandlerTrait */ private $socket; - public function __construct(string $host, string|int|Level|LevelName $level = Logger::DEBUG, bool $bubble = true, array $context = []) + public function __construct(string $host, string|int|Level $level = Logger::DEBUG, bool $bubble = true, array $context = []) { parent::__construct($level, $bubble); From 389df989b9597b6b18f76a10317cbbde8eec4262 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 2 Mar 2022 15:35:07 +0100 Subject: [PATCH 51/65] [Security/Http] Ignore invalid URLs found in failure/success paths --- .../Resources/config/security_listeners.xml | 1 + .../DefaultAuthenticationFailureHandler.php | 23 +++++++++++-------- .../DefaultAuthenticationSuccessHandler.php | 13 +++++++++-- ...efaultAuthenticationFailureHandlerTest.php | 20 ++++++++++++++++ ...efaultAuthenticationSuccessHandlerTest.php | 22 ++++++++++++++++++ 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 503bd10bed4ed..3cd2bfabdfbf6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -88,6 +88,7 @@ + diff --git a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php index f57a9ba8db441..46489f6394bd9 100644 --- a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php +++ b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php @@ -70,31 +70,34 @@ public function setOptions(array $options) */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { - if ($failureUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['failure_path_parameter'])) { - $this->options['failure_path'] = $failureUrl; - } + $options = $this->options; + $failureUrl = ParameterBagUtils::getRequestParameterValue($request, $options['failure_path_parameter']); - if (null === $this->options['failure_path']) { - $this->options['failure_path'] = $this->options['login_path']; + if (\is_string($failureUrl) && str_starts_with($failureUrl, '/')) { + $options['failure_path'] = $failureUrl; + } elseif ($this->logger && $failureUrl) { + $this->logger->debug(sprintf('Ignoring query parameter "%s": not a valid URL.', $options['failure_path_parameter'])); } - if ($this->options['failure_forward']) { + $options['failure_path'] ?? $options['failure_path'] = $options['login_path']; + + if ($options['failure_forward']) { if (null !== $this->logger) { - $this->logger->debug('Authentication failure, forward triggered.', ['failure_path' => $this->options['failure_path']]); + $this->logger->debug('Authentication failure, forward triggered.', ['failure_path' => $options['failure_path']]); } - $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']); + $subRequest = $this->httpUtils->createRequest($request, $options['failure_path']); $subRequest->attributes->set(Security::AUTHENTICATION_ERROR, $exception); return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } if (null !== $this->logger) { - $this->logger->debug('Authentication failure, redirect triggered.', ['failure_path' => $this->options['failure_path']]); + $this->logger->debug('Authentication failure, redirect triggered.', ['failure_path' => $options['failure_path']]); } $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); - return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']); + return $this->httpUtils->createRedirectResponse($request, $options['failure_path']); } } diff --git a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php index f0580320f4df6..391fe5369c73b 100644 --- a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php +++ b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Authentication; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\HttpUtils; @@ -29,6 +30,7 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle use TargetPathTrait; protected $httpUtils; + protected $logger; protected $options; protected $providerKey; protected $defaultOptions = [ @@ -42,9 +44,10 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle /** * @param array $options Options for processing a successful authentication attempt */ - public function __construct(HttpUtils $httpUtils, array $options = []) + public function __construct(HttpUtils $httpUtils, array $options = [], LoggerInterface $logger = null) { $this->httpUtils = $httpUtils; + $this->logger = $logger; $this->setOptions($options); } @@ -102,10 +105,16 @@ protected function determineTargetUrl(Request $request) return $this->options['default_target_path']; } - if ($targetUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['target_path_parameter'])) { + $targetUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['target_path_parameter']); + + if (\is_string($targetUrl) && str_starts_with($targetUrl, '/')) { return $targetUrl; } + if ($this->logger && $targetUrl) { + $this->logger->debug(sprintf('Ignoring query parameter "%s": not a valid URL.', $this->options['target_path_parameter'])); + } + if (null !== $this->providerKey && $targetUrl = $this->getTargetPath($request->getSession(), $this->providerKey)) { $this->removeTargetPath($request->getSession(), $this->providerKey); diff --git a/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php index d95027560b706..22a2b9277bbbd 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php @@ -187,6 +187,26 @@ public function testFailurePathParameterCanBeOverwritten() $handler->onAuthenticationFailure($this->request, $this->exception); } + public function testFailurePathFromRequestWithInvalidUrl() + { + $options = ['failure_path_parameter' => '_my_failure_path']; + + $this->request->expects($this->once()) + ->method('get')->with('_my_failure_path') + ->willReturn('some_route_name'); + + $this->logger->expects($this->exactly(2)) + ->method('debug') + ->withConsecutive( + ['Ignoring query parameter "_my_failure_path": not a valid URL.'], + ['Authentication failure, redirect triggered.', ['failure_path' => '/login']] + ); + + $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger); + + $handler->onAuthenticationFailure($this->request, $this->exception); + } + private function getRequest() { $request = $this->createMock(Request::class); diff --git a/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php index f168e415c0e69..5f05248911f91 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Http\Tests\Authentication; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -113,4 +114,25 @@ public function getRequestRedirections() ], ]; } + + public function testTargetPathFromRequestWithInvalidUrl() + { + $httpUtils = $this->createMock(HttpUtils::class); + $options = ['target_path_parameter' => '_my_target_path']; + $token = $this->createMock(TokenInterface::class); + + $request = $this->createMock(Request::class); + $request->expects($this->once()) + ->method('get')->with('_my_target_path') + ->willReturn('some_route_name'); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once()) + ->method('debug') + ->with('Ignoring query parameter "_my_target_path": not a valid URL.'); + + $handler = new DefaultAuthenticationSuccessHandler($httpUtils, $options, $logger); + + $handler->onAuthenticationSuccess($request, $token); + } } From 2b28df39a8b47962a26b649b1f3a348714bb51f0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 11 May 2022 14:12:29 +0200 Subject: [PATCH 52/65] Update sponsors of components v6.1 --- src/Symfony/Component/Console/README.md | 16 ---------------- src/Symfony/Component/HttpClient/README.md | 14 -------------- src/Symfony/Component/HttpFoundation/README.md | 14 -------------- src/Symfony/Component/HttpKernel/README.md | 16 ---------------- src/Symfony/Component/Messenger/README.md | 2 +- src/Symfony/Component/Notifier/README.md | 2 +- src/Symfony/Component/Process/README.md | 2 +- src/Symfony/Component/Security/Core/README.md | 2 +- src/Symfony/Component/Security/Csrf/README.md | 2 +- src/Symfony/Component/Security/Http/README.md | 2 +- .../Translation/Bridge/Crowdin/README.md | 2 +- .../Translation/Bridge/Lokalise/README.md | 14 -------------- src/Symfony/Component/Translation/README.md | 8 +++----- 13 files changed, 10 insertions(+), 86 deletions(-) diff --git a/src/Symfony/Component/Console/README.md b/src/Symfony/Component/Console/README.md index c4c129989cbd9..c89b4a1a2066b 100644 --- a/src/Symfony/Component/Console/README.md +++ b/src/Symfony/Component/Console/README.md @@ -4,18 +4,6 @@ Console Component The Console component eases the creation of beautiful and testable command line interfaces. -Sponsor -------- - -The Console component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2]. - -Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and -fix your projects. We provide a wide range of professional services including development, -consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps. -We are a worker cooperative! - -Help Symfony by [sponsoring][3] its development! - Resources --------- @@ -30,7 +18,3 @@ Credits `Resources/bin/hiddeninput.exe` is a third party binary provided within this component. Find sources and license at https://github.com/Seldaek/hidden-input. - -[1]: https://symfony.com/backers -[2]: https://les-tilleuls.coop -[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/HttpClient/README.md b/src/Symfony/Component/HttpClient/README.md index 0c55ccc118876..214489b7e7f76 100644 --- a/src/Symfony/Component/HttpClient/README.md +++ b/src/Symfony/Component/HttpClient/README.md @@ -3,16 +3,6 @@ HttpClient component The HttpClient component provides powerful methods to fetch HTTP resources synchronously or asynchronously. -Sponsor -------- - -The Httpclient component for Symfony 5.4/6.0 is [backed][1] by [Klaxoon][2]. - -Klaxoon is a platform that empowers organizations to run effective and -productive workshops easily in a hybrid environment. Anytime, Anywhere. - -Help Symfony by [sponsoring][3] its development! - Resources --------- @@ -21,7 +11,3 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) - -[1]: https://symfony.com/backers -[2]: https://klaxoon.com -[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/HttpFoundation/README.md b/src/Symfony/Component/HttpFoundation/README.md index 424f2c4f0b848..5cf9007444456 100644 --- a/src/Symfony/Component/HttpFoundation/README.md +++ b/src/Symfony/Component/HttpFoundation/README.md @@ -4,16 +4,6 @@ HttpFoundation Component The HttpFoundation component defines an object-oriented layer for the HTTP specification. -Sponsor -------- - -The HttpFoundation component for Symfony 5.4/6.0 is [backed][1] by [Laravel][2]. - -Laravel is a PHP web development framework that is passionate about maximum developer -happiness. Laravel is built using a variety of bespoke and Symfony based components. - -Help Symfony by [sponsoring][3] its development! - Resources --------- @@ -22,7 +12,3 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) - -[1]: https://symfony.com/backers -[2]: https://laravel.com/ -[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/HttpKernel/README.md b/src/Symfony/Component/HttpKernel/README.md index ca504178278c4..18d15f5ad835f 100644 --- a/src/Symfony/Component/HttpKernel/README.md +++ b/src/Symfony/Component/HttpKernel/README.md @@ -5,18 +5,6 @@ The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher component. It's flexible enough to create full-stack frameworks, micro-frameworks or advanced CMS systems like Drupal. -Sponsor -------- - -The HttpKernel component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2]. - -Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and -fix your projects. We provide a wide range of professional services including development, -consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps. -We are a worker cooperative! - -Help Symfony by [sponsoring][3] its development! - Resources --------- @@ -25,7 +13,3 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) - -[1]: https://symfony.com/backers -[2]: https://les-tilleuls.coop -[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Messenger/README.md b/src/Symfony/Component/Messenger/README.md index 644269c7f34a1..02fd6b5081e76 100644 --- a/src/Symfony/Component/Messenger/README.md +++ b/src/Symfony/Component/Messenger/README.md @@ -7,7 +7,7 @@ other applications or via message queues. Sponsor ------- -The Messenger component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2]. +The Messenger component for Symfony 6.1 is [backed][1] by [SensioLabs][2]. As the creator of Symfony, SensioLabs supports companies using Symfony, with an offering encompassing consultancy, expertise, services, training, and technical diff --git a/src/Symfony/Component/Notifier/README.md b/src/Symfony/Component/Notifier/README.md index 4a9631653841e..2e0e70e1a4995 100644 --- a/src/Symfony/Component/Notifier/README.md +++ b/src/Symfony/Component/Notifier/README.md @@ -6,7 +6,7 @@ The Notifier component sends notifications via one or more channels (email, SMS, Sponsor ------- -The Notifier component for Symfony 5.4/6.0 is [backed][1] by [Mercure.rocks][2]. +The Notifier component for Symfony 6.1 is [backed][1] by [Mercure.rocks][2]. Create real-time experiences in minutes! Mercure.rocks provides a realtime API service that is tightly integrated with Symfony: create UIs that update in live with UX Turbo, diff --git a/src/Symfony/Component/Process/README.md b/src/Symfony/Component/Process/README.md index 8777de4a65c52..a371d286b274f 100644 --- a/src/Symfony/Component/Process/README.md +++ b/src/Symfony/Component/Process/README.md @@ -6,7 +6,7 @@ The Process component executes commands in sub-processes. Sponsor ------- -The Process component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2]. +The Process component for Symfony 6.1 is [backed][1] by [SensioLabs][2]. As the creator of Symfony, SensioLabs supports companies using Symfony, with an offering encompassing consultancy, expertise, services, training, and technical diff --git a/src/Symfony/Component/Security/Core/README.md b/src/Symfony/Component/Security/Core/README.md index 6e31770c4910f..00e74cbada342 100644 --- a/src/Symfony/Component/Security/Core/README.md +++ b/src/Symfony/Component/Security/Core/README.md @@ -41,7 +41,7 @@ if (!$accessDecisionManager->decide($token, ['ROLE_ADMIN'])) { Sponsor ------- -The Security component for Symfony 5.4/6.0 is [backed][1] by [SymfonyCasts][2]. +The Security component for Symfony 6.1 is [backed][1] by [SymfonyCasts][2]. Learn Symfony faster by watching real projects being built and actively coding along with them. SymfonyCasts bridges that learning gap, bringing you video diff --git a/src/Symfony/Component/Security/Csrf/README.md b/src/Symfony/Component/Security/Csrf/README.md index a27d877284343..65c63c19cb741 100644 --- a/src/Symfony/Component/Security/Csrf/README.md +++ b/src/Symfony/Component/Security/Csrf/README.md @@ -7,7 +7,7 @@ The Security CSRF (cross-site request forgery) component provides a class Sponsor ------- -The Security component for Symfony 5.4/6.0 is [backed][1] by [SymfonyCasts][2]. +The Security component for Symfony 6.1 is [backed][1] by [SymfonyCasts][2]. Learn Symfony faster by watching real projects being built and actively coding along with them. SymfonyCasts bridges that learning gap, bringing you video diff --git a/src/Symfony/Component/Security/Http/README.md b/src/Symfony/Component/Security/Http/README.md index 91a7583373e68..be8982a946d46 100644 --- a/src/Symfony/Component/Security/Http/README.md +++ b/src/Symfony/Component/Security/Http/README.md @@ -15,7 +15,7 @@ $ composer require symfony/security-http Sponsor ------- -The Security component for Symfony 5.4/6.0 is [backed][1] by [SymfonyCasts][2]. +The Security component for Symfony 6.1 is [backed][1] by [SymfonyCasts][2]. Learn Symfony faster by watching real projects being built and actively coding along with them. SymfonyCasts bridges that learning gap, bringing you video diff --git a/src/Symfony/Component/Translation/Bridge/Crowdin/README.md b/src/Symfony/Component/Translation/Bridge/Crowdin/README.md index a1b8a1a6cc46c..4e33501a6bd99 100644 --- a/src/Symfony/Component/Translation/Bridge/Crowdin/README.md +++ b/src/Symfony/Component/Translation/Bridge/Crowdin/README.md @@ -23,7 +23,7 @@ where: Sponsor ------- -This bridge for Symfony 5.4/6.0 is [backed][1] by [Crowdin][2]. +This bridge for Symfony 6.1 is [backed][1] by [Crowdin][2]. Crowdin is a cloud-based localization management software helping teams to go global and stay agile. diff --git a/src/Symfony/Component/Translation/Bridge/Lokalise/README.md b/src/Symfony/Component/Translation/Bridge/Lokalise/README.md index e91ac094f3cab..64e6cd0de7800 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/README.md +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/README.md @@ -19,16 +19,6 @@ Go to the Project Settings in Lokalise to find the Project ID. [Generate an API key on Lokalise](https://app.lokalise.com/api2docs/curl/#resource-authentication) -Sponsor -------- - -This bridge for Symfony 5.4/6.0 is [backed][1] by [Lokalise][2]. - -Lokalise is a continuous localization and translation management platform. It integrates -into your development workflow so you can ship localized products, faster. - -Help Symfony by [sponsoring][3] its development! - Resources --------- @@ -36,7 +26,3 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) - -[1]: https://symfony.com/backers -[2]: https://lokalise.com -[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Translation/README.md b/src/Symfony/Component/Translation/README.md index adda9a5b21e55..4fedd6a2517d8 100644 --- a/src/Symfony/Component/Translation/README.md +++ b/src/Symfony/Component/Translation/README.md @@ -26,12 +26,11 @@ echo $translator->trans('Hello World!'); // outputs « Bonjour ! » Sponsor ------- -The Translation component for Symfony 5.4/6.0 is [backed][1] by: +The Translation component for Symfony 6.1 is [backed][1] by: * [Crowdin][2], a cloud-based localization management software helping teams to go global and stay agile. - * [Lokalise][3], a continuous localization and translation management platform that integrates into your development workflow so you can ship localized products, faster. -Help Symfony by [sponsoring][4] its development! +Help Symfony by [sponsoring][3] its development! Resources --------- @@ -44,5 +43,4 @@ Resources [1]: https://symfony.com/backers [2]: https://crowdin.com -[3]: https://lokalise.com -[4]: https://symfony.com/sponsor +[3]: https://symfony.com/sponsor From deae8b3eb5b5b94a68c769727e75ce6f0e5126b2 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Wed, 11 May 2022 15:13:50 +0000 Subject: [PATCH 53/65] Allow ErrorHandler ^5.0 to be used in HttpKernel --- 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 c2758e45ae8cc..8111f72b46b2f 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=7.1.3", - "symfony/error-handler": "^4.4", + "symfony/error-handler": "^4.4|^5.0", "symfony/event-dispatcher": "^4.4", "symfony/http-client-contracts": "^1.1|^2", "symfony/http-foundation": "^4.4.30|^5.3.7", From 50286625ca09f3f9a7dd2d1ec63741303cb9092e Mon Sep 17 00:00:00 2001 From: Tom Van Looy Date: Wed, 11 May 2022 16:27:22 +0200 Subject: [PATCH 54/65] Fix division by zero --- .../Security/Csrf/CsrfTokenManager.php | 3 +++ .../Csrf/Tests/CsrfTokenManagerTest.php | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php b/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php index 3e7454e793d28..14c05592d3241 100644 --- a/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php +++ b/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php @@ -134,6 +134,9 @@ private function derandomize(string $value): string return $value; } $key = base64_decode(strtr($parts[1], '-_', '+/')); + if ('' === $key || false === $key) { + return $value; + } $value = base64_decode(strtr($parts[2], '-_', '+/')); return $this->xor($value, $key); diff --git a/src/Symfony/Component/Security/Csrf/Tests/CsrfTokenManagerTest.php b/src/Symfony/Component/Security/Csrf/Tests/CsrfTokenManagerTest.php index d654bbf195fa4..bd911987f1f2d 100644 --- a/src/Symfony/Component/Security/Csrf/Tests/CsrfTokenManagerTest.php +++ b/src/Symfony/Component/Security/Csrf/Tests/CsrfTokenManagerTest.php @@ -193,6 +193,26 @@ public function testNonExistingTokenIsNotValid($namespace, $manager, $storage) $this->assertFalse($manager->isTokenValid(new CsrfToken('token_id', 'FOOBAR'))); } + public function testTokenShouldNotTriggerDivisionByZero() + { + [$generator, $storage] = $this->getGeneratorAndStorage(); + $manager = new CsrfTokenManager($generator, $storage); + + // Scenario: the token that was returned is abc.def.ghi, and gets modified in the browser to abc..ghi + + $storage->expects($this->once()) + ->method('hasToken') + ->with('https-token_id') + ->willReturn(true); + + $storage->expects($this->once()) + ->method('getToken') + ->with('https-token_id') + ->willReturn('def'); + + $this->assertFalse($manager->isTokenValid(new CsrfToken('token_id', 'abc..ghi'))); + } + /** * @dataProvider getManagerGeneratorAndStorage */ From 124b3741a2cb9447814e5e1090401bff1ce2a746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 12 May 2022 10:58:13 +0200 Subject: [PATCH 55/65] [WebProfilerBundle] Fix spelling of curl the cli is spelled `curl` the project is spelled `cURL` Some reference: * https://curl.se/ * https://github.com/curl/curl * https://twitter.com/bagder/status/1524674023224922112 --- .../Resources/views/Collector/http_client.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig index b6d925dc3ba27..f409a2dc03fde 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/http_client.html.twig @@ -96,7 +96,7 @@ {% endif %} {% if trace.curlCommand is not null %} - + {% endif %} From 8ffc0152a326a41c36ead89a371d9fc1624bcd62 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 13 May 2022 12:06:30 +0200 Subject: [PATCH 56/65] Fix aliases handling in command name completion --- src/Symfony/Component/Console/Application.php | 15 ++++++++++++--- .../Component/Console/Command/CompleteCommand.php | 3 ++- .../Console/Tests/Command/CompleteCommandTest.php | 10 +++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 3decfc04bb338..366d61204f710 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -363,9 +363,18 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && 'command' === $input->getCompletionName() ) { - $suggestions->suggestValues(array_filter(array_map(function (Command $command) { - return $command->isHidden() ? null : $command->getName(); - }, $this->all()))); + $commandNames = []; + foreach ($this->all() as $name => $command) { + // skip hidden commands and aliased commands as they already get added below + if ($command->isHidden() || $command->getName() !== $name) { + continue; + } + $commandNames[] = $command->getName(); + foreach ($command->getAliases() as $name) { + $commandNames[] = $name; + } + } + $suggestions->suggestValues(array_filter($commandNames)); return; } diff --git a/src/Symfony/Component/Console/Command/CompleteCommand.php b/src/Symfony/Component/Console/Command/CompleteCommand.php index 97357d6737ed3..a94021ce46a27 100644 --- a/src/Symfony/Component/Console/Command/CompleteCommand.php +++ b/src/Symfony/Component/Console/Command/CompleteCommand.php @@ -105,11 +105,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int } elseif ( $completionInput->mustSuggestArgumentValuesFor('command') && $command->getName() !== $completionInput->getCompletionValue() + && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true) ) { $this->log(' No command found, completing using the Application class.'); // expand shortcut names ("cache:cl") into their full name ("cache:clear") - $suggestions->suggestValue($command->getName()); + $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases()))); } else { $command->mergeApplicationDefinition(); $completionInput->bind($command->getDefinition()); diff --git a/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php b/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php index 189928897cc7c..f3ffe7b502dcb 100644 --- a/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php @@ -102,9 +102,10 @@ public function testCompleteCommandName(array $input, array $suggestions) public function provideCompleteCommandNameInputs() { - yield 'empty' => [['bin/console'], ['help', 'list', 'completion', 'hello']]; - yield 'partial' => [['bin/console', 'he'], ['help', 'list', 'completion', 'hello']]; - yield 'complete-shortcut-name' => [['bin/console', 'hell'], ['hello']]; + yield 'empty' => [['bin/console'], ['help', 'list', 'completion', 'hello', 'ahoy']]; + yield 'partial' => [['bin/console', 'he'], ['help', 'list', 'completion', 'hello', 'ahoy']]; + yield 'complete-shortcut-name' => [['bin/console', 'hell'], ['hello', 'ahoy']]; + yield 'complete-aliases' => [['bin/console', 'ah'], ['hello', 'ahoy']]; } /** @@ -120,6 +121,8 @@ public function provideCompleteCommandInputDefinitionInputs() { yield 'definition' => [['bin/console', 'hello', '-'], ['--help', '--quiet', '--verbose', '--version', '--ansi', '--no-interaction']]; yield 'custom' => [['bin/console', 'hello'], ['Fabien', 'Robin', 'Wouter']]; + yield 'definition-aliased' => [['bin/console', 'ahoy', '-'], ['--help', '--quiet', '--verbose', '--version', '--ansi', '--no-interaction']]; + yield 'custom-aliased' => [['bin/console', 'ahoy'], ['Fabien', 'Robin', 'Wouter']]; } private function execute(array $input) @@ -134,6 +137,7 @@ class CompleteCommandTest_HelloCommand extends Command public function configure(): void { $this->setName('hello') + ->setAliases(['ahoy']) ->addArgument('name', InputArgument::REQUIRED) ; } From 0ea89e574f23f35c27d66b5fa6ae310846f819b0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 12 May 2022 18:47:43 +0200 Subject: [PATCH 57/65] [FrameworkBundle][TwigBundle][Form] Add Twig filter, form-type extension and improve service definitions for HtmlSanitizer --- .../Twig/Extension/HtmlSanitizerExtension.php | 40 +++++++++++ .../Extension/HtmlSanitizerExtensionTest.php | 52 +++++++++++++++ .../Bridge/Twig/UndefinedCallableHandler.php | 2 + src/Symfony/Bridge/Twig/composer.json | 2 + .../Compiler/UnusedTagsPass.php | 1 + .../DependencyInjection/Configuration.php | 4 -- .../FrameworkExtension.php | 15 +++-- .../FrameworkBundle/Resources/config/form.php | 6 ++ .../Resources/config/html_sanitizer.php | 9 ++- .../Resources/config/schema/symfony-1.0.xsd | 1 - .../DependencyInjection/ConfigurationTest.php | 1 - .../Fixtures/php/html_sanitizer.php | 3 +- .../Fixtures/xml/html_sanitizer.xml | 4 +- .../Fixtures/yml/html_sanitizer.yml | 3 +- .../FrameworkExtensionTest.php | 37 ++++------- .../DependencyInjection/TwigExtension.php | 5 ++ .../TwigBundle/Resources/config/twig.php | 4 ++ .../HtmlSanitizer/HtmlSanitizerExtension.php | 36 ++++++++++ .../Type/TextTypeHtmlSanitizerExtension.php | 66 +++++++++++++++++++ .../TextTypeHtmlSanitizerExtensionTest.php | 63 ++++++++++++++++++ src/Symfony/Component/Form/composer.json | 1 + 21 files changed, 312 insertions(+), 43 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php create mode 100644 src/Symfony/Bridge/Twig/Tests/Extension/HtmlSanitizerExtensionTest.php create mode 100644 src/Symfony/Component/Form/Extension/HtmlSanitizer/HtmlSanitizerExtension.php create mode 100644 src/Symfony/Component/Form/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtension.php create mode 100644 src/Symfony/Component/Form/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php diff --git a/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php b/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php new file mode 100644 index 0000000000000..bec5ceb94e34e --- /dev/null +++ b/src/Symfony/Bridge/Twig/Extension/HtmlSanitizerExtension.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Psr\Container\ContainerInterface; +use Twig\Extension\AbstractExtension; +use Twig\TwigFilter; + +/** + * @author Titouan Galopin + */ +final class HtmlSanitizerExtension extends AbstractExtension +{ + public function __construct( + private ContainerInterface $sanitizers, + private string $defaultSanitizer = 'default', + ) { + } + + public function getFilters(): array + { + return [ + new TwigFilter('sanitize_html', $this->sanitize(...), ['is_safe' => ['html']]), + ]; + } + + public function sanitize(string $html, string $sanitizer = null): string + { + return $this->sanitizers->get($sanitizer ?? $this->defaultSanitizer)->sanitize($html); + } +} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HtmlSanitizerExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HtmlSanitizerExtensionTest.php new file mode 100644 index 0000000000000..23755d0317be2 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HtmlSanitizerExtensionTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Twig\Extension\HtmlSanitizerExtension; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; +use Twig\Environment; +use Twig\Loader\ArrayLoader; + +class HtmlSanitizerExtensionTest extends TestCase +{ + public function testSanitizeHtml() + { + $loader = new ArrayLoader([ + 'foo' => '{{ "foobar"|sanitize_html }}', + 'bar' => '{{ "foobar"|sanitize_html("bar") }}', + ]); + + $twig = new Environment($loader, ['debug' => true, 'cache' => false, 'autoescape' => 'html', 'optimizations' => 0]); + + $fooSanitizer = $this->createMock(HtmlSanitizerInterface::class); + $fooSanitizer->expects($this->once()) + ->method('sanitize') + ->with('foobar') + ->willReturn('foo'); + + $barSanitizer = $this->createMock(HtmlSanitizerInterface::class); + $barSanitizer->expects($this->once()) + ->method('sanitize') + ->with('foobar') + ->willReturn('bar'); + + $twig->addExtension(new HtmlSanitizerExtension(new ServiceLocator([ + 'foo' => fn () => $fooSanitizer, + 'bar' => fn () => $barSanitizer, + ]), 'foo')); + + $this->assertSame('foo', $twig->render('foo')); + $this->assertSame('bar', $twig->render('bar')); + } +} diff --git a/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php b/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php index 30dd92ff2ff3b..472330a859c6e 100644 --- a/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php +++ b/src/Symfony/Bridge/Twig/UndefinedCallableHandler.php @@ -24,6 +24,7 @@ class UndefinedCallableHandler private const FILTER_COMPONENTS = [ 'humanize' => 'form', 'trans' => 'translation', + 'sanitize_html' => 'html-sanitizer', 'yaml_encode' => 'yaml', 'yaml_dump' => 'yaml', ]; @@ -61,6 +62,7 @@ class UndefinedCallableHandler ]; private const FULL_STACK_ENABLE = [ + 'html-sanitizer' => 'enable "framework.html_sanitizer"', 'form' => 'enable "framework.form"', 'security-core' => 'add the "SecurityBundle"', 'security-http' => 'add the "SecurityBundle"', diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 46cea3b115b4d..f182dfa406417 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -28,6 +28,7 @@ "symfony/dependency-injection": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "symfony/form": "^6.1", + "symfony/html-sanitizer": "^6.1", "symfony/http-foundation": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", @@ -65,6 +66,7 @@ "symfony/finder": "", "symfony/asset": "For using the AssetExtension", "symfony/form": "For using the FormExtension", + "symfony/html-sanitizer": "For using the HtmlSanitizerExtension", "symfony/http-kernel": "For using the HttpKernelExtension", "symfony/routing": "For using the RoutingExtension", "symfony/translation": "For using the TranslationExtension", diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index 558111e6a5d43..c1d18f91f7dff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -49,6 +49,7 @@ class UnusedTagsPass implements CompilerPassInterface 'form.type', 'form.type_extension', 'form.type_guesser', + 'html_sanitizer', 'http_client.client', 'kernel.cache_clearer', 'kernel.cache_warmer', diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 92f7cbc9a93a0..947f182eef1f4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -2129,10 +2129,6 @@ private function addHtmlSanitizerSection(ArrayNodeDefinition $rootNode, callable ->{$enableIfStandalone('symfony/html-sanitizer', HtmlSanitizerInterface::class)}() ->fixXmlConfig('sanitizer') ->children() - ->scalarNode('default') - ->defaultNull() - ->info('Default sanitizer to use when injecting without named binding.') - ->end() ->arrayNode('sanitizers') ->useAttributeAsKey('name') ->arrayPrototype() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index d21de7da9d1f9..07f15e9b28b52 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -69,6 +69,7 @@ use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\Finder\Finder; use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; +use Symfony\Component\Form\Extension\HtmlSanitizer\Type\TextTypeHtmlSanitizerExtension; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeGuesserInterface; @@ -485,6 +486,9 @@ public function load(array $configs, ContainerBuilder $container) $container->removeDefinition('form.type_extension.form.validator'); $container->removeDefinition('form.type_guesser.validator'); } + if (!$this->isConfigEnabled($container, $config['html_sanitizer']) || !class_exists(TextTypeHtmlSanitizerExtension::class)) { + $container->removeDefinition('form.type_extension.form.html_sanitizer'); + } } else { $container->removeDefinition('console.command.form_debug'); } @@ -2740,13 +2744,14 @@ private function registerHtmlSanitizerConfiguration(array $config, ContainerBuil // Create the sanitizer and link its config $sanitizerId = 'html_sanitizer.sanitizer.'.$sanitizerName; - $container->register($sanitizerId, HtmlSanitizer::class)->addArgument(new Reference($configId)); + $container->register($sanitizerId, HtmlSanitizer::class) + ->addTag('html_sanitizer', ['sanitizer' => $sanitizerName]) + ->addArgument(new Reference($configId)); - $container->registerAliasForArgument($sanitizerId, HtmlSanitizerInterface::class, $sanitizerName); + if ('default' !== $sanitizerName) { + $container->registerAliasForArgument($sanitizerId, HtmlSanitizerInterface::class, $sanitizerName); + } } - - $default = $config['default'] ? 'html_sanitizer.sanitizer.'.$config['default'] : 'html_sanitizer'; - $container->setAlias(HtmlSanitizerInterface::class, new Reference($default)); } private function resolveTrustedHeaders(array $headers): int diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php index 75bfb7eb651af..3c936a284b325 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.php @@ -19,8 +19,10 @@ use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension; use Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension; +use Symfony\Component\Form\Extension\HtmlSanitizer\Type\TextTypeHtmlSanitizerExtension; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\Extension\HttpFoundation\Type\FormTypeHttpFoundationExtension; use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension; @@ -113,6 +115,10 @@ ->args([service('translator')->ignoreOnInvalid()]) ->tag('form.type_extension', ['extended-type' => FormType::class]) + ->set('form.type_extension.form.html_sanitizer', TextTypeHtmlSanitizerExtension::class) + ->args([tagged_locator('html_sanitizer', 'sanitizer')]) + ->tag('form.type_extension', ['extended-type' => TextType::class]) + ->set('form.type_extension.form.http_foundation', FormTypeHttpFoundationExtension::class) ->args([service('form.type_extension.form.request_handler')]) ->tag('form.type_extension') diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php index 558188d18915f..ba87eda1a3357 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/html_sanitizer.php @@ -13,13 +13,18 @@ use Symfony\Component\HtmlSanitizer\HtmlSanitizer; use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; return static function (ContainerConfigurator $container) { $container->services() - ->set('html_sanitizer.config', HtmlSanitizerConfig::class) + ->set('html_sanitizer.config.default', HtmlSanitizerConfig::class) ->call('allowSafeElements') - ->set('html_sanitizer', HtmlSanitizer::class) + ->set('html_sanitizer.sanitizer.default', HtmlSanitizer::class) ->args([service('html_sanitizer.config')]) + ->tag('html_sanitizer', ['name' => 'default']) + + ->alias('html_sanitizer', 'html_sanitizer.sanitizer.default') + ->alias(HtmlSanitizerInterface::class, 'html_sanitizer') ; }; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index c2bf87f9daf45..2baa0a33a3ebc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -826,7 +826,6 @@ - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index cc567b14829eb..e5b1a947e3313 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -652,7 +652,6 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor ], 'html_sanitizer' => [ 'enabled' => !class_exists(FullStack::class) && class_exists(HtmlSanitizer::class), - 'default' => null, 'sanitizers' => [], ], 'exceptions' => [], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php index 687f05a3ffa2b..de6a0a1ae34bc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php @@ -3,9 +3,8 @@ $container->loadFromExtension('framework', [ 'http_method_override' => false, 'html_sanitizer' => [ - 'default' => 'my.sanitizer', 'sanitizers' => [ - 'my.sanitizer' => [ + 'default' => [ 'allow_safe_elements' => true, 'allow_all_static_elements' => true, 'allow_elements' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml index 77a47724541bf..f2b11618d18e2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml @@ -6,8 +6,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - + createContainerFromFile('html_sanitizer'); // html_sanitizer service - $this->assertTrue($container->hasDefinition('html_sanitizer'), '->registerHtmlSanitizerConfiguration() loads html_sanitizer.php'); - $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer')->getClass()); - $this->assertCount(1, $args = $container->getDefinition('html_sanitizer')->getArguments()); - $this->assertSame('html_sanitizer.config', (string) $args[0]); - - // html_sanitizer.config service - $this->assertTrue($container->hasDefinition('html_sanitizer.config'), '->registerHtmlSanitizerConfiguration() loads html_sanitizer.php'); - $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config')->getClass()); - $this->assertCount(1, $calls = $container->getDefinition('html_sanitizer.config')->getMethodCalls()); - $this->assertSame(['allowSafeElements', []], $calls[0]); - - // my.sanitizer - $this->assertTrue($container->hasDefinition('html_sanitizer.sanitizer.my.sanitizer'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); - $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer.sanitizer.my.sanitizer')->getClass()); - $this->assertCount(1, $args = $container->getDefinition('html_sanitizer.sanitizer.my.sanitizer')->getArguments()); - $this->assertSame('html_sanitizer.config.my.sanitizer', (string) $args[0]); - - // my.sanitizer config - $this->assertTrue($container->hasDefinition('html_sanitizer.config.my.sanitizer'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); - $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.my.sanitizer')->getClass()); - $this->assertCount(23, $calls = $container->getDefinition('html_sanitizer.config.my.sanitizer')->getMethodCalls()); + $this->assertTrue($container->hasAlias('html_sanitizer'), '->registerHtmlSanitizerConfiguration() loads html_sanitizer.php'); + $this->assertSame('html_sanitizer.sanitizer.default', (string) $container->getAlias('html_sanitizer')); + $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer.sanitizer.default')->getClass()); + $this->assertCount(1, $args = $container->getDefinition('html_sanitizer.sanitizer.default')->getArguments()); + $this->assertSame('html_sanitizer.config.default', (string) $args[0]); + + // config + $this->assertTrue($container->hasDefinition('html_sanitizer.config.default'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); + $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.default')->getClass()); + $this->assertCount(23, $calls = $container->getDefinition('html_sanitizer.config.default')->getMethodCalls()); $this->assertSame( [ ['allowSafeElements', [], true], @@ -2092,11 +2081,11 @@ static function ($call) { ); // Named alias - $this->assertSame('html_sanitizer.sanitizer.my.sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class.' $mySanitizer'), '->registerHtmlSanitizerConfiguration() creates appropriate named alias'); - $this->assertSame('html_sanitizer.sanitizer.all.sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class.' $allSanitizer'), '->registerHtmlSanitizerConfiguration() creates appropriate named alias'); + $this->assertSame('html_sanitizer.sanitizer.all.sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class.' $allSanitizer')); + $this->assertFalse($container->hasAlias(HtmlSanitizerInterface::class.' $default')); // Default alias - $this->assertSame('html_sanitizer.sanitizer.my.sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class), '->registerHtmlSanitizerConfiguration() creates appropriate default alias'); + $this->assertSame('html_sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class)); } protected function createContainer(array $data = []) diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index f598524da4d64..adfab4f96610c 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Form\AbstractRendererEngine; use Symfony\Component\Form\Form; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Mailer\Mailer; use Symfony\Component\Translation\Translator; @@ -54,6 +55,10 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('console.php'); } + if (!$container::willBeAvailable('symfony/html-sanitizer', HtmlSanitizerInterface::class, ['symfony/twig-bundle'])) { + $container->removeDefinition('twig.extension.htmlsanitizer'); + } + if ($container::willBeAvailable('symfony/mailer', Mailer::class, ['symfony/twig-bundle'])) { $loader->load('mailer.php'); } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.php b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.php index 6a5e52df6b472..5536315306b72 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.php +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.php @@ -18,6 +18,7 @@ use Symfony\Bridge\Twig\Extension\AssetExtension; use Symfony\Bridge\Twig\Extension\CodeExtension; use Symfony\Bridge\Twig\Extension\ExpressionExtension; +use Symfony\Bridge\Twig\Extension\HtmlSanitizerExtension; use Symfony\Bridge\Twig\Extension\HttpFoundationExtension; use Symfony\Bridge\Twig\Extension\HttpKernelExtension; use Symfony\Bridge\Twig\Extension\HttpKernelRuntime; @@ -118,6 +119,9 @@ ->set('twig.extension.expression', ExpressionExtension::class) + ->set('twig.extension.htmlsanitizer', HtmlSanitizerExtension::class) + ->args([tagged_locator('html_sanitizer', 'sanitizer')]) + ->set('twig.extension.httpkernel', HttpKernelExtension::class) ->set('twig.runtime.httpkernel', HttpKernelRuntime::class) diff --git a/src/Symfony/Component/Form/Extension/HtmlSanitizer/HtmlSanitizerExtension.php b/src/Symfony/Component/Form/Extension/HtmlSanitizer/HtmlSanitizerExtension.php new file mode 100644 index 0000000000000..6c4bf49d6ab8b --- /dev/null +++ b/src/Symfony/Component/Form/Extension/HtmlSanitizer/HtmlSanitizerExtension.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\HtmlSanitizer; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Form\AbstractExtension; + +/** + * Integrates the HtmlSanitizer component with the Form library. + * + * @author Nicolas Grekas + */ +class HtmlSanitizerExtension extends AbstractExtension +{ + public function __construct( + private ContainerInterface $sanitizers, + private string $defaultSanitizer = 'default', + ) { + } + + protected function loadTypeExtensions(): array + { + return [ + new Type\TextTypeHtmlSanitizerExtension($this->sanitizers, $this->defaultSanitizer), + ]; + } +} diff --git a/src/Symfony/Component/Form/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtension.php b/src/Symfony/Component/Form/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtension.php new file mode 100644 index 0000000000000..0d28c65bce1ad --- /dev/null +++ b/src/Symfony/Component/Form/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtension.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\HtmlSanitizer\Type; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Form\AbstractTypeExtension; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @author Titouan Galopin + */ +class TextTypeHtmlSanitizerExtension extends AbstractTypeExtension +{ + public function __construct( + private ContainerInterface $sanitizers, + private string $defaultSanitizer = 'default', + ) { + } + + public static function getExtendedTypes(): iterable + { + return [TextType::class]; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefaults(['sanitize_html' => false, 'sanitizer' => null]) + ->setAllowedTypes('sanitize_html', 'bool') + ->setAllowedTypes('sanitizer', ['string', 'null']) + ; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + if (!$options['sanitize_html']) { + return; + } + + $sanitizers = $this->sanitizers; + $sanitizer = $options['sanitizer'] ?? $this->defaultSanitizer; + + $builder->addEventListener( + FormEvents::PRE_SUBMIT, + static function (FormEvent $event) use ($sanitizers, $sanitizer) { + if (is_scalar($data = $event->getData()) && '' !== trim($data)) { + $event->setData($sanitizers->get($sanitizer)->sanitize($data)); + } + }, + 10000 /* as soon as possible */ + ); + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php new file mode 100644 index 0000000000000..39b8d03323342 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Csrf\Type; + +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\HtmlSanitizer\HtmlSanitizerExtension; +use Symfony\Component\Form\Test\TypeTestCase; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; + +class TextTypeHtmlSanitizerExtensionTest extends TypeTestCase +{ + protected function getExtensions() + { + $fooSanitizer = $this->createMock(HtmlSanitizerInterface::class); + $fooSanitizer->expects($this->once()) + ->method('sanitize') + ->with('foobar') + ->willReturn('foo'); + + $barSanitizer = $this->createMock(HtmlSanitizerInterface::class); + $barSanitizer->expects($this->once()) + ->method('sanitize') + ->with('foobar') + ->willReturn('bar'); + + return array_merge(parent::getExtensions(), [ + new HtmlSanitizerExtension(new ServiceLocator([ + 'foo' => fn () => $fooSanitizer, + 'bar' => fn () => $barSanitizer, + ]), 'foo'), + ]); + } + + public function testSanitizer() + { + $form = $this->factory->createBuilder(FormType::class, ['data' => null]) + ->add('data', TextType::class, ['sanitize_html' => true]) + ->getForm() + ; + $form->submit(['data' => 'foobar']); + + $this->assertSame(['data' => 'foo'], $form->getData()); + + $form = $this->factory->createBuilder(FormType::class, ['data' => null]) + ->add('data', TextType::class, ['sanitize_html' => true, 'sanitizer' => 'bar']) + ->getForm() + ; + $form->submit(['data' => 'foobar']); + + $this->assertSame(['data' => 'bar'], $form->getData()); + } +} diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 6fb2b50866543..05193a2f0c2e8 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -33,6 +33,7 @@ "symfony/expression-language": "^5.4|^6.0", "symfony/config": "^5.4|^6.0", "symfony/console": "^5.4|^6.0", + "symfony/html-sanitizer": "^6.1", "symfony/http-foundation": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", From 41ff71e64b482847bc048e9b688cd2ad2c2c4566 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 13 May 2022 15:52:09 +0200 Subject: [PATCH 58/65] [Console] fix CS for code related to Table vertical rendering --- .../Component/Console/Helper/Table.php | 22 ++++++++++++------- .../Console/Tests/Helper/TableTest.php | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 4e602b37e484c..e91fb75ed39ea 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -311,7 +311,7 @@ public function setVertical(bool $vertical = true): static public function render() { $divider = new TableSeparator(); - $isCellWithColspan = static fn ($cell): bool => $cell instanceof TableCell && $cell->getColspan() >= 2; + $isCellWithColspan = static fn ($cell) => $cell instanceof TableCell && $cell->getColspan() >= 2; $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation; $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation; @@ -334,30 +334,36 @@ public function render() } } } elseif ($vertical) { - $maxHeaderLength = array_reduce($this->headers[0] ?? [], static fn (int $max, string $header) => max($max, mb_strlen($header)), 0); + $formatter = $this->output->getFormatter(); + $maxHeaderLength = array_reduce($this->headers[0] ?? [], static fn ($max, $header) => max($max, Helper::width(Helper::removeDecoration($formatter, $header))), 0); foreach ($this->rows as $row) { if ($row instanceof TableSeparator) { continue; } - if (0 < \count($rows)) { + if ($rows) { $rows[] = [$divider]; } - $containsColspan = 0 < \count(array_filter($row, $isCellWithColspan)); + $containsColspan = false; + foreach ($row as $cell) { + if ($containsColspan = $isCellWithColspan($cell)) { + break; + } + } $headers = $this->headers[0] ?? []; $maxRows = max(\count($headers), \count($row)); for ($i = 0; $i < $maxRows; ++$i) { $cell = (string) ($row[$i] ?? ''); - if ([] !== $headers && !$containsColspan) { + if ($headers && !$containsColspan) { $rows[] = [sprintf( '%s: %s', str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), $cell )]; - } elseif (!empty($cell)) { + } elseif ('' !== $cell) { $rows[] = [$cell]; } } @@ -443,7 +449,7 @@ public function render() */ private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null) { - if (0 === $count = $this->numberOfColumns) { + if (!$count = $this->numberOfColumns) { return; } @@ -652,7 +658,7 @@ private function calculateRowCount(): int ++$numberOfRows; // Add row for header separator } - if (\count($this->rows) > 0) { + if ($this->rows) { ++$numberOfRows; // Add row for footer separator } diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 236506996ca28..f540a0807e182 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -1938,10 +1938,10 @@ public function testVerticalRender(string $expectedOutput, array $headers, array ->setVertical() ->setStyle($style); - if (!empty($headerTitle)) { + if ('' !== $headerTitle) { $table->setHeaderTitle($headerTitle); } - if (!empty($footerTitle)) { + if ('' !== $footerTitle) { $table->setFooterTitle($footerTitle); } From b5702ffe68f05e98150de356d75d50a0ed788e64 Mon Sep 17 00:00:00 2001 From: Nommyde Date: Fri, 13 May 2022 18:44:40 +0300 Subject: [PATCH 59/65] fix probably undefined variable $expireAt --- .../RateLimiter/Storage/InMemoryStorage.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/Storage/InMemoryStorage.php b/src/Symfony/Component/RateLimiter/Storage/InMemoryStorage.php index 7dade5a4e98fd..d0bfccdb4b63c 100644 --- a/src/Symfony/Component/RateLimiter/Storage/InMemoryStorage.php +++ b/src/Symfony/Component/RateLimiter/Storage/InMemoryStorage.php @@ -22,15 +22,7 @@ class InMemoryStorage implements StorageInterface public function save(LimiterStateInterface $limiterState): void { - if (isset($this->buckets[$limiterState->getId()])) { - [$expireAt, ] = $this->buckets[$limiterState->getId()]; - } - - if (null !== ($expireSeconds = $limiterState->getExpirationTime())) { - $expireAt = microtime(true) + $expireSeconds; - } - - $this->buckets[$limiterState->getId()] = [$expireAt, serialize($limiterState)]; + $this->buckets[$limiterState->getId()] = [$this->getExpireAt($limiterState), serialize($limiterState)]; } public function fetch(string $limiterStateId): ?LimiterStateInterface @@ -57,4 +49,13 @@ public function delete(string $limiterStateId): void unset($this->buckets[$limiterStateId]); } + + private function getExpireAt(LimiterStateInterface $limiterState): ?float + { + if (null !== $expireSeconds = $limiterState->getExpirationTime()) { + return microtime(true) + $expireSeconds; + } + + return $this->buckets[$limiterState->getId()][0] ?? null; + } } From 78a9c5905402264cf61f75346c689a76592d58e1 Mon Sep 17 00:00:00 2001 From: buffcode Date: Wed, 11 May 2022 17:11:17 +0200 Subject: [PATCH 60/65] Fix LDAP connection options --- .../Ldap/Adapter/ExtLdap/Connection.php | 16 +++++++++++++++- .../Ldap/Adapter/ExtLdap/ConnectionOptions.php | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php index 49e465d3f791c..77be43ba9b84e 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php @@ -29,6 +29,12 @@ class Connection extends AbstractConnection private const LDAP_INVALID_CREDENTIALS = 0x31; private const LDAP_TIMEOUT = 0x55; private const LDAP_ALREADY_EXISTS = 0x44; + private const PRECONNECT_OPTIONS = [ + ConnectionOptions::DEBUG_LEVEL, + ConnectionOptions::X_TLS_CACERTDIR, + ConnectionOptions::X_TLS_CACERTFILE, + ConnectionOptions::X_TLS_REQUIRE_CERT, + ]; /** @var bool */ private $bound = false; @@ -147,10 +153,18 @@ private function connect() return; } + foreach ($this->config['options'] as $name => $value) { + if (\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONS, true)) { + $this->setOption($name, $value); + } + } + $this->connection = ldap_connect($this->config['connection_string']); foreach ($this->config['options'] as $name => $value) { - $this->setOption($name, $value); + if (!\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONS, true)) { + $this->setOption($name, $value); + } } if (false === $this->connection) { diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/ConnectionOptions.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/ConnectionOptions.php index 50061bd80959e..58094fad5b8ea 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/ConnectionOptions.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/ConnectionOptions.php @@ -40,6 +40,7 @@ final class ConnectionOptions public const DEBUG_LEVEL = 0x5001; public const TIMEOUT = 0x5002; public const NETWORK_TIMEOUT = 0x5005; + public const X_TLS_CACERTFILE = 0x6002; public const X_TLS_CACERTDIR = 0x6003; public const X_TLS_CERTFILE = 0x6004; public const X_TLS_CRL_ALL = 0x02; From 9e2306e9737d752db87afb6e081d6505fa3d6b7d Mon Sep 17 00:00:00 2001 From: Kris Kelly Date: Tue, 19 Apr 2022 18:05:47 +0100 Subject: [PATCH 61/65] [Console] Fixes "Incorrectly nested style tag found" error when using multi-line header content --- .../Descriptor/alias_with_definition_2.txt | 6 ++--- .../Fixtures/Descriptor/definition_2.txt | 6 ++--- .../Descriptor/definition_arguments_1.txt | 14 +++++------ .../Descriptor/definition_arguments_2.txt | 6 ++--- .../Tests/Fixtures/Descriptor/route_1.txt | 6 ++--- .../Tests/Fixtures/Descriptor/route_2.txt | 6 ++--- .../Bundle/FrameworkBundle/composer.json | 2 +- .../Component/Console/Helper/Table.php | 2 +- .../Console/Tests/Helper/TableTest.php | 24 +++++++++++++++++-- 9 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/alias_with_definition_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/alias_with_definition_2.txt index 12e90d48ae40b..4fd20cf7e5fab 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/alias_with_definition_2.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/alias_with_definition_2.txt @@ -8,9 +8,9 @@ ----------------- --------------------------------- Service ID .service_2 Class Full\Qualified\Class2 - Tags tag1 (attr1: val1, attr2: val2)  - tag1 (attr3: val3)  - tag2 + Tags tag1 (attr1: val1, attr2: val2) + tag1 (attr3: val3) + tag2 Calls setMailer Public no Synthetic yes diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt index 2d5b03794ea80..0ceb807a45c2f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.txt @@ -3,9 +3,9 @@ ----------------- --------------------------------- Service ID - Class Full\Qualified\Class2 - Tags tag1 (attr1: val1, attr2: val2)  - tag1 (attr3: val3)  - tag2 + Tags tag1 (attr1: val1, attr2: val2) + tag1 (attr3: val3) + tag2 Calls setMailer Public no Synthetic yes diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt index 2e9dc9771c09d..a3caa93c9dcf9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_1.txt @@ -13,12 +13,12 @@ Autoconfigured no Factory Class Full\Qualified\FactoryClass Factory Method get - Arguments Service(.definition_2)  - %parameter%  - Inlined Service  - Array (3 element(s))  - Iterator (2 element(s))  - - Service(definition_1)  - - Service(.definition_2) + Arguments Service(.definition_2) + %parameter% + Inlined Service + Array (3 element(s)) + Iterator (2 element(s)) + - Service(definition_1) + - Service(.definition_2) ---------------- ----------------------------- diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt index 2d5b03794ea80..0ceb807a45c2f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_2.txt @@ -3,9 +3,9 @@ ----------------- --------------------------------- Service ID - Class Full\Qualified\Class2 - Tags tag1 (attr1: val1, attr2: val2)  - tag1 (attr3: val3)  - tag2 + Tags tag1 (attr1: val1, attr2: val2) + tag1 (attr3: val3) + tag2 Calls setMailer Public no Synthetic yes diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt index 25074dfd18b2c..9814273b7a221 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt @@ -11,7 +11,7 @@ | Requirements | name: [a-z]+ | | Class | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\RouteStub | | Defaults | name: Joseph | -| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | -| | opt1: val1 | -| | opt2: val2 | +| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +| | opt1: val1 | +| | opt2: val2 | +--------------+-------------------------------------------------------------------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt index 5853dd013d3a3..533409d402add 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt @@ -11,8 +11,8 @@ | Requirements | NO CUSTOM | | Class | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\RouteStub | | Defaults | NONE | -| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | -| | opt1: val1 | -| | opt2: val2 | +| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +| | opt1: val1 | +| | opt2: val2 | | Condition | context.getMethod() in ['GET', 'HEAD', 'POST'] | +--------------+-------------------------------------------------------------------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index a9735e6c47ec3..bf3ffcac6fe0f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -37,7 +37,7 @@ "paragonie/sodium_compat": "^1.8", "symfony/asset": "^3.4|^4.0|^5.0", "symfony/browser-kit": "^4.3|^5.0", - "symfony/console": "^4.4.21|^5.0", + "symfony/console": "^4.4.42|^5.4.9", "symfony/css-selector": "^3.4|^4.0|^5.0", "symfony/dom-crawler": "^4.4.30|^5.3.7", "symfony/dotenv": "^4.3.6|^5.0", diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 141e7d4908bc6..99496b1c72dea 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -586,7 +586,7 @@ private function buildTableRows(array $rows): TableRows } $escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; - $lines = explode("\n", str_replace("\n", "\n", $cell)); + $lines = explode("\n", str_replace("\n", "\n", $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 14ea5c6bb15ba..c0f3f96b2aa95 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -615,8 +615,8 @@ public function renderProvider() 'default', <<<'TABLE' +-------+------------+ -| Dont break | -| here | +| Dont break | +| here | +-------+------------+ | foo | Dont break | | bar | here | @@ -1078,6 +1078,26 @@ public function renderSetTitle() | 80-902734-1-6 | And Then There Were None | Agatha Christie | +---------------+--------- Page 1/2 -------+------------------+ +TABLE + , + true, + ], + 'header contains multiple lines' => [ + 'Multiline'."\n".'header'."\n".'here', + 'footer', + 'default', + <<<'TABLE' ++---------------+--- Multiline +header +here +------------------+ +| ISBN | Title | Author | ++---------------+--------------------------+------------------+ +| 99921-58-10-7 | Divine Comedy | Dante Alighieri | +| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | +| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | +| 80-902734-1-6 | And Then There Were None | Agatha Christie | ++---------------+---------- footer --------+------------------+ + TABLE ], [ From 40dbb2a6af7a1fa4cab93643659dc57777065566 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 14 May 2022 15:25:11 +0200 Subject: [PATCH 62/65] [GHA] fix tests for kafka --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index fc578fd6283a1..b2d8d1e540ace 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -91,7 +91,7 @@ jobs: zookeeper: image: wurstmeister/zookeeper:3.4.6 kafka: - image: wurstmeister/kafka:2.12-2.4.1 + image: wurstmeister/kafka:2.12-2.0.1 ports: - 9092:9092 env: From b6ff1d618a622d8c58895bdaf88dd33942be66ed Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 14 May 2022 16:13:10 +0200 Subject: [PATCH 63/65] [GHA] fix tests for couchbase --- .github/workflows/integration-tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index fc578fd6283a1..5f8c3e7507a56 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -108,11 +108,13 @@ jobs: - name: Install system dependencies run: | echo "::group::apt-get update" + sudo wget -O - https://packages.couchbase.com/clients/c/repos/deb/couchbase.key | sudo apt-key add - + echo "deb https://packages.couchbase.com/clients/c/repos/deb/ubuntu2004 focal focal/main" | sudo tee /etc/apt/sources.list.d/couchbase.list sudo apt-get update echo "::endgroup::" echo "::group::install tools & libraries" - sudo apt-get install librdkafka-dev redis-server + sudo apt-get install librdkafka-dev redis-server libcouchbase-dev sudo -- sh -c 'echo unixsocket /var/run/redis/redis-server.sock >> /etc/redis/redis.conf' sudo -- sh -c 'echo unixsocketperm 777 >> /etc/redis/redis.conf' sudo service redis-server restart @@ -129,7 +131,7 @@ jobs: uses: shivammathur/setup-php@v2 with: coverage: "none" - extensions: "json,couchbase,memcached,mongodb-1.10.0,redis-5.3.4,rdkafka,xsl,ldap" + extensions: "json,couchbase-3.2.2,memcached,mongodb-1.10.0,redis-5.3.4,rdkafka,xsl,ldap" ini-values: date.timezone=Europe/Paris,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,apc.enable_cli=1,zend.assertions=1 php-version: "${{ matrix.php }}" tools: pecl From ddb2443ad318fb1ed8de34bc105271de358cdc7f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 14 May 2022 20:28:25 +0200 Subject: [PATCH 64/65] Update CHANGELOG for 6.1.0-RC1 --- CHANGELOG-6.1.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/CHANGELOG-6.1.md b/CHANGELOG-6.1.md index c6f96fbf15753..88b3cc9960d82 100644 --- a/CHANGELOG-6.1.md +++ b/CHANGELOG-6.1.md @@ -7,6 +7,38 @@ in 6.1 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/v6.1.0...v6.1.1 +* 6.1.0-RC1 (2022-05-14) + + * feature #46335 [Form][FrameworkBundle][TwigBundle] Add Twig filter, form-type extension and improve service definitions for HtmlSanitizer (nicolas-grekas) + * bug #46114 Fixes "Incorrectly nested style tag found" error when using multi-line header content (Perturbatio) + * bug #46325 [Ldap] Fix LDAP connection options (buffcode) + * bug #46341 Fix aliases handling in command name completion (Seldaek) + * bug #46317 [Security/Http] Ignore invalid URLs found in failure/success paths (nicolas-grekas) + * bug #46309 [Security] Fix division by zero (tvlooy) + * bug #46327 [HttpKernel] Allow ErrorHandler ^5.0 to be used in HttpKernel 4.4 (mpdude) + * bug #46310 [MonologBridge] Fix LevelName being removed in Monolog 3.0 (Seldaek) + * bug #46297 [Serializer] Fix JsonSerializableNormalizer ignores circular reference handler in $context (BreyndotEchse) + * bug #46291 [Console] Suppress unhandled error in some specific use-cases. (rw4lll) + * bug #46302 [ErrorHandler] Fix list of tentative return types (nicolas-grekas) + * bug #46293 [HttpClient] "debug" is missing if a request failed to even start (weaverryan) + * bug #45981 [Serializer][PropertyInfo] Fix support for "false" built-in type on PHP 8.2 (alexandre-daubois) + * feature #41676 [Console] Table vertical rendering (yoannrenard) + * bug #46277 [HttpKernel] Fix SessionListener without session in request (edditor) + * bug #46282 [DoctrineBridge] Treat firstResult === 0 like null (derrabus) + * bug #46239 [Translation] Refresh local translations on PushCommand if the provider has domains (Florian-B) + * bug #46274 [HtmlSanitizer] Fix node renderer handling of self-closing (void) elements (omniError) + * bug #46276 [DependencyInjection] Fix lazyness of AutowiringFailedException (nicolas-grekas) + * bug #46278 [Workflow] Fix deprecated syntax for interpolated strings (nicolas-grekas) + * bug #46264 [Console] Better required argument check in InputArgument (jnoordsij) + * bug #46272 [DependencyInjection] Fix resolving parameters found in #[Autowire] (nicolas-grekas) + * bug #46262 [EventDispatcher] Fix removing listeners when using first-class callable syntax (javer) + * feature #46153 [MonologBridge] Add support for Monolog 3 (Seldaek) + * bug #46199 [HttpKernel] Handle previously converted `DateTime` arguments (mbabker) + * bug #46216 [Form] fix populating single widget time view data with different timezones (xabbuh) + * bug #46221 [DomCrawler][VarDumper] Fix html-encoding emojis (nicolas-grekas) + * bug #46220 [Console] Fix fish completion script (wouterj) + * bug #46167 [VarExporter] Fix exporting DateTime objects on PHP 8.2 (nicolas-grekas) + * 6.1.0-BETA2 (2022-04-27) * feature #45282 [Serializer] Support canners in object normalizer (rmikalkenas) From 34c665d759813ecc0cc23270b0d5c4cd4d914aba Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 14 May 2022 20:28:31 +0200 Subject: [PATCH 65/65] Update VERSION for 6.1.0-RC1 --- 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 aafc62dbb01f9..603365b81c3b5 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.1.0-DEV'; + public const VERSION = '6.1.0-RC1'; public const VERSION_ID = 60100; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 1; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = 'RC1'; public const END_OF_MAINTENANCE = '01/2023'; public const END_OF_LIFE = '01/2023';