From 2e567f1114bf8f1722be7aa1b4f357a61afc8752 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 24 Nov 2021 09:45:16 +0100 Subject: [PATCH 01/75] Bump Symfony version to 4.4.36 --- 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 3f5a3314ab883..398f4c102cca0 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.35'; - public const VERSION_ID = 40435; + public const VERSION = '4.4.36-DEV'; + public const VERSION_ID = 40436; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 35; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 36; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From 9ce61e128f20156830ac708cb27db2b0db0fdc74 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 24 Nov 2021 14:16:06 +0100 Subject: [PATCH 02/75] [appveyor] Bump apcu to 5.1.18 --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c125ea3afb205..f342e252ec340 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -20,8 +20,8 @@ install: - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-Win32-VC14-x86.zip - 7z x php-7.1.3-Win32-VC14-x86.zip -y >nul - cd ext - - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.8-7.1-ts-vc14-x86.zip - - 7z x php_apcu-5.1.8-7.1-ts-vc14-x86.zip -y >nul + - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.18-7.1-ts-vc14-x86.zip + - 7z x php_apcu-5.1.18-7.1-ts-vc14-x86.zip -y >nul - cd .. - copy /Y php.ini-development php.ini-min - echo memory_limit=-1 >> php.ini-min From a1e22dc9874c5326041893b9ef306f138e7424c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 25 Nov 2021 11:18:20 +0100 Subject: [PATCH 03/75] Revert "[DoctrineBridge] add support for the JSON type" This reverts commit 1e218c5a6aa684ea2ebd15b7b6635de5d8af58b9. --- .../Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php | 2 -- .../Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 072fa91affa2b..879e87979499c 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -189,7 +189,6 @@ public function getTypes($class, $property, array $context = []) case self::$useDeprecatedConstants ? DBALType::TARRAY : Types::ARRAY: // no break case 'json_array': - case 'json': return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)]; case self::$useDeprecatedConstants ? DBALType::SIMPLE_ARRAY : Types::SIMPLE_ARRAY: @@ -317,7 +316,6 @@ private function getPhpType(string $doctrineType): ?string case self::$useDeprecatedConstants ? DBALType::SIMPLE_ARRAY : Types::SIMPLE_ARRAY: // no break case 'json_array': - case 'json': return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index 71eaf31ca7f80..7e256eb77e2d8 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -254,11 +254,11 @@ public function typesProvider() new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class) )]], - ['json', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]], + ['json', null], ]; if (class_exists(Types::class)) { - $provider[] = ['json', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]]; + $provider[] = ['json', null]; } return $provider; From e724d5ae4809c87536b135f529e8cadc4da9a671 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 25 Nov 2021 13:05:50 +0100 Subject: [PATCH 04/75] Fix redundant type casts --- ...ExtensionBootstrap3HorizontalLayoutTest.php | 18 +++++++++--------- .../FormExtensionBootstrap3LayoutTest.php | 18 +++++++++--------- ...ExtensionBootstrap4HorizontalLayoutTest.php | 18 +++++++++--------- .../FormExtensionBootstrap4LayoutTest.php | 18 +++++++++--------- .../Extension/FormExtensionDivLayoutTest.php | 18 +++++++++--------- .../Extension/FormExtensionTableLayoutTest.php | 18 +++++++++--------- .../Tests/Templating/TimedPhpEngineTest.php | 14 ++------------ .../DependencyInjection/SecurityExtension.php | 2 +- .../Controller/ExceptionController.php | 2 +- .../Config/Resource/ClassExistenceResource.php | 2 +- src/Symfony/Component/Config/Util/XmlUtils.php | 4 ++-- .../Loader/XmlFileLoader.php | 6 +++--- .../Component/ErrorHandler/ErrorHandler.php | 2 +- .../Iterator/RecursiveDirectoryIterator.php | 2 +- .../Component/HttpFoundation/Request.php | 2 +- .../Session/Flash/AutoExpireFlashBag.php | 2 +- .../Storage/Proxy/SessionHandlerProxy.php | 14 +++++++------- .../DataCollector/RequestDataCollector.php | 2 +- .../Intl/NumberFormatter/NumberFormatter.php | 4 +--- .../AbstractNumberFormatterTest.php | 8 ++++---- .../Transport/RedisExt/Connection.php | 2 +- .../Component/Templating/Storage/Storage.php | 2 +- src/Symfony/Component/Yaml/Inline.php | 2 +- 23 files changed, 84 insertions(+), 96 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php index d8e8468c3f4bc..9f0b0c070a2d9 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php @@ -57,7 +57,7 @@ protected function setUp(): void protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -66,42 +66,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php index 0735cc2973e65..38c445f927726 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php @@ -107,7 +107,7 @@ public function testMoneyWidgetInIso() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -116,42 +116,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php index da0564851229a..5c2e5afcfdf99 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php @@ -59,7 +59,7 @@ protected function setUp(): void protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -68,42 +68,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php index f62e903473ca5..7dda79420ca12 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php @@ -111,7 +111,7 @@ public function testMoneyWidgetInIso() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -120,42 +120,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 9e7b1684b8265..ff9357627579c 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -298,7 +298,7 @@ public function testHelpHtmlIsTrue() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -307,42 +307,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php index ecf3597b311a8..301a74ed94449 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -184,7 +184,7 @@ public function testHelpHtmlIsTrue() protected function renderForm(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form', $vars); + return $this->renderer->renderBlock($view, 'form', $vars); } protected function renderLabel(FormView $view, $label = null, array $vars = []) @@ -193,42 +193,42 @@ protected function renderLabel(FormView $view, $label = null, array $vars = []) $vars += ['label' => $label]; } - return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars); + return $this->renderer->searchAndRenderBlock($view, 'label', $vars); } protected function renderHelp(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'help'); + return $this->renderer->searchAndRenderBlock($view, 'help'); } protected function renderErrors(FormView $view) { - return (string) $this->renderer->searchAndRenderBlock($view, 'errors'); + return $this->renderer->searchAndRenderBlock($view, 'errors'); } protected function renderWidget(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars); + return $this->renderer->searchAndRenderBlock($view, 'widget', $vars); } protected function renderRow(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars); + return $this->renderer->searchAndRenderBlock($view, 'row', $vars); } protected function renderRest(FormView $view, array $vars = []) { - return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars); + return $this->renderer->searchAndRenderBlock($view, 'rest', $vars); } protected function renderStart(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_start', $vars); + return $this->renderer->renderBlock($view, 'form_start', $vars); } protected function renderEnd(FormView $view, array $vars = []) { - return (string) $this->renderer->renderBlock($view, 'form_end', $vars); + return $this->renderer->renderBlock($view, 'form_end', $vars); } protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TimedPhpEngineTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TimedPhpEngineTest.php index 4951b46c45137..2db6d689530ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TimedPhpEngineTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TimedPhpEngineTest.php @@ -31,7 +31,7 @@ public function testThatRenderLogsTime() $container = $this->createMock(Container::class); $templateNameParser = $this->getTemplateNameParser(); $globalVariables = $this->getGlobalVariables(); - $loader = $this->getLoader($this->getStorage()); + $loader = $this->getLoader(new StringStorage('foo')); $stopwatch = new Stopwatch(); @@ -60,17 +60,7 @@ private function getGlobalVariables(): GlobalVariables return $this->createMock(GlobalVariables::class); } - private function getStorage(): StringStorage - { - return $this->getMockBuilder(StringStorage::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - } - - /** - * @param StringStorage $storage - */ - private function getLoader($storage): Loader + private function getLoader(StringStorage $storage): Loader { $loader = $this->getMockForAbstractClass(Loader::class); $loader->expects($this->once()) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 22f3a8fa54351..1996249a72070 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -730,7 +730,7 @@ private function createExpression(ContainerBuilder $container, string $expressio private function createRequestMatcher(ContainerBuilder $container, string $path = null, string $host = null, int $port = null, array $methods = [], array $ips = null, array $attributes = []): Reference { if ($methods) { - $methods = array_map('strtoupper', (array) $methods); + $methods = array_map('strtoupper', $methods); } if (null !== $ips) { diff --git a/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php index a5127a25d823c..dda4ae6e82f32 100644 --- a/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php +++ b/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php @@ -64,7 +64,7 @@ public function showAction(Request $request, FlattenException $exception, DebugL $code = $exception->getStatusCode(); return new Response($this->twig->render( - (string) $this->findTemplate($request, $request->getRequestFormat(), $code, $showException), + $this->findTemplate($request, $request->getRequestFormat(), $code, $showException), [ 'status_code' => $code, 'status_text' => Response::$statusTexts[$code] ?? '', diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index 8179ce7fb4f1e..f04b767e7f704 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -38,7 +38,7 @@ public function __construct(string $resource, bool $exists = null) { $this->resource = $resource; if (null !== $exists) { - $this->exists = [(bool) $exists, null]; + $this->exists = [$exists, null]; } } diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php index 12caa486bfc4c..41fb5a9e6259b 100644 --- a/src/Symfony/Component/Config/Util/XmlUtils.php +++ b/src/Symfony/Component/Config/Util/XmlUtils.php @@ -239,12 +239,12 @@ public static function phpize($value) $raw = $value; $cast = (int) $value; - return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw); + return '0' == $value[0] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw); case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)): $raw = $value; $cast = (int) $value; - return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw); + return '0' == $value[1] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw); case 'true' === $lowercaseValue: return true; case 'false' === $lowercaseValue: diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 968a3f5eebff5..fdf4fa1f4c887 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -197,7 +197,7 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa if ($alias = $service->getAttribute('alias')) { $this->validateAlias($service, $file); - $this->container->setAlias((string) $service->getAttribute('id'), $alias = new Alias($alias)); + $this->container->setAlias($service->getAttribute('id'), $alias = new Alias($alias)); if ($publicAttr = $service->getAttribute('public')) { $alias->setPublic(XmlUtils::phpize($publicAttr)); } elseif (isset($defaults['public'])) { @@ -345,7 +345,7 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa } if ('' === $tag->getAttribute('name')) { - throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', (string) $service->getAttribute('id'), $file)); + throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', $service->getAttribute('id'), $file)); } $definition->addTag($tag->getAttribute('name'), $parameters); @@ -374,7 +374,7 @@ private function parseDefinition(\DOMElement $service, string $file, array $defa } elseif ('null' === $decorationOnInvalid) { $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; } else { - throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, (string) $service->getAttribute('id'), $file)); + throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, $service->getAttribute('id'), $file)); } $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null; diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index e6e21d601700e..4c4d7dc361cb9 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -342,7 +342,7 @@ public function scopeAt(int $levels, bool $replace = false): int public function traceAt(int $levels, bool $replace = false): int { $prev = $this->tracedErrors; - $this->tracedErrors = (int) $levels; + $this->tracedErrors = $levels; if (!$replace) { $this->tracedErrors |= $prev; } diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php index a18e6185beeec..8508ab707b9a3 100644 --- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php +++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php @@ -64,7 +64,7 @@ public function current() // the logic here avoids redoing the same work in all iterations if (null === $subPathname = $this->subPath) { - $subPathname = $this->subPath = (string) $this->getSubPath(); + $subPathname = $this->subPath = $this->getSubPath(); } if ('' !== $subPathname) { $subPathname .= $this->directorySeparator; diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index e2586f9a91a6b..b6e6c3036b80f 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1907,7 +1907,7 @@ protected function preparePathInfo() return '/'; } - return (string) $pathInfo; + return $pathInfo; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php index 6502f3d50155f..facbe102d5408 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php @@ -78,7 +78,7 @@ public function peek($type, array $default = []) */ public function peekAll() { - return \array_key_exists('display', $this->flashes) ? (array) $this->flashes['display'] : []; + return \array_key_exists('display', $this->flashes) ? $this->flashes['display'] : []; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php index 5535bc96441db..9b0cdeb7fe1d0 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -21,7 +21,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf public function __construct(\SessionHandlerInterface $handler) { $this->handler = $handler; - $this->wrapper = ($handler instanceof \SessionHandler); + $this->wrapper = $handler instanceof \SessionHandler; $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user'; } @@ -41,7 +41,7 @@ public function getHandler() #[\ReturnTypeWillChange] public function open($savePath, $sessionName) { - return (bool) $this->handler->open($savePath, $sessionName); + return $this->handler->open($savePath, $sessionName); } /** @@ -50,16 +50,16 @@ public function open($savePath, $sessionName) #[\ReturnTypeWillChange] public function close() { - return (bool) $this->handler->close(); + return $this->handler->close(); } /** - * @return string + * @return string|false */ #[\ReturnTypeWillChange] public function read($sessionId) { - return (string) $this->handler->read($sessionId); + return $this->handler->read($sessionId); } /** @@ -68,7 +68,7 @@ public function read($sessionId) #[\ReturnTypeWillChange] public function write($sessionId, $data) { - return (bool) $this->handler->write($sessionId, $data); + return $this->handler->write($sessionId, $data); } /** @@ -77,7 +77,7 @@ public function write($sessionId, $data) #[\ReturnTypeWillChange] public function destroy($sessionId) { - return (bool) $this->handler->destroy($sessionId); + return $this->handler->destroy($sessionId); } /** diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php index 2a3f6ce514f46..1fb226d13c38f 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php @@ -150,7 +150,7 @@ public function collect(Request $request, Response $response/*, \Throwable $exce 'method' => $request->getMethod(), 'controller' => $this->parseController($request->attributes->get('_controller')), 'status_code' => $statusCode, - 'status_text' => Response::$statusTexts[(int) $statusCode], + 'status_text' => Response::$statusTexts[$statusCode], ]), 0, '/', null, $request->isSecure(), true, false, 'lax' )); diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index 0424d5e20f4c1..3ec7eb343e04e 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -272,7 +272,7 @@ public function __construct(?string $locale = 'en', int $style = null, $pattern throw new MethodArgumentNotImplementedException(__METHOD__, 'pattern'); } - $this->style = null !== $style ? (int) $style : null; + $this->style = $style; } /** @@ -796,8 +796,6 @@ private function isInitializedAttribute(string $attr): bool */ private function convertValueDataType($value, int $type) { - $type = (int) $type; - if (self::TYPE_DOUBLE === $type) { $value = (float) $value; } elseif (self::TYPE_INT32 === $type) { diff --git a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php index f392b3da50bac..7feb599fc5678 100644 --- a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php @@ -674,12 +674,12 @@ public function parseProvider() return [ ['prefix1', false, '->parse() does not parse a number with a string prefix.', 0], ['prefix1', false, '->parse() does not parse a number with a string prefix.', 0, false], - ['1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3], - ['1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3, false], + ['1.4suffix', 1.4, '->parse() parses a number with a string suffix.', 3], + ['1.4suffix', 1.4, '->parse() parses a number with a string suffix.', 3, false], ['1,234.4suffix', 1234.4, '->parse() parses a number with a string suffix.', 7], ['1,234.4suffix', 1.0, '->parse() parses a number with a string suffix.', 1, false], - ['-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3], - ['-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3, false], + ['-.4suffix', -0.4, '->parse() parses a negative dot float with suffix.', 3], + ['-.4suffix', -0.4, '->parse() parses a negative dot float with suffix.', 3, false], [',4', false, '->parse() does not parse when invalid grouping used.', 0], [',4', false, '->parse() does not parse when invalid grouping used.', 0, false], ['123,4', false, '->parse() does not parse when invalid grouping used.', 0], diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 340cd792d3c06..4e372eecd72f8 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -267,7 +267,7 @@ public function add(string $body, array $headers, int $delayInMs = 0): void throw new TransportException(json_last_error_msg()); } - $score = (int) ($this->getCurrentTimeInMilliseconds() + $delayInMs); + $score = $this->getCurrentTimeInMilliseconds() + $delayInMs; $added = $this->connection->zadd($this->queue, ['NX'], $score, $message); } else { $message = json_encode([ diff --git a/src/Symfony/Component/Templating/Storage/Storage.php b/src/Symfony/Component/Templating/Storage/Storage.php index 8c817ba5b0187..459c45c947d56 100644 --- a/src/Symfony/Component/Templating/Storage/Storage.php +++ b/src/Symfony/Component/Templating/Storage/Storage.php @@ -35,7 +35,7 @@ public function __construct(string $template) */ public function __toString() { - return (string) $this->template; + return $this->template; } /** diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index cb68755404224..24c802bcfa338 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -653,7 +653,7 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer // no break case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]): if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) { - $scalar = str_replace('_', '', (string) $scalar); + $scalar = str_replace('_', '', $scalar); } switch (true) { From db043aa478cf603ad64699c8d79ab706aaea88b2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 26 Nov 2021 16:37:56 +0100 Subject: [PATCH 05/75] [Serializer] fix support for lazy/unset properties --- .../PropertyAccess/PropertyAccessor.php | 6 ++++ .../Normalizer/AbstractObjectNormalizer.php | 30 ++++++++++++++++++- .../Normalizer/ObjectNormalizer.php | 10 +------ .../Normalizer/PropertyNormalizer.php | 26 +++++++++++----- .../Component/Serializer/composer.json | 2 +- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 061e6d71cba98..4df3d78913895 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -385,6 +385,7 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid $result = self::RESULT_PROTO; $object = $zval[self::VALUE]; + $class = \get_class($object); $access = $this->getReadAccessInfo(\get_class($object), $property); try { @@ -406,6 +407,11 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid throw $e; } } elseif (self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE]) { + $name = $access[self::ACCESS_NAME]; + if (!method_exists($object, '__get') && !isset($object->$name) && !\array_key_exists($name, (array) $object) && (\PHP_VERSION_ID < 70400 || !(new \ReflectionProperty($class, $name))->hasType())) { + throw new AccessException(sprintf('The property "%s::$%s" is not initialized.', $class, $name)); + } + $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}; if ($access[self::ACCESS_REF] && isset($zval[self::REF])) { diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 3c790d03d6f72..57df0b6b8e521 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Serializer\Normalizer; +use Symfony\Component\PropertyAccess\Exception\AccessException; use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException; use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; @@ -181,7 +182,23 @@ public function normalize($object, $format = null, array $context = []) continue; } - $attributeValue = $this->getAttributeValue($object, $attribute, $format, $context); + try { + $attributeValue = $this->getAttributeValue($object, $attribute, $format, $context); + } catch (AccessException $e) { + if (sprintf('The property "%s::$%s" is not initialized.', \get_class($object), $attribute) === $e->getMessage()) { + continue; + } + if (($p = $e->getPrevious()) && 'Error' === \get_class($p) && $this->isUninitializedValueError($p)) { + continue; + } + throw $e; + } catch (\Error $e) { + if ($this->isUninitializedValueError($e)) { + continue; + } + throw $e; + } + if ($maxDepthReached) { $attributeValue = $maxDepthHandler($attributeValue, $object, $attribute, $format, $context); } @@ -637,4 +654,15 @@ private function getCacheKey(?string $format, array $context) return false; } } + + /** + * This error may occur when specific object normalizer implementation gets attribute value + * by accessing a public uninitialized property or by calling a method accessing such property. + */ + private function isUninitializedValueError(\Error $e): bool + { + return \PHP_VERSION_ID >= 70400 + && str_starts_with($e->getMessage(), 'Typed property') + && str_ends_with($e->getMessage(), 'must not be accessed before initialization'); + } } diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index 874b4788d9295..758611a5d7ad4 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -104,16 +104,8 @@ protected function extractAttributes($object, $format = null, array $context = [ } // properties - $propertyValues = !method_exists($object, '__get') ? (array) $object : null; foreach ($reflClass->getProperties() as $reflProperty) { - if (null !== $propertyValues && !\array_key_exists($reflProperty->name, $propertyValues)) { - if ($reflProperty->isPublic() - || ($reflProperty->isProtected() && !\array_key_exists("\0*\0{$reflProperty->name}", $propertyValues)) - || ($reflProperty->isPrivate() && !\array_key_exists("\0{$reflProperty->class}\0{$reflProperty->name}", $propertyValues)) - ) { - unset($attributes[$reflProperty->name]); - } - + if (!$reflProperty->isPublic()) { continue; } diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index 8ecd340816698..14017726aa58b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Serializer\Normalizer; +use Symfony\Component\PropertyAccess\Exception\AccessException; + /** * Converts between objects and arrays by mapping properties. * @@ -101,17 +103,10 @@ protected function extractAttributes($object, $format = null, array $context = [ { $reflectionObject = new \ReflectionObject($object); $attributes = []; - $propertyValues = !method_exists($object, '__get') ? (array) $object : null; do { foreach ($reflectionObject->getProperties() as $property) { - if ((null !== $propertyValues && ( - ($property->isPublic() && !\array_key_exists($property->name, $propertyValues)) - || ($property->isProtected() && !\array_key_exists("\0*\0{$property->name}", $propertyValues)) - || ($property->isPrivate() && !\array_key_exists("\0{$property->class}\0{$property->name}", $propertyValues)) - )) - || !$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context) - ) { + if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context)) { continue; } @@ -138,6 +133,21 @@ protected function getAttributeValue($object, $attribute, $format = null, array $reflectionProperty->setAccessible(true); } + if (\PHP_VERSION_ID >= 70400 && $reflectionProperty->hasType()) { + return $reflectionProperty->getValue($object); + } + + if (!method_exists($object, '__get') && !isset($object->$attribute)) { + $propertyValues = (array) $object; + + if (($reflectionProperty->isPublic() && !\array_key_exists($reflectionProperty->name, $propertyValues)) + || ($reflectionProperty->isProtected() && !\array_key_exists("\0*\0{$reflectionProperty->name}", $propertyValues)) + || ($reflectionProperty->isPrivate() && !\array_key_exists("\0{$reflectionProperty->class}\0{$reflectionProperty->name}", $propertyValues)) + ) { + throw new AccessException(sprintf('The property "%s::$%s" is not initialized.', \get_class($object), $reflectionProperty->name)); + } + } + return $reflectionProperty->getValue($object); } diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index 324c30edffddc..ad876e13b911b 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -29,7 +29,7 @@ "symfony/error-handler": "^4.4|^5.0", "symfony/http-foundation": "^3.4|^4.0|^5.0", "symfony/mime": "^4.4|^5.0", - "symfony/property-access": "^3.4.41|^4.4.9|^5.0.9", + "symfony/property-access": "^4.4.36|^5.3.13", "symfony/property-info": "^3.4.13|~4.0|^5.0", "symfony/validator": "^3.4|^4.0|^5.0", "symfony/yaml": "^3.4|^4.0|^5.0" From d78bc24940fa44623a6c5dceb7f545adde941bd1 Mon Sep 17 00:00:00 2001 From: Kirill Lazarev Date: Wed, 24 Nov 2021 02:20:44 +0300 Subject: [PATCH 06/75] [Process] intersect with getenv() in case-insensitive manner to get default envs - since environment variables are case-insensitive in Windows, all envs should be compared in case-insensitive manner --- src/Symfony/Component/Process/Process.php | 8 ++++---- src/Symfony/Component/Process/Tests/ProcessTest.php | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index d5c697cf9c2d7..c0b638aabda1e 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -304,10 +304,10 @@ public function start(callable $callback = null, array $env = []) $descriptors = $this->getDescriptors(); if ($this->env) { - $env += $this->env; + $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env; } - $env += $this->getDefaultEnv(); + $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->getDefaultEnv(), $env, 'strcasecmp') : $this->getDefaultEnv(); if (\is_array($commandline = $this->commandline)) { $commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline)); @@ -1659,8 +1659,8 @@ private function replacePlaceholders(string $commandline, array $env) private function getDefaultEnv(): array { $env = getenv(); - $env = array_intersect_key($env, $_SERVER) ?: $env; + $env = ('\\' === \DIRECTORY_SEPARATOR ? array_intersect_ukey($env, $_SERVER, 'strcasecmp') : array_intersect_key($env, $_SERVER)) ?: $env; - return $_ENV + $env; + return $_ENV + ('\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($env, $_ENV, 'strcasecmp') : $env); } } diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 70b8e05139026..806afbab0948c 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1522,6 +1522,18 @@ public function testWaitStoppedDeadProcess() $this->assertFalse($process->isRunning()); } + public function testEnvCaseInsensitiveOnWindows() + { + $p = $this->getProcessForCode('print_r([$_SERVER[\'PATH\'] ?? 1, $_SERVER[\'Path\'] ?? 2]);', null, ['PATH' => 'bar/baz']); + $p->run(null, ['Path' => 'foo/bar']); + + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->assertSame('Array ( [0] => 1 [1] => foo/bar )', preg_replace('/\s++/', ' ', trim($p->getOutput()))); + } else { + $this->assertSame('Array ( [0] => bar/baz [1] => foo/bar )', preg_replace('/\s++/', ' ', trim($p->getOutput()))); + } + } + /** * @param string|array $commandline * @param mixed $input From 325d19c35a5c3c5723a92c583f6261be4a519e83 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 28 Nov 2021 19:02:56 +0100 Subject: [PATCH 07/75] [DoctrineBridge] Add DbalLoggerTest to group legacy --- .appveyor.yml | 1 - .github/workflows/integration-tests.yml | 1 - .github/workflows/unit-tests.yml | 1 - .../Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php | 7 +++++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f342e252ec340..7fe5b25c3686e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,7 +12,6 @@ init: - SET SYMFONY_DEPRECATIONS_HELPER=strict - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 - - SET SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f install: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 09acdcd9dbbae..9832c8a9d09a2 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -99,7 +99,6 @@ jobs: - name: Run tests run: ./phpunit --group integration -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=1 # to be removed once DbalLogger is compatible with dbal 3.2+ REDIS_HOST: localhost REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' REDIS_SENTINEL_HOSTS: 'localhost:26379' diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index edd59d3f188f6..157f6462b4e67 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -63,7 +63,6 @@ jobs: echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV - echo SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 >> $GITHUB_ENV # to be removed once DbalLogger is compatible with dbal 3.2+ SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+') diff --git a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php index d79b7d4998134..710e87a15e0b8 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php @@ -15,6 +15,9 @@ use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Logger\DbalLogger; +/** + * @group legacy + */ class DbalLoggerTest extends TestCase { /** @@ -46,8 +49,8 @@ public function getLogFixtures() ['SQL', null, []], ['SQL', [], []], ['SQL', ['foo' => 'bar'], ['foo' => 'bar']], - ['SQL', ['foo' => "\x7F\xFF"], ['foo' => DbalLogger::BINARY_DATA_VALUE]], - ['SQL', ['foo' => "bar\x7F\xFF"], ['foo' => DbalLogger::BINARY_DATA_VALUE]], + ['SQL', ['foo' => "\x7F\xFF"], ['foo' => '(binary value)']], + ['SQL', ['foo' => "bar\x7F\xFF"], ['foo' => '(binary value)']], ['SQL', ['foo' => ''], ['foo' => '']], ]; } From cbac3133c5875b28addebf2741593ec1e4048670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20S=CC=8Cakalys?= Date: Mon, 29 Nov 2021 10:40:48 +0200 Subject: [PATCH 08/75] Increased the reserved memory from 10k to 32k The ErrorHandler's job includes handling out of memory (OOM) exceptions, therefore it is imoprtant that that feature works. In the current state, when handling OOM exceptions, the error handler produces an OOM error itself, because the old 10k reserve is apparently not enough anymore. To mitigate that, the reserved memory gets bumped to 32k (which is enouogh). --- src/Symfony/Component/Debug/ErrorHandler.php | 2 +- src/Symfony/Component/ErrorHandler/ErrorHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index fd22f201adef6..99791f9aad9f3 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -119,7 +119,7 @@ class ErrorHandler public static function register(self $handler = null, $replace = true) { if (null === self::$reservedMemory) { - self::$reservedMemory = str_repeat('x', 10240); + self::$reservedMemory = str_repeat('x', 32768); register_shutdown_function(__CLASS__.'::handleFatalError'); } diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index 4c4d7dc361cb9..9e523fd4c11f4 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -111,7 +111,7 @@ class ErrorHandler public static function register(self $handler = null, bool $replace = true): self { if (null === self::$reservedMemory) { - self::$reservedMemory = str_repeat('x', 10240); + self::$reservedMemory = str_repeat('x', 32768); register_shutdown_function(__CLASS__.'::handleFatalError'); } From 653a21d9756196c59417dcc4c3c860487b742ed3 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Mon, 29 Nov 2021 08:33:54 +0100 Subject: [PATCH 09/75] [Validator] Fix validation for single level domains --- .../Validator/Constraints/UrlValidator.php | 8 +++++++- .../Tests/Constraints/UrlValidatorTest.php | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 5bac10c8fe604..1150a8ab8e03d 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -26,7 +26,13 @@ class UrlValidator extends ConstraintValidator (%s):// # protocol (((?:[\_\.\pL\pN-]|%%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%%[0-9A-Fa-f]{2})+)@)? # basic auth ( - ([\pL\pN\pS\-\_]+\.)*(([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name + (?: + (?:xn--[a-z0-9-]++\.)*+xn--[a-z0-9-]++ # a domain name using punycode + | + (?:[\pL\pN\pS\pM\-\_]++\.)+[\pL\pN\pM]++ # a multi-level domain name + | + [a-z0-9\-\_]++ # a single-level domain name + )\.? | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index b224671c5340c..26d0f34cc812c 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -128,6 +128,10 @@ public function getValidUrls() ['http://very.long.domain.name.com/'], ['http://localhost/'], ['http://myhost123/'], + ['http://internal-api'], + ['http://internal-api.'], + ['http://internal-api/'], + ['http://internal-api/path'], ['http://127.0.0.1/'], ['http://127.0.0.1:80/'], ['http://[::1]/'], @@ -174,6 +178,7 @@ public function getValidUrls() ['http://symfony.com/#fragment'], ['http://symfony.com/#one_more%20test'], ['http://example.com/exploit.html?hello[0]=test'], + ['http://বিডিআইএ.বাংলা'], ]; } @@ -259,7 +264,14 @@ public function getInvalidUrls() ['http://127.0.0.1:aa/'], ['ftp://[::1]/'], ['http://[::1'], + ['http://☎'], + ['http://☎.'], + ['http://☎/'], + ['http://☎/path'], + ['http://hello.☎'], + ['http://hello.☎.'], ['http://hello.☎/'], + ['http://hello.☎/path'], ['http://:password@symfony.com'], ['http://:password@@symfony.com'], ['http://username:passwordsymfony.com'], @@ -276,6 +288,9 @@ public function getInvalidUrls() ['http://.m.example.com'], ['http://wwww.example..com'], ['http://.www.example.com'], + ['http://example.co-'], + ['http://example.co-/path'], + ['http:///path'], ]; } From 369d9d7c8db282b39aab95c73ce44940602605ff Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Tue, 30 Nov 2021 12:58:03 +0100 Subject: [PATCH 10/75] [HttpClient] Fix handling error info in MockResponse --- .../HttpClient/Response/MockResponse.php | 4 +++ .../HttpClient/Tests/MockHttpClientTest.php | 31 +++---------------- .../Tests/Response/MockResponseTest.php | 11 +++++++ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 8f5803202c1bf..c38a0a4f0cd6b 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -260,6 +260,10 @@ private static function readResponse(self $response, array $options, ResponseInt 'http_code' => $response->info['http_code'], ] + $info + $response->info; + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + if (!isset($response->info['total_time'])) { $response->info['total_time'] = microtime(true) - $response->info['start_time']; } diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index 75bf16d3e6c86..f97b0cbb363ff 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -18,7 +18,6 @@ use Symfony\Component\HttpClient\Response\ResponseStream; use Symfony\Contracts\HttpClient\ChunkInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -use Symfony\Contracts\HttpClient\ResponseInterface; class MockHttpClientTest extends HttpClientTestCase { @@ -141,16 +140,8 @@ protected function getHttpClient(string $testCase): HttpClientInterface break; case 'testDnsError': - $mock = $this->createMock(ResponseInterface::class); - $mock->expects($this->any()) - ->method('getStatusCode') - ->willThrowException(new TransportException('DSN error')); - $mock->expects($this->any()) - ->method('getInfo') - ->willReturn([]); - - $responses[] = $mock; - $responses[] = $mock; + $responses[] = $mockResponse = new MockResponse('', ['error' => 'DNS error']); + $responses[] = $mockResponse; break; case 'testToStream': @@ -164,12 +155,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface break; case 'testTimeoutOnAccess': - $mock = $this->createMock(ResponseInterface::class); - $mock->expects($this->any()) - ->method('getHeaders') - ->willThrowException(new TransportException('Timeout')); - - $responses[] = $mock; + $responses[] = new MockResponse('', ['error' => 'Timeout']); break; case 'testAcceptHeader': @@ -231,16 +217,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface break; case 'testMaxDuration': - $mock = $this->createMock(ResponseInterface::class); - $mock->expects($this->any()) - ->method('getContent') - ->willReturnCallback(static function (): void { - usleep(100000); - - throw new TransportException('Max duration was reached.'); - }); - - $responses[] = $mock; + $responses[] = new MockResponse('', ['error' => 'Max duration was reached.']); break; } diff --git a/src/Symfony/Component/HttpClient/Tests/Response/MockResponseTest.php b/src/Symfony/Component/HttpClient/Tests/Response/MockResponseTest.php index 2f389bcc80c79..c87c020ecac2c 100644 --- a/src/Symfony/Component/HttpClient/Tests/Response/MockResponseTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Response/MockResponseTest.php @@ -4,6 +4,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\Exception\JsonException; +use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Response\MockResponse; /** @@ -83,4 +84,14 @@ public function toArrayErrors() 'message' => 'JSON content was expected to decode to an array, "integer" returned for "https://example.com/file.json".', ]; } + + public function testErrorIsTakenIntoAccountInInitialization() + { + $this->expectException(TransportException::class); + $this->expectExceptionMessage('ccc error'); + + MockResponse::fromRequest('GET', 'https://symfony.com', [], new MockResponse('', [ + 'error' => 'ccc error', + ]))->getStatusCode(); + } } From 731712b29fad177649b78859c5522b99f99febb4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 29 Nov 2021 19:16:58 +0100 Subject: [PATCH 11/75] Update PR template --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 62662f876fd3a..5e7092d385910 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 5.4 for features / 4.4 or 5.3 for bug fixes +| Branch? | 6.1 for features / 4.4, 5.3, 5.4 or 6.0 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no @@ -8,14 +8,14 @@ | License | MIT | Doc PR | symfony/symfony-docs#... From 70310ca9f3d3aebe02bca32f7cec9d40a3e8080b Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 30 Nov 2021 13:33:01 -0500 Subject: [PATCH 12/75] [DoctrineBridge] fix calling get_class on non-object --- .../Constraints/UniqueEntityValidatorTest.php | 27 +++++++++++++++++++ .../Constraints/UniqueEntityValidator.php | 5 ++++ 2 files changed, 32 insertions(+) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index c0945114c9c23..bc0041c20b64c 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -37,6 +37,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** @@ -821,6 +822,32 @@ public function testValidateUniquenessWithEmptyIterator($entity, $result) $this->assertNoViolation(); } + public function testValueMustBeObject() + { + $constraint = new UniqueEntity([ + 'message' => 'myMessage', + 'fields' => ['name'], + 'em' => self::EM_NAME, + ]); + + $this->expectException(UnexpectedValueException::class); + + $this->validator->validate('foo', $constraint); + } + + public function testValueCanBeNull() + { + $constraint = new UniqueEntity([ + 'message' => 'myMessage', + 'fields' => ['name'], + 'em' => self::EM_NAME, + ]); + + $this->validator->validate(null, $constraint); + + $this->assertNoViolation(); + } + public function resultWithEmptyIterator(): array { $entity = new SingleIntIdEntity(1, 'foo'); diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index df17e0eedd4c8..cce8cb9079723 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -16,6 +16,7 @@ use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; /** * Unique Entity Validator checks if one or a set of fields contain unique values. @@ -61,6 +62,10 @@ public function validate($entity, Constraint $constraint) return; } + if (!\is_object($entity)) { + throw new UnexpectedValueException($entity, 'object'); + } + if ($constraint->em) { $em = $this->registry->getManager($constraint->em); From bd4ace6cf9a3446c15f4b1bfa1d782e4ee4001ef Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 29 Nov 2021 19:01:24 +0100 Subject: [PATCH 13/75] [gha] swap the php versions we use in jobs --- .github/workflows/unit-tests.yml | 8 +- src/Symfony/Bridge/Doctrine/composer.json | 2 + .../Component/ErrorHandler/ErrorHandler.php | 4 +- .../Tests/phpt/exception_rethrown.phpt | 6 +- .../Tests/ConstraintValidatorTest.php | 4 +- src/Symfony/Component/Validator/composer.json | 2 +- .../VarDumper/Caster/ReflectionCaster.php | 20 ++-- .../Tests/Caster/ReflectionCasterTest.php | 98 +++---------------- 8 files changed, 43 insertions(+), 101 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 157f6462b4e67..9671caa0ed004 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -21,10 +21,10 @@ jobs: matrix: include: - php: '7.2' - - php: '8.1' - php: '7.4' - mode: high-deps - php: '8.0' + mode: high-deps + - php: '8.1' mode: low-deps - php: '8.2' mode: experimental @@ -172,14 +172,14 @@ jobs: exit 0 fi - (cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb) - if [[ "${{ matrix.mode }}" = low-deps ]]; then echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT'" exit 0 fi + (cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb) + # matrix.mode = high-deps echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1 diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 79961033bc0a6..cce2609cf1a89 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -49,11 +49,13 @@ "conflict": { "doctrine/dbal": "<2.7", "doctrine/orm": "<2.6.3", + "doctrine/lexer": "<1.1", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/dependency-injection": "<3.4", "symfony/form": "<4.4", "symfony/http-kernel": "<4.3.7", "symfony/messenger": "<4.3", + "symfony/proxy-manager-bridge": "<4.4.19", "symfony/security-core": "<4.4", "symfony/validator": "<4.4.2|<5.0.2,>=5.0" }, diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index 9e523fd4c11f4..ceadcaf674fc6 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -609,7 +609,9 @@ public function handleException(\Throwable $exception) } $loggedErrors = $this->loggedErrors; - $this->loggedErrors = $exception === $handlerException ? 0 : $this->loggedErrors; + if ($exception === $handlerException) { + $this->loggedErrors &= ~$type; + } try { $this->handleException($handlerException); diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt index 06540f4530121..be5ce6a5cdffa 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt +++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/exception_rethrown.phpt @@ -16,7 +16,9 @@ if (true) { { public function log($level, $message, array $context = []): void { - echo 'LOG: ', $message, "\n"; + if (0 !== strpos($message, 'Deprecated: ')) { + echo 'LOG: ', $message, "\n"; + } } } } @@ -34,5 +36,5 @@ Exception {%S #message: "foo" #code: 0 #file: "%s" - #line: 25 + #line: 27 } diff --git a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php index 6ca3eab41fd6e..aeaef472fb03d 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php @@ -15,13 +15,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -final class ConstraintValidatorTest extends TestCase +class ConstraintValidatorTest extends TestCase { /** * @dataProvider formatValueProvider */ public function testFormatValue($expected, $value, $format = 0) { + \Locale::setDefault('en'); + $this->assertSame($expected, (new TestFormatValueConstraintValidator())->formatValueProxy($value, $format)); } diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 0e84422e8deaf..72617c39cea09 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -41,7 +41,7 @@ "egulias/email-validator": "^2.1.10|^3" }, "conflict": { - "doctrine/lexer": "<1.0.2", + "doctrine/lexer": "<1.1", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/dependency-injection": "<3.4", "symfony/http-kernel": "<4.4", diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index 819a618765dc5..2a74b25f21499 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -134,7 +134,7 @@ public static function castReflectionGenerator(\ReflectionGenerator $c, array $a array_unshift($trace, [ 'function' => 'yield', 'file' => $function->getExecutingFile(), - 'line' => $function->getExecutingLine() - 1, + 'line' => $function->getExecutingLine() - (int) (\PHP_VERSION_ID < 80100), ]); $trace[] = $frame; $a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1); @@ -263,15 +263,17 @@ public static function castParameter(\ReflectionParameter $c, array $a, Stub $st unset($a[$prefix.'allowsNull']); } - try { - $a[$prefix.'default'] = $v = $c->getDefaultValue(); - if ($c->isDefaultValueConstant()) { - $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); - } - if (null === $v) { - unset($a[$prefix.'allowsNull']); + if ($c->isOptional()) { + try { + $a[$prefix.'default'] = $v = $c->getDefaultValue(); + if ($c->isDefaultValueConstant()) { + $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); + } + if (null === $v) { + unset($a[$prefix.'allowsNull']); + } + } catch (\ReflectionException $e) { } - } catch (\ReflectionException $e) { } return $a; diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index ff259b345793d..3dae54ce46b33 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -122,21 +122,8 @@ public function testReflectionParameter() { $var = new \ReflectionParameter(reflectionParameterFixture::class, 0); - if (\PHP_VERSION_ID < 80100) { - $this->assertDumpMatchesFormat( - <<<'EOTXT' -ReflectionParameter { - +name: "arg1" - position: 0 - typeHint: "Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass" - default: null -} -EOTXT - , $var - ); - } else { - $this->assertDumpMatchesFormat( - <<<'EOTXT' + $this->assertDumpMatchesFormat( + <<<'EOTXT' ReflectionParameter { +name: "arg1" position: 0 @@ -145,8 +132,7 @@ public function testReflectionParameter() } EOTXT , $var - ); - } + ); } public function testReflectionParameterScalar() @@ -468,38 +454,20 @@ public function testGenerator() $generator = new GeneratorDemo(); $generator = $generator->baz(); - if (\PHP_VERSION_ID < 80100) { - $expectedDump = <<<'EODUMP' + $expectedDump = <<<'EODUMP' Generator { this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} - executing: { + %s: { %sGeneratorDemo.php:14 { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() › { › yield from bar(); › } } - } +%A} closed: false } EODUMP; - } else { - $expectedDump = <<<'EODUMP' -Generator { - this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} - trace: { - ./src/Symfony/Component/VarDumper/Tests/Fixtures/GeneratorDemo.php:13 { - Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() - › public function baz() - › { - › yield from bar(); - } - Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {} - } - closed: false -} -EODUMP; - } $this->assertDumpMatchesFormat($expectedDump, $generator); @@ -507,69 +475,33 @@ public function testGenerator() break; } - if (\PHP_VERSION_ID < 80100) { - $expectedDump = <<<'EODUMP' + $expectedDump = <<<'EODUMP' array:2 [ 0 => ReflectionGenerator { this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} - trace: { - %s%eTests%eFixtures%eGeneratorDemo.php:9 { + %s: { + %s%eTests%eFixtures%eGeneratorDemo.php:%d { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() - › { - › yield 1; - › } - } +%A › yield 1; +%A } %s%eTests%eFixtures%eGeneratorDemo.php:20 { …} %s%eTests%eFixtures%eGeneratorDemo.php:14 { …} - } +%A } closed: false } 1 => Generator { - executing: { - %sGeneratorDemo.php:10 { + %s: { + %s%eTests%eFixtures%eGeneratorDemo.php:%d { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() › yield 1; › } › } - } - closed: false - } -] -EODUMP; - } else { - $expectedDump = <<<'EODUMP' -array:2 [ - 0 => ReflectionGenerator { - this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} - trace: { - %s%eTests%eFixtures%eGeneratorDemo.php:9 { - Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() - › { - › yield 1; - › } - } - %s%eTests%eFixtures%eGeneratorDemo.php:20 { …} - %s%eTests%eFixtures%eGeneratorDemo.php:14 { …} - Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {} - } - closed: false - } - 1 => Generator { - trace: { - ./src/Symfony/Component/VarDumper/Tests/Fixtures/GeneratorDemo.php:9 { - Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() - › { - › yield 1; - › } - } - Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() {} - } +%A } closed: false } ] EODUMP; - } $r = new \ReflectionGenerator($generator); $this->assertDumpMatchesFormat($expectedDump, [$r, $r->getExecutingGenerator()]); From 770425c75abbb875f58f5bfdc3903dfee05afcc9 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 1 Dec 2021 17:25:24 +0100 Subject: [PATCH 14/75] Prevent infinite nesting of lazy `ObjectManager` instances when `ObjectManager` is reset This patch ensures that the `ObjectManager` that the `Symfony\Bridge\Doctrine\ManagerRegistry` replaces during `Symfony\Bridge\Doctrine\ManagerRegistry#resetService()` operations is a fresh non-lazy service. Before this change, `Symfony\Bridge\Doctrine\ManagerRegistry#resetService()` would replace the initialization of the lazy proxy with a new service each time, but that service being lazy, this led to an additional proxy nesting level at each service reset call. That leads to general issues around memory reliability, stack trace nesting (and therefore bigger logged traces) and potentially even stack overflow problems, when running with XDebug. The problem seems to only apply when the `symfony/dependency-injection` `Container` is compiled as a set of small factory files: that's because each generated factory has a boolean flag that indicates whether a lazy or non-lazy version of a service is requested, as introduced in the original implementation at https://github.com/symfony/symfony/pull/7890 --- .../Bridge/Doctrine/ManagerRegistry.php | 2 +- .../Doctrine/Tests/ManagerRegistryTest.php | 93 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php index 2139562dedbaf..0ed055fec64b7 100644 --- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php +++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php @@ -62,7 +62,7 @@ function (&$wrappedInstance, LazyLoadingInterface $manager) use ($name) { $name = $this->aliases[$name]; } if (isset($this->fileMap[$name])) { - $wrappedInstance = $this->load($this->fileMap[$name]); + $wrappedInstance = $this->load($this->fileMap[$name], false); } else { $method = $this->methodMap[$name] ?? 'get'.strtr($name, $this->underscoreMap).'Service'; // BC with DI v3.4 $wrappedInstance = $this->{$method}(false); diff --git a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php index a004935a6afdc..dcdc4ce6360fc 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php @@ -12,8 +12,15 @@ namespace Symfony\Bridge\Doctrine\Tests; use PHPUnit\Framework\TestCase; +use ProxyManager\Proxy\LazyLoadingInterface; +use ProxyManager\Proxy\ValueHolderInterface; use Symfony\Bridge\Doctrine\ManagerRegistry; +use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Bridge\ProxyManager\Tests\LazyProxy\Dumper\PhpDumperTest; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Dumper\PhpDumper; +use Symfony\Component\Filesystem\Filesystem; class ManagerRegistryTest extends TestCase { @@ -39,6 +46,92 @@ public function testResetService() $this->assertSame($foo, $container->get('foo')); $this->assertObjectNotHasAttribute('bar', $foo); } + + /** + * When performing an entity manager lazy service reset, the reset operations may re-use the container + * to create a "fresh" service: when doing so, it can happen that the "fresh" service is itself a proxy. + * + * Because of that, the proxy will be populated with a wrapped value that is itself a proxy: repeating + * the reset operation keeps increasing this nesting until the application eventually runs into stack + * overflow or memory overflow operations, which can happen for long-running processes that rely on + * services that are reset very often. + */ + public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther() + { + // This test scenario only applies to containers composed as a set of generated sources + $this->dumpLazyServiceProjectAsFilesServiceContainer(); + + /** @var ContainerInterface $container */ + $container = new \LazyServiceProjectAsFilesServiceContainer(); + + $registry = new TestManagerRegistry( + 'irrelevant', + [], + ['defaultManager' => 'foo'], + 'irrelevant', + 'defaultManager', + 'irrelevant' + ); + $registry->setTestContainer($container); + + $service = $container->get('foo'); + + self::assertInstanceOf(\stdClass::class, $service); + self::assertInstanceOf(LazyLoadingInterface::class, $service); + self::assertInstanceOf(ValueHolderInterface::class, $service); + self::assertFalse($service->isProxyInitialized()); + + $service->initializeProxy(); + + self::assertTrue($container->initialized('foo')); + self::assertTrue($service->isProxyInitialized()); + + $registry->resetManager(); + $service->initializeProxy(); + + $wrappedValue = $service->getWrappedValueHolderValue(); + self::assertInstanceOf(\stdClass::class, $wrappedValue); + self::assertNotInstanceOf(LazyLoadingInterface::class, $wrappedValue); + self::assertNotInstanceOf(ValueHolderInterface::class, $wrappedValue); + } + + /** @return void */ + private function dumpLazyServiceProjectAsFilesServiceContainer() + { + if (class_exists(\LazyServiceProjectAsFilesServiceContainer::class, false)) { + return; + } + + $container = new ContainerBuilder(); + + $container->register('foo', \stdClass::class) + ->setPublic(true) + ->setLazy(true); + $container->compile(); + + $fileSystem = new Filesystem(); + + $temporaryPath = $fileSystem->tempnam(sys_get_temp_dir(), 'symfonyManagerRegistryTest'); + $fileSystem->remove($temporaryPath); + $fileSystem->mkdir($temporaryPath); + + $dumper = new PhpDumper($container); + + $dumper->setProxyDumper(new ProxyDumper()); + $containerFiles = $dumper->dump([ + 'class' => 'LazyServiceProjectAsFilesServiceContainer', + 'as_files' => true, + ]); + + array_walk( + $containerFiles, + static function (string $containerSources, string $fileName) use ($temporaryPath): void { + (new Filesystem())->dumpFile($temporaryPath.'/'.$fileName, $containerSources); + } + ); + + require $temporaryPath.'/LazyServiceProjectAsFilesServiceContainer.php'; + } } class TestManagerRegistry extends ManagerRegistry From 517ff013cfc9a1e5c8bb33508732075cdbdf688c Mon Sep 17 00:00:00 2001 From: Maxim Semkin Date: Thu, 2 Dec 2021 00:00:27 +0300 Subject: [PATCH 15/75] Missing translations for Belarusian (be) #41032 --- .../Core/Resources/translations/security.be.xlf | 8 ++++++++ .../Resources/translations/validators.be.xlf | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf index b24a5c421acfa..0647f45279a43 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Спасылка для ўваходу несапраўдная або пратэрмінаваная. + + Too many failed login attempts, please try again in %minutes% minute. + Занадта шмат няўдалых спроб уваходу ў сістэму, паспрабуйце спробу праз %minutes% хвіліну. + + + Too many failed login attempts, please try again in %minutes% minutes. + Занадта шмат няўдалых спроб уваходу ў сістэму, паспрабуйце спробу праз %minutes% хвілін. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf index 5f9988ef3cdbe..648955684baa0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -386,6 +386,22 @@ This value is not a valid International Securities Identification Number (ISIN). Значэнне не з'яўляецца карэктным міжнародным ідэнтыфікацыйным нумарам каштоўных папер (ISIN). + + This value should be a valid expression. + Значэнне не з'яўляецца сапраўдным выразам. + + + This value is not a valid CSS color. + Значэнне не з'яўляецца дапушчальным колерам CSS. + + + This value is not a valid CIDR notation. + Значэнне не з'яўляецца сапраўднай натацыяй CIDR. + + + The value of the netmask should be between {{ min }} and {{ max }}. + Значэнне сеткавай маскі павінна быць ад {{min}} да {{max}}. + From a7c771250ae7ec97e11fbb4363b85ccd0789f298 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 2 Dec 2021 09:27:42 +0100 Subject: [PATCH 16/75] Tweak bug report template --- .github/ISSUE_TEMPLATE/1_Bug_report.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml index 5518d4e4ad79d..241c1f779bfaa 100644 --- a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml @@ -14,7 +14,7 @@ body: id: description attributes: label: Description - description: A clear and consise description of the problem + description: A clear and concise description of the problem validations: required: true - type: textarea @@ -22,15 +22,21 @@ body: attributes: label: How to reproduce description: | - Code and/or config needed to reproduce the problem. - If it's a complex bug, create a "bug reproducer" as explained in https://symfony.com/doc/current/contributing/code/reproducer.html + ⚠️ This is the most important part of the report ⚠️ + Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix. + Please, take the time to show us some code and/or config that is needed for others to reproduce the problem easily. + Most of the time, creating a "bug reproducer" as explained in the URL below is the best way to help us + and increases the chances someone will have a look at it: + https://symfony.com/doc/current/contributing/code/reproducer.html validations: required: true - type: textarea id: possible-solution attributes: label: Possible Solution - description: "Optional: only if you have suggestions on a fix/reason for the bug" + description: | + Optional: only if you have suggestions on a fix/reason for the bug + Don't hesitate to create a pull request with your solution, it helps get faster feedback. - type: textarea id: additional-context attributes: From 53cfbfda640ea7c11da7076a6e1f8e3ffc709834 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 2 Dec 2021 14:45:50 +0100 Subject: [PATCH 17/75] Add missing files from 5.3 --- .github/ISSUE_TEMPLATE/3_Support_question.md | 11 +++++++++++ .github/ISSUE_TEMPLATE/4_Documentation_issue.md | 10 ++++++++++ 2 files changed, 21 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/3_Support_question.md create mode 100644 .github/ISSUE_TEMPLATE/4_Documentation_issue.md diff --git a/.github/ISSUE_TEMPLATE/3_Support_question.md b/.github/ISSUE_TEMPLATE/3_Support_question.md new file mode 100644 index 0000000000000..9480710c15655 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_Support_question.md @@ -0,0 +1,11 @@ +--- +name: ⛔ Support Question +about: See https://symfony.com/support for questions about using Symfony and its components + +--- + +We use GitHub issues only to discuss about Symfony bugs and new features. For +this kind of questions about using Symfony or third-party bundles, please use +any of the support alternatives shown in https://symfony.com/support + +Thanks! diff --git a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md b/.github/ISSUE_TEMPLATE/4_Documentation_issue.md new file mode 100644 index 0000000000000..0855c3c5f1e12 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4_Documentation_issue.md @@ -0,0 +1,10 @@ +--- +name: ⛔ Documentation Issue +about: See https://github.com/symfony/symfony-docs/issues for documentation issues + +--- + +Symfony Documentation has its own dedicated repository. Please open your +documentation-related issue at https://github.com/symfony/symfony-docs/issues + +Thanks! From c3374d276aba6f3c49919c4a7ab9a2c1dbac07bf Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 2 Dec 2021 14:54:19 +0100 Subject: [PATCH 18/75] Fix description that does not work well --- .github/ISSUE_TEMPLATE/1_Bug_report.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml index 241c1f779bfaa..ef0f72c794278 100644 --- a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml @@ -1,5 +1,5 @@ name: 🐛 Bug Report -description: ⚠️ See below for security reports +description: ⚠️ NEVER report security issues, read https://symfony.com/security instead labels: Bug body: From 10b3b6870e892889b1a6f4ac85fddcd0a35c1b2f Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Thu, 2 Dec 2021 15:49:54 +0100 Subject: [PATCH 19/75] Use external links instead of fake issue templates --- .github/ISSUE_TEMPLATE/3_Support_question.md | 11 ----------- .github/ISSUE_TEMPLATE/4_Documentation_issue.md | 10 ---------- .github/ISSUE_TEMPLATE/config.yml | 8 ++++++++ 3 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/3_Support_question.md delete mode 100644 .github/ISSUE_TEMPLATE/4_Documentation_issue.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/3_Support_question.md b/.github/ISSUE_TEMPLATE/3_Support_question.md deleted file mode 100644 index 9480710c15655..0000000000000 --- a/.github/ISSUE_TEMPLATE/3_Support_question.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: ⛔ Support Question -about: See https://symfony.com/support for questions about using Symfony and its components - ---- - -We use GitHub issues only to discuss about Symfony bugs and new features. For -this kind of questions about using Symfony or third-party bundles, please use -any of the support alternatives shown in https://symfony.com/support - -Thanks! diff --git a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md b/.github/ISSUE_TEMPLATE/4_Documentation_issue.md deleted file mode 100644 index 0855c3c5f1e12..0000000000000 --- a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: ⛔ Documentation Issue -about: See https://github.com/symfony/symfony-docs/issues for documentation issues - ---- - -Symfony Documentation has its own dedicated repository. Please open your -documentation-related issue at https://github.com/symfony/symfony-docs/issues - -Thanks! diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000..34227566ed84a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Support Question + url: https://symfony.com/support + about: We use GitHub issues only to discuss about Symfony bugs and new features. For this kind of questions about using Symfony or third-party bundles, please use any of the support alternatives shown in https://symfony.com/support + - name: Documentation Issue + url: https://github.com/symfony/symfony-docs/issues + about: Symfony Documentation has its own dedicated repository. From 3c1c8542d1493f1f6c6bac6d49548aec963c7664 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 3 Dec 2021 12:31:53 +0100 Subject: [PATCH 20/75] Remove return void PHPDoc in test --- src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php index dcdc4ce6360fc..dd7dabcc87db1 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php @@ -95,7 +95,6 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther() self::assertNotInstanceOf(ValueHolderInterface::class, $wrappedValue); } - /** @return void */ private function dumpLazyServiceProjectAsFilesServiceContainer() { if (class_exists(\LazyServiceProjectAsFilesServiceContainer::class, false)) { From c1c8c2067723be3876e08d5c14b26a539d4d4e54 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 5 Dec 2021 16:41:54 +0100 Subject: [PATCH 21/75] Fix parameter types for ProcessHelper::mustRun() --- src/Symfony/Component/Console/Helper/ProcessHelper.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php index d580357b93ffd..862d09f214522 100644 --- a/src/Symfony/Component/Console/Helper/ProcessHelper.php +++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php @@ -95,10 +95,10 @@ public function run(OutputInterface $output, $cmd, $error = null, callable $call * This is identical to run() except that an exception is thrown if the process * exits with a non-zero exit code. * - * @param string|Process $cmd An instance of Process or a command to run - * @param string|null $error An error message that must be displayed if something went wrong - * @param callable|null $callback A PHP callback to run whenever there is some - * output available on STDOUT or STDERR + * @param array|Process $cmd An instance of Process or a command to run + * @param string|null $error An error message that must be displayed if something went wrong + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR * * @return Process The process that ran * From 47298dcef80beefbfa1f8fedcb49fb2ca6fef42f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 8 Dec 2021 11:40:53 +0100 Subject: [PATCH 22/75] do not call preg_match() on null --- src/Symfony/Component/HttpFoundation/Request.php | 2 +- .../Component/HttpFoundation/Tests/RequestTest.php | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index b6e6c3036b80f..cbe61a152a885 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1502,7 +1502,7 @@ public function isMethodCacheable() public function getProtocolVersion() { if ($this->isFromTrustedProxy()) { - preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via'), $matches); + preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via') ?? '', $matches); if ($matches) { return 'HTTP/'.$matches[2]; diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 798c355d37138..6035dd5d32da9 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -2230,7 +2230,10 @@ public function testProtocolVersion($serverProtocol, $trustedProxy, $via, $expec $request = new Request(); $request->server->set('SERVER_PROTOCOL', $serverProtocol); $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Via', $via); + + if (null !== $via) { + $request->headers->set('Via', $via); + } $this->assertSame($expected, $request->getProtocolVersion()); } @@ -2238,9 +2241,11 @@ public function testProtocolVersion($serverProtocol, $trustedProxy, $via, $expec public function protocolVersionProvider() { return [ - 'untrusted without via' => ['HTTP/2.0', false, '', 'HTTP/2.0'], + 'untrusted with empty via' => ['HTTP/2.0', false, '', 'HTTP/2.0'], + 'untrusted without via' => ['HTTP/2.0', false, null, 'HTTP/2.0'], 'untrusted with via' => ['HTTP/2.0', false, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/2.0'], - 'trusted without via' => ['HTTP/2.0', true, '', 'HTTP/2.0'], + 'trusted with empty via' => ['HTTP/2.0', true, '', 'HTTP/2.0'], + 'trusted without via' => ['HTTP/2.0', true, null, 'HTTP/2.0'], 'trusted with via' => ['HTTP/2.0', true, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'], 'trusted with via and protocol name' => ['HTTP/2.0', true, 'HTTP/1.0 fred, HTTP/1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'], 'trusted with broken via' => ['HTTP/2.0', true, 'HTTP/1^0 foo', 'HTTP/2.0'], From d923d04441661ad6b9cbeb662c3fb05f25c20e8b Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Dec 2021 18:23:29 +0100 Subject: [PATCH 23/75] [DebugBundle] Add missing README --- src/Symfony/Bundle/DebugBundle/README.md | 13 +++++++++++++ src/Symfony/Bundle/DebugBundle/composer.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/DebugBundle/README.md diff --git a/src/Symfony/Bundle/DebugBundle/README.md b/src/Symfony/Bundle/DebugBundle/README.md new file mode 100644 index 0000000000000..bed2f5b6d680a --- /dev/null +++ b/src/Symfony/Bundle/DebugBundle/README.md @@ -0,0 +1,13 @@ +DebugBundle +=========== + +DebugBundle provides a tight integration of the Symfony VarDumper component and +the ServerLogCommand from MonologBridge into the Symfony full-stack framework. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Bundle/DebugBundle/composer.json b/src/Symfony/Bundle/DebugBundle/composer.json index bae6358b2c005..261f3d23c7264 100644 --- a/src/Symfony/Bundle/DebugBundle/composer.json +++ b/src/Symfony/Bundle/DebugBundle/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/debug-bundle", "type": "symfony-bundle", - "description": "Provides a tight integration of the Symfony Debug component into the Symfony full-stack framework", + "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", From c71265b19a0445d5024048a9b8e7b3993ae6304d Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 3 Dec 2021 12:25:20 +0100 Subject: [PATCH 24/75] [HttpClient] Fix handling thrown \Exception in \Generator in MockResponse --- .../HttpClient/Response/MockResponse.php | 27 ++++++----- .../HttpClient/Tests/MockHttpClientTest.php | 45 ++++++++++++++++++- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index c38a0a4f0cd6b..91b917f0458d4 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -38,7 +38,7 @@ class MockResponse implements ResponseInterface /** * @param string|string[]|iterable $body The response body as a string or an iterable of strings, * yielding an empty string simulates an idle timeout, - * exceptions are turned to TransportException + * throwing an exception yields an ErrorChunk * * @see ResponseInterface::getInfo() for possible info, e.g. "response_headers" */ @@ -183,6 +183,9 @@ protected static function perform(ClientState $multi, array &$responses): void $multi->handlesActivity[$id][] = null; $multi->handlesActivity[$id][] = $e; } + } elseif ($chunk instanceof \Throwable) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = $chunk; } else { // Data or timeout chunk $multi->handlesActivity[$id][] = $chunk; @@ -275,16 +278,20 @@ private static function readResponse(self $response, array $options, ResponseInt $body = $mock instanceof self ? $mock->body : $mock->getContent(false); if (!\is_string($body)) { - foreach ($body as $chunk) { - if ('' === $chunk = (string) $chunk) { - // simulate an idle timeout - $response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url'])); - } else { - $response->body[] = $chunk; - $offset += \strlen($chunk); - // "notify" download progress - $onProgress($offset, $dlSize, $response->info); + try { + foreach ($body as $chunk) { + if ('' === $chunk = (string) $chunk) { + // simulate an idle timeout + $response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url'])); + } else { + $response->body[] = $chunk; + $offset += \strlen($chunk); + // "notify" download progress + $onProgress($offset, $dlSize, $response->info); + } } + } catch (\Throwable $e) { + $response->body[] = $e; } } elseif ('' !== $body) { $response->body[] = $body; diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index f97b0cbb363ff..47234d71de0e9 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -11,6 +11,9 @@ namespace Symfony\Component\HttpClient\Tests; +use Symfony\Component\HttpClient\Chunk\DataChunk; +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\NativeHttpClient; @@ -63,6 +66,46 @@ public function invalidResponseFactoryProvider() ]; } + public function testThrowExceptionInBodyGenerator() + { + $mockHttpClient = new MockHttpClient([ + new MockResponse((static function (): \Generator { + yield 'foo'; + throw new TransportException('foo ccc'); + })()), + new MockResponse((static function (): \Generator { + yield 'bar'; + throw new \RuntimeException('bar ccc'); + })()), + ]); + + try { + $mockHttpClient->request('GET', 'https://symfony.com', [])->getContent(); + $this->fail(); + } catch (TransportException $e) { + $this->assertEquals(new TransportException('foo ccc'), $e->getPrevious()); + $this->assertSame('foo ccc', $e->getMessage()); + } + + $chunks = []; + try { + foreach ($mockHttpClient->stream($mockHttpClient->request('GET', 'https://symfony.com', [])) as $chunk) { + $chunks[] = $chunk; + } + $this->fail(); + } catch (TransportException $e) { + $this->assertEquals(new \RuntimeException('bar ccc'), $e->getPrevious()); + $this->assertSame('bar ccc', $e->getMessage()); + } + + $this->assertCount(3, $chunks); + $this->assertEquals(new FirstChunk(0, ''), $chunks[0]); + $this->assertEquals(new DataChunk(0, 'bar'), $chunks[1]); + $this->assertInstanceOf(ErrorChunk::class, $chunks[2]); + $this->assertSame(3, $chunks[2]->getOffset()); + $this->assertSame('bar ccc', $chunks[2]->getError()); + } + protected function getHttpClient(string $testCase): HttpClientInterface { $responses = []; @@ -167,7 +210,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface case 'testResolve': $responses[] = new MockResponse($body, ['response_headers' => $headers]); $responses[] = new MockResponse($body, ['response_headers' => $headers]); - $responses[] = new MockResponse((function () { throw new \Exception('Fake connection timeout'); yield ''; })(), ['response_headers' => $headers]); + $responses[] = new MockResponse((function () { yield ''; })(), ['response_headers' => $headers]); break; case 'testTimeoutOnStream': From 863dd5e24733c272624a0312954ff44ee16b13e6 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 24 Sep 2021 14:47:56 +0200 Subject: [PATCH 25/75] [FrameworkBundle] Fix cache pool configuration with one adapter and one provider --- .../FrameworkBundle/DependencyInjection/Configuration.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index f52bdb7ff5c14..3875db646ff21 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1012,13 +1012,14 @@ private function addCacheSection(ArrayNodeDefinition $rootNode) ->prototype('array') ->fixXmlConfig('adapter') ->beforeNormalization() - ->ifTrue(function ($v) { return (isset($v['adapters']) || \is_array($v['adapter'] ?? null)) && isset($v['provider']); }) - ->thenInvalid('Pool cannot have a "provider" while "adapter" is set to a map') + ->ifTrue(function ($v) { return isset($v['provider']) && \is_array($v['adapters'] ?? $v['adapter'] ?? null) && 1 < \count($v['adapters'] ?? $v['adapter']); }) + ->thenInvalid('Pool cannot have a "provider" while more than one adapter is defined') ->end() ->children() ->arrayNode('adapters') ->performNoDeepMerging() ->info('One or more adapters to chain for creating the pool, defaults to "cache.app".') + ->beforeNormalization()->castToArray()->end() ->beforeNormalization() ->always()->then(function ($values) { if ([0] === array_keys($values) && \is_array($values[0])) { From d05e10a7230e742876da5c3c6f716464d425c24a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 11 Dec 2021 15:02:40 +0100 Subject: [PATCH 26/75] [Mailer] Update docs for sendmail -t --- .../Mailer/Transport/SendmailTransport.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Mailer/Transport/SendmailTransport.php b/src/Symfony/Component/Mailer/Transport/SendmailTransport.php index 4dbe270ad6ed8..c53d72f6974d6 100644 --- a/src/Symfony/Component/Mailer/Transport/SendmailTransport.php +++ b/src/Symfony/Component/Mailer/Transport/SendmailTransport.php @@ -23,10 +23,6 @@ /** * SendmailTransport for sending mail through a Sendmail/Postfix (etc..) binary. * - * Supported modes are -bs and -t, with any additional flags desired. - * It is advised to use -bs mode since error reporting with -t mode is not - * possible. - * * @author Fabien Potencier * @author Chris Corbyn */ @@ -39,11 +35,14 @@ class SendmailTransport extends AbstractTransport /** * Constructor. * - * If using -t mode you are strongly advised to include -oi or -i in the flags. - * For example: /usr/sbin/sendmail -oi -t - * -f flag will be appended automatically if one is not present. + * Supported modes are -bs and -t, with any additional flags desired. * * The recommended mode is "-bs" since it is interactive and failure notifications are hence possible. + * Note that the -t mode does not support error reporting and does not support Bcc properly (the Bcc headers are not removed). + * + * If using -t mode, you are strongly advised to include -oi or -i in the flags (like /usr/sbin/sendmail -oi -t) + * + * -f flag will be appended automatically if one is not present. */ public function __construct(string $command = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { From 29eec31f6f239ac8a17126eebc0bd792e692dc61 Mon Sep 17 00:00:00 2001 From: Kevin SCHNEKENBURGER Date: Thu, 2 Dec 2021 14:20:52 +0100 Subject: [PATCH 27/75] [PropertyAccess] Add tests accessing public (dynamic) properties --- .../PropertyAccess/PropertyAccessor.php | 2 +- .../TestPublicPropertyDynamicallyCreated.php | 21 ++++++++++ .../TestPublicPropertyGetterOnObject.php | 18 +++++++++ ...stPublicPropertyGetterOnObjectMagicGet.php | 25 ++++++++++++ .../Tests/PropertyAccessorTest.php | 38 +++++++++++++++++++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyDynamicallyCreated.php create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObject.php create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObjectMagicGet.php diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 4df3d78913895..fccc09b6c63a6 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -408,7 +408,7 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid } } elseif (self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE]) { $name = $access[self::ACCESS_NAME]; - if (!method_exists($object, '__get') && !isset($object->$name) && !\array_key_exists($name, (array) $object) && (\PHP_VERSION_ID < 70400 || !(new \ReflectionProperty($class, $name))->hasType())) { + if ($access[self::ACCESS_REF] && !isset($object->$name) && !\array_key_exists($name, (array) $object) && (\PHP_VERSION_ID < 70400 || !(new \ReflectionProperty($class, $name))->hasType())) { throw new AccessException(sprintf('The property "%s::$%s" is not initialized.', $class, $name)); } diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyDynamicallyCreated.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyDynamicallyCreated.php new file mode 100644 index 0000000000000..e6df12ae80c15 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyDynamicallyCreated.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +#[\AllowDynamicProperties] +class TestPublicPropertyDynamicallyCreated +{ + public function __construct(string $bar) + { + $this->foo = $bar; + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObject.php new file mode 100644 index 0000000000000..c5e576df76ade --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObject.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestPublicPropertyGetterOnObject +{ + public $a = 'A'; + private $b = 'B'; +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObjectMagicGet.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObjectMagicGet.php new file mode 100644 index 0000000000000..7e992b6265e8f --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestPublicPropertyGetterOnObjectMagicGet.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\PropertyAccess\Tests\Fixtures; + +class TestPublicPropertyGetterOnObjectMagicGet +{ + public $a = 'A'; + private $b = 'B'; + + public function __get($property) + { + if ('b' === $property) { + return $this->b; + } + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 6ca71798d9abe..95c37b4b474c4 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -29,6 +29,9 @@ use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicGet; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassSetValue; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassTypeErrorInsideCall; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestPublicPropertyDynamicallyCreated; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestPublicPropertyGetterOnObject; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestPublicPropertyGetterOnObjectMagicGet; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularAndPluralProps; use Symfony\Component\PropertyAccess\Tests\Fixtures\Ticket5775Object; use Symfony\Component\PropertyAccess\Tests\Fixtures\TypeHinted; @@ -849,4 +852,39 @@ public function testSetterNeedsPublicAccess() $object = new TestClassSetValue(0); $this->propertyAccessor->setValue($object, 'foo', 1); } + + public function testGetPublicProperty() + { + $value = 'A'; + $path = 'a'; + $object = new TestPublicPropertyGetterOnObject(); + + $this->assertSame($value, $this->propertyAccessor->getValue($object, $path)); + } + + public function testGetPrivateProperty() + { + $object = new TestPublicPropertyGetterOnObject(); + + $this->expectException(NoSuchPropertyException::class); + $this->expectExceptionMessageMatches('/.*Neither the property "b" nor one of the methods/'); + $this->propertyAccessor->getValue($object, 'b'); + } + + public function testGetDynamicPublicProperty() + { + $value = 'Bar'; + $path = 'foo'; + $object = new TestPublicPropertyDynamicallyCreated('Bar'); + + $this->assertSame($value, $this->propertyAccessor->getValue($object, $path)); + } + + public function testGetDynamicPublicPropertyWithMagicGetterAllow() + { + $value = 'B'; + $path = 'b'; + $object = new TestPublicPropertyGetterOnObjectMagicGet(); + $this->assertSame($value, $this->propertyAccessor->getValue($object, $path)); + } } From 0ced90cb38f3c03596cf02e265b93b7a5c808fa2 Mon Sep 17 00:00:00 2001 From: Rein Baarsma Date: Thu, 9 Dec 2021 17:18:10 +0100 Subject: [PATCH 28/75] [Process] fixed uppercase ARGC and ARGV should also be skipped --- src/Symfony/Component/Process/Process.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index c0b638aabda1e..39fc4d3c92fb0 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -340,7 +340,7 @@ public function start(callable $callback = null, array $env = []) $envPairs = []; foreach ($env as $k => $v) { - if (false !== $v && 'argc' !== $k && 'argv' !== $k) { + if (false !== $v && false === \in_array($k, ['argc', 'argv', 'ARGC', 'ARGV'], true)) { $envPairs[] = $k.'='.$v; } } @@ -973,8 +973,6 @@ public function addErrorOutput(string $line) /** * Gets the last output time in seconds. - * - * @return float|null The last output time in seconds or null if it isn't started */ public function getLastOutputTime(): ?float { @@ -1503,8 +1501,6 @@ private function resetProcessData() * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) * @param bool $throwException Whether to throw exception in case signal failed * - * @return bool True if the signal was sent successfully, false otherwise - * * @throws LogicException In case the process is not running * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed * @throws RuntimeException In case of failure From acbee81fcb345848d6eb64b8b81bc6b89c7151b7 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 2 Dec 2021 14:13:47 +0100 Subject: [PATCH 29/75] [DependencyInjection] Resolve ChildDefinition in AbstractRecursivePass --- .../Compiler/AbstractRecursivePass.php | 29 +++- .../Compiler/AbstractRecursivePassTest.php | 127 ++++++++++++++++++ 2 files changed, 149 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php index 73ed14a60a42e..ffd3c4e08b819 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\LogicException; @@ -131,25 +132,35 @@ protected function getConstructor(Definition $definition, $required) if ($factory) { [$class, $method] = $factory; + + if ('__construct' === $method) { + throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId)); + } + if ($class instanceof Reference) { - $class = $this->container->findDefinition((string) $class)->getClass(); + $factoryDefinition = $this->container->findDefinition((string) $class); + while ((null === $class = $factoryDefinition->getClass()) && $factoryDefinition instanceof ChildDefinition) { + $factoryDefinition = $this->container->findDefinition($factoryDefinition->getParent()); + } } elseif ($class instanceof Definition) { $class = $class->getClass(); } elseif (null === $class) { $class = $definition->getClass(); } - if ('__construct' === $method) { - throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId)); - } - return $this->getReflectionMethod(new Definition($class), $method); } - $class = $definition->getClass(); + while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) { + $definition = $this->container->findDefinition($definition->getParent()); + } try { if (!$r = $this->container->getReflectionClass($class)) { + if (null === $class) { + throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId)); + } + throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class)); } } catch (\ReflectionException $e) { @@ -179,7 +190,11 @@ protected function getReflectionMethod(Definition $definition, $method) return $this->getConstructor($definition, true); } - if (!$class = $definition->getClass()) { + while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) { + $definition = $this->container->findDefinition($definition->getParent()); + } + + if (null === $class) { throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php new file mode 100644 index 0000000000000..aecdc9a5a2169 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AbstractRecursivePassTest.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Compiler; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy; + +class AbstractRecursivePassTest extends TestCase +{ + public function testGetConstructorResolvesFactoryChildDefinitionsClass() + { + $container = new ContainerBuilder(); + $container->setParameter('factory_dummy_class', FactoryDummy::class); + $container + ->register('parent', '%factory_dummy_class%') + ->setAbstract(true); + $container->setDefinition('child', new ChildDefinition('parent')); + $container + ->register('foo', \stdClass::class) + ->setFactory([new Reference('child'), 'createFactory']); + + $pass = new class() extends AbstractRecursivePass { + public $actual; + + protected function processValue($value, $isRoot = false) + { + if ($value instanceof Definition && 'foo' === $this->currentId) { + $this->actual = $this->getConstructor($value, true); + } + + return parent::processValue($value, $isRoot); + } + }; + $pass->process($container); + + $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual); + $this->assertSame(FactoryDummy::class, $pass->actual->class); + } + + public function testGetConstructorResolvesChildDefinitionsClass() + { + $container = new ContainerBuilder(); + $container + ->register('parent', Bar::class) + ->setAbstract(true); + $container->setDefinition('foo', new ChildDefinition('parent')); + + $pass = new class() extends AbstractRecursivePass { + public $actual; + + protected function processValue($value, $isRoot = false) + { + if ($value instanceof Definition && 'foo' === $this->currentId) { + $this->actual = $this->getConstructor($value, true); + } + + return parent::processValue($value, $isRoot); + } + }; + $pass->process($container); + + $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual); + $this->assertSame(Bar::class, $pass->actual->class); + } + + public function testGetReflectionMethodResolvesChildDefinitionsClass() + { + $container = new ContainerBuilder(); + $container + ->register('parent', Bar::class) + ->setAbstract(true); + $container->setDefinition('foo', new ChildDefinition('parent')); + + $pass = new class() extends AbstractRecursivePass { + public $actual; + + protected function processValue($value, $isRoot = false) + { + if ($value instanceof Definition && 'foo' === $this->currentId) { + $this->actual = $this->getReflectionMethod($value, 'create'); + } + + return parent::processValue($value, $isRoot); + } + }; + $pass->process($container); + + $this->assertInstanceOf(\ReflectionMethod::class, $pass->actual); + $this->assertSame(Bar::class, $pass->actual->class); + } + + public function testGetConstructorDefinitionNoClass() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Invalid service "foo": the class is not set.'); + + $container = new ContainerBuilder(); + $container->register('foo'); + + (new class() extends AbstractRecursivePass { + protected function processValue($value, $isRoot = false) + { + if ($value instanceof Definition && 'foo' === $this->currentId) { + $this->getConstructor($value, true); + } + + return parent::processValue($value, $isRoot); + } + })->process($container); + } +} From d39c07e859d3fcc2a06169ae32bd14e21d4729b3 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 17 Oct 2020 13:24:58 +0200 Subject: [PATCH 30/75] CI for macOS --- .github/workflows/unit-tests.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9671caa0ed004..d35f38d52d087 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -12,7 +12,6 @@ jobs: tests: name: Tests - runs-on: Ubuntu-20.04 env: extensions: amqp,apcu,igbinary,intl,mbstring,memcached,redis-5.3.4 @@ -21,15 +20,24 @@ jobs: matrix: include: - php: '7.2' + os: ubuntu-20.04 - php: '7.4' + os: ubuntu-20.04 + - php: '8.0' + os: macos-11 - php: '8.0' mode: high-deps + os: ubuntu-20.04 - php: '8.1' mode: low-deps + os: ubuntu-20.04 - php: '8.2' mode: experimental + os: ubuntu-20.04 fail-fast: false + runs-on: "${{ matrix.os }}" + steps: - name: Checkout uses: actions/checkout@v2 @@ -50,6 +58,11 @@ jobs: extensions: "${{ env.extensions }}" tools: flex + - name: Install Homebrew packages + if: "matrix.os == 'macos-11'" + run: | + brew install parallel + - name: Configure environment run: | git config --global user.email "" @@ -61,11 +74,11 @@ jobs: ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" echo COLUMNS=120 >> $GITHUB_ENV - echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV + echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) - SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+') + SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | cut -d "'" -f2 | cut -d '.' -f 1-2) SYMFONY_FEATURE_BRANCH=$(curl -s https://raw.githubusercontent.com/symfony/recipes/flex/main/index.json | jq -r '.versions."dev-name"') # Install the phpunit-bridge from a PR if required @@ -111,9 +124,9 @@ jobs: # Skip the phpunit-bridge on bugfix-branches when not in *-deps mode if [[ ! "${{ matrix.mode }}" = *-deps && $SYMFONY_VERSION != $SYMFONY_FEATURE_BRANCH ]]; then - echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h ') >> $GITHUB_ENV + echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' | xargs -I{} dirname {}) >> $GITHUB_ENV else - echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h ') >> $GITHUB_ENV + echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist | xargs -I{} dirname {}) >> $GITHUB_ENV fi # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one @@ -135,7 +148,7 @@ jobs: echo "::endgroup::" - name: Patch return types - if: "matrix.php == '8.1' && ! matrix.mode" + if: "matrix.php == '8.1' && ! matrix.mode && matrix.os == 'ubuntu-20.04'" run: | sed -i 's/"\*\*\/Tests\/"//' composer.json composer install -q --optimize-autoloader From f35a6ad77e770b57501b0e4afb7ff80a1a4e79ea Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 6 Dec 2021 19:53:06 +0100 Subject: [PATCH 31/75] [HttpClient] Double check if handle is complete --- src/Symfony/Component/HttpClient/Response/CurlResponse.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index ae596ba7eefd1..c22a593f0712f 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -277,6 +277,9 @@ private static function perform(ClientState $multi, array &$responses = null): v while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($multi->handle, $active)); while ($info = curl_multi_info_read($multi->handle)) { + if (\CURLMSG_DONE !== $info['msg']) { + continue; + } $result = $info['result']; $id = (int) $ch = $info['handle']; $waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0'; From 6f66dec437abe04f7d587ff37361db758eb1d4f3 Mon Sep 17 00:00:00 2001 From: divinity76 Date: Thu, 9 Dec 2021 14:42:01 +0100 Subject: [PATCH 32/75] [HttpClient] Don't ignore errors from curl_multi_exec() --- src/Symfony/Component/HttpClient/Response/CurlResponse.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index ae596ba7eefd1..a790a0b081843 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -274,7 +274,11 @@ private static function perform(ClientState $multi, array &$responses = null): v try { self::$performing = true; $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($multi->handle, $active)); + while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))); + + if (\CURLM_OK !== $err) { + throw new TransportException(curl_multi_strerror($err)); + } while ($info = curl_multi_info_read($multi->handle)) { $result = $info['result']; From 8f3bdeb359c90d880c4302ecc8681023526e6c71 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 11 Dec 2021 17:29:22 +0100 Subject: [PATCH 33/75] [HttpClient] Don't reset timeout counter when initializing requests --- .../HttpClient/Response/CurlResponse.php | 1 + .../HttpClient/Response/NativeResponse.php | 1 + .../HttpClient/Response/ResponseTrait.php | 8 ++--- .../HttpClient/Tests/MockHttpClientTest.php | 1 + .../HttpClient/Tests/NativeHttpClientTest.php | 5 +++ .../HttpClient/Test/HttpClientTestCase.php | 33 +++++++++++++++++++ 6 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index ae596ba7eefd1..4ee683e9ec5a2 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -148,6 +148,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, }; // Schedule the request in a non-blocking way + $multi->lastTimeout = null; $multi->openHandles[$id] = [$ch, $options]; curl_multi_add_handle($multi->handle, $ch); diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index e87402f0ad8dc..c186900c5e658 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -183,6 +183,7 @@ private function open(): void return; } + $this->multi->lastTimeout = null; $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->onProgress, &$this->remaining, &$this->info]; } diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 0f041d4d02d21..b70c1e885a869 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -233,15 +233,15 @@ abstract protected static function perform(ClientState $multi, array &$responses */ abstract protected static function select(ClientState $multi, float $timeout): int; - private static function initialize(self $response, float $timeout = null): void + private static function initialize(self $response): void { if (null !== $response->info['error']) { throw new TransportException($response->info['error']); } try { - if (($response->initializer)($response, $timeout)) { - foreach (self::stream([$response], $timeout) as $chunk) { + if (($response->initializer)($response, -0.0)) { + foreach (self::stream([$response], -0.0) as $chunk) { if ($chunk->isFirst()) { break; } @@ -304,7 +304,7 @@ private function doDestruct() $this->shouldBuffer = true; if ($this->initializer && null === $this->info['error']) { - self::initialize($this, -0.0); + self::initialize($this); $this->checkStatusCode(); } } diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index 47234d71de0e9..d56f20aec206d 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -157,6 +157,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface $this->markTestSkipped('Real transport required'); break; + case 'testTimeoutOnInitialize': case 'testTimeoutOnDestruct': $this->markTestSkipped('Real transport required'); break; diff --git a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php index 2f76cc91c609f..a03b2db8c99b4 100644 --- a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php @@ -26,6 +26,11 @@ public function testInformationalResponseStream() $this->markTestSkipped('NativeHttpClient doesn\'t support informational status codes.'); } + public function testTimeoutOnInitialize() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); + } + public function testTimeoutOnDestruct() { $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 1062c7c024b4d..7ebf055d75701 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -810,6 +810,39 @@ public function testTimeoutWithActiveConcurrentStream() } } + public function testTimeoutOnInitialize() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + foreach ($responses as $response) { + try { + $response->getContent(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + $responses = []; + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); From 30c3913eb24beb5237fff832173ab512512b48cb Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 9 Dec 2021 17:15:29 +0100 Subject: [PATCH 34/75] [Config] In XmlUtils, avoid converting from octal every string starting with a 0 --- .../Component/Config/Tests/Util/XmlUtilsTest.php | 2 ++ src/Symfony/Component/Config/Util/XmlUtils.php | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php index a7a8ae980d597..9319b98ea26a8 100644 --- a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php +++ b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php @@ -169,6 +169,8 @@ public function getDataForPhpize(): array [1, '1'], [-1, '-1'], [0777, '0777'], + [-511, '-0777'], + ['0877', '0877'], [255, '0xFF'], [100.0, '1e2'], [-120.0, '-1.2E2'], diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php index 41fb5a9e6259b..e032414944071 100644 --- a/src/Symfony/Component/Config/Util/XmlUtils.php +++ b/src/Symfony/Component/Config/Util/XmlUtils.php @@ -236,15 +236,11 @@ public static function phpize($value) case 'null' === $lowercaseValue: return null; case ctype_digit($value): - $raw = $value; - $cast = (int) $value; - - return '0' == $value[0] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw); case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)): $raw = $value; $cast = (int) $value; - return '0' == $value[1] ? octdec($value) : (($raw === (string) $cast) ? $cast : $raw); + return self::isOctal($value) ? \intval($value, 8) : (($raw === (string) $cast) ? $cast : $raw); case 'true' === $lowercaseValue: return true; case 'false' === $lowercaseValue: @@ -281,4 +277,13 @@ protected static function getXmlErrors($internalErrors) return $errors; } + + private static function isOctal(string $str): bool + { + if ('-' === $str[0]) { + $str = substr($str, 1); + } + + return $str === '0'.decoct(\intval($str, 8)); + } } From f5c2f53eec615ca2a5dc7d8113e35a587a186082 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Wed, 8 Dec 2021 23:06:48 +0330 Subject: [PATCH 35/75] [Form] Improve Persian (Farsi) Translation For Forms --- .../Form/Resources/translations/validators.fa.xlf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf index 4ed719917549d..4a98eea8eb314 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf @@ -24,7 +24,7 @@ The selected choice is invalid. - گزینه‌ی انتخاب‌شده نامعتبر است. + گزینه‌ انتخاب‌ شده نامعتبر است. The collection is invalid. @@ -44,7 +44,7 @@ Please choose a valid date interval. - لطفاً یک بازه‌ی زمانی معتبر انتخاب کنید. + لطفاً یک بازه‌ زمانی معتبر انتخاب کنید. Please enter a valid date and time. @@ -124,15 +124,15 @@ Please select a valid option. - لطفاً یک گزینه‌ی معتبر انتخاب کنید. + لطفاً یک گزینه‌ معتبر انتخاب کنید. Please select a valid range. - لطفاً یک محدوده‌ی معتبر انتخاب کنید. + لطفاً یک محدوده‌ معتبر انتخاب کنید. Please enter a valid week. - لطفاً یک هفته‌ی معتبر وارد کنید. + لطفاً یک هفته‌ معتبر وارد کنید. From c0602fde4e172a3f68101409c8f3dbda9894b145 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 13 Dec 2021 17:50:20 +0100 Subject: [PATCH 36/75] [HttpClient] Fix closing curl-multi handle too early on destruct --- .../Component/HttpClient/CurlHttpClient.php | 114 +++--------------- .../HttpClient/Internal/CurlClientState.php | 98 ++++++++++++--- 2 files changed, 99 insertions(+), 113 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 119c45924e4cd..c925bbf8a34ca 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpClient; use Psr\Log\LoggerAwareInterface; -use Psr\Log\LoggerAwareTrait; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Exception\InvalidArgumentException; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Internal\CurlClientState; @@ -35,13 +35,17 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface { use HttpClientTrait; - use LoggerAwareTrait; private $defaultOptions = self::OPTIONS_DEFAULTS + [ 'auth_ntlm' => null, // array|string - an array containing the username as first value, and optionally the // password as the second one; or string like username:password - enabling NTLM auth ]; + /** + * @var LoggerInterface|null + */ + private $logger; + /** * An internal object to share state between the client and its responses. * @@ -49,8 +53,6 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, */ private $multi; - private static $curlVersion; - /** * @param array $defaultOptions Default request's options * @param int $maxHostConnections The maximum number of connections to a single host @@ -70,33 +72,12 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); } - $this->multi = new CurlClientState(); - self::$curlVersion = self::$curlVersion ?? curl_version(); - - // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order - if (\defined('CURLPIPE_MULTIPLEX')) { - curl_multi_setopt($this->multi->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX); - } - if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) { - $maxHostConnections = curl_multi_setopt($this->multi->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections; - } - if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) { - curl_multi_setopt($this->multi->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections); - } - - // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535 - if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) { - return; - } - - // HTTP/2 push crashes before curl 7.61 - if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > self::$curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & self::$curlVersion['features'])) { - return; - } + $this->multi = new CurlClientState($maxHostConnections, $maxPendingPushes); + } - curl_multi_setopt($this->multi->handle, \CURLMOPT_PUSHFUNCTION, function ($parent, $pushed, array $requestHeaders) use ($maxPendingPushes) { - return $this->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes); - }); + public function setLogger(LoggerInterface $logger): void + { + $this->logger = $this->multi->logger = $logger; } /** @@ -142,7 +123,7 @@ public function request(string $method, string $url, array $options = []): Respo $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0; } elseif (1.1 === (float) $options['http_version']) { $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; - } elseif (\defined('CURL_VERSION_HTTP2') && (\CURL_VERSION_HTTP2 & self::$curlVersion['features']) && ('https:' === $scheme || 2.0 === (float) $options['http_version'])) { + } elseif (\defined('CURL_VERSION_HTTP2') && (\CURL_VERSION_HTTP2 & CurlClientState::$curlVersion['features']) && ('https:' === $scheme || 2.0 === (float) $options['http_version'])) { $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0; } @@ -185,11 +166,10 @@ public function request(string $method, string $url, array $options = []): Respo $this->multi->dnsCache->evictions = []; $port = parse_url($authority, \PHP_URL_PORT) ?: ('http:' === $scheme ? 80 : 443); - if ($resolve && 0x072A00 > self::$curlVersion['version_number']) { + if ($resolve && 0x072A00 > CurlClientState::$curlVersion['version_number']) { // DNS cache removals require curl 7.42 or higher // On lower versions, we have to create a new multi handle - curl_multi_close($this->multi->handle); - $this->multi->handle = (new self())->multi->handle; + $this->multi->reset(); } foreach ($options['resolve'] as $host => $ip) { @@ -312,7 +292,7 @@ public function request(string $method, string $url, array $options = []): Respo } } - return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host), self::$curlVersion['version_number']); + return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host), CurlClientState::$curlVersion['version_number']); } /** @@ -328,7 +308,8 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) { $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)); + while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)) { + } } return new ResponseStream(CurlResponse::stream($responses, $timeout)); @@ -336,70 +317,9 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa public function reset() { - $this->multi->logger = $this->logger; $this->multi->reset(); } - /** - * @return array - */ - public function __sleep() - { - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); - } - - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); - } - - public function __destruct() - { - $this->multi->logger = $this->logger; - } - - private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int - { - $headers = []; - $origin = curl_getinfo($parent, \CURLINFO_EFFECTIVE_URL); - - foreach ($requestHeaders as $h) { - if (false !== $i = strpos($h, ':', 1)) { - $headers[substr($h, 0, $i)][] = substr($h, 1 + $i); - } - } - - if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) { - $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); - - return \CURL_PUSH_DENY; - } - - $url = $headers[':scheme'][0].'://'.$headers[':authority'][0]; - - // curl before 7.65 doesn't validate the pushed ":authority" header, - // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, - // ignoring domains mentioned as alt-name in the certificate for now (same as curl). - if (!str_starts_with($origin, $url.'/')) { - $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); - - return \CURL_PUSH_DENY; - } - - if ($maxPendingPushes <= \count($this->multi->pushedResponses)) { - $fifoUrl = key($this->multi->pushedResponses); - unset($this->multi->pushedResponses[$fifoUrl]); - $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); - } - - $url .= $headers[':path'][0]; - $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url)); - - $this->multi->pushedResponses[$url] = new PushedResponse(new CurlResponse($this->multi, $pushed), $headers, $this->multi->openHandles[(int) $parent][1] ?? [], $pushed); - - return \CURL_PUSH_OK; - } - /** * Accepts pushed responses only if their headers related to authentication match the request. */ diff --git a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php index a4c596eb45d3f..2ca6e8ddee48b 100644 --- a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpClient\Internal; use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Response\CurlResponse; /** * Internal representation of the cURL client's state. @@ -31,10 +32,44 @@ final class CurlClientState extends ClientState /** @var LoggerInterface|null */ public $logger; - public function __construct() + public static $curlVersion; + + private $maxHostConnections; + private $maxPendingPushes; + + public function __construct(int $maxHostConnections, int $maxPendingPushes) { + self::$curlVersion = self::$curlVersion ?? curl_version(); + $this->handle = curl_multi_init(); $this->dnsCache = new DnsCache(); + $this->maxHostConnections = $maxHostConnections; + $this->maxPendingPushes = $maxPendingPushes; + + // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order + if (\defined('CURLPIPE_MULTIPLEX')) { + curl_multi_setopt($this->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX); + } + if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) { + $maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections; + } + if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) { + curl_multi_setopt($this->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections); + } + + // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535 + if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) { + return; + } + + // HTTP/2 push crashes before curl 7.61 + if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > self::$curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & self::$curlVersion['features'])) { + return; + } + + curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, function ($parent, $pushed, array $requestHeaders) use ($maxPendingPushes) { + return $this->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes); + }); } public function reset() @@ -54,32 +89,63 @@ public function reset() curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, null); } - $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->handle, $active)); + $this->__construct($this->maxHostConnections, $this->maxPendingPushes); } + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() + { foreach ($this->openHandles as [$ch]) { if (\is_resource($ch) || $ch instanceof \CurlHandle) { curl_setopt($ch, \CURLOPT_VERBOSE, false); } } - - curl_multi_close($this->handle); - $this->handle = curl_multi_init(); } - public function __sleep(): array + private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int { - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); - } + $headers = []; + $origin = curl_getinfo($parent, \CURLINFO_EFFECTIVE_URL); - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); - } + foreach ($requestHeaders as $h) { + if (false !== $i = strpos($h, ':', 1)) { + $headers[substr($h, 0, $i)][] = substr($h, 1 + $i); + } + } - public function __destruct() - { - $this->reset(); + if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) { + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); + + return \CURL_PUSH_DENY; + } + + $url = $headers[':scheme'][0].'://'.$headers[':authority'][0]; + + // curl before 7.65 doesn't validate the pushed ":authority" header, + // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, + // ignoring domains mentioned as alt-name in the certificate for now (same as curl). + if (!str_starts_with($origin, $url.'/')) { + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); + + return \CURL_PUSH_DENY; + } + + if ($maxPendingPushes <= \count($this->pushedResponses)) { + $fifoUrl = key($this->pushedResponses); + unset($this->pushedResponses[$fifoUrl]); + $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); + } + + $url .= $headers[':path'][0]; + $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url)); + + $this->pushedResponses[$url] = new PushedResponse(new CurlResponse($this, $pushed), $headers, $this->openHandles[(int) $parent][1] ?? [], $pushed); + + return \CURL_PUSH_OK; } } From 276ef95044305c24efbc5bf9f4271fe72f55821c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Dec 2021 15:09:57 +0100 Subject: [PATCH 37/75] [HttpClient] minor change --- src/Symfony/Component/HttpClient/Internal/CurlClientState.php | 1 + src/Symfony/Component/HttpClient/Response/CurlResponse.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php index 2ca6e8ddee48b..ac3a29c89c02c 100644 --- a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php @@ -89,6 +89,7 @@ public function reset() curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, null); } + curl_multi_close($this->handle); $this->__construct($this->maxHostConnections, $this->maxPendingPushes); } } diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 0877a0167f015..341617f701f5c 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -275,7 +275,8 @@ private static function perform(ClientState $multi, array &$responses = null): v try { self::$performing = true; $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))); + while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))) { + } if (\CURLM_OK !== $err) { throw new TransportException(curl_multi_strerror($err)); From d793d03cb6e8ffdfa9ec7ec19b68767447eb3b26 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Dec 2021 17:18:11 +0100 Subject: [PATCH 38/75] [HttpClient] Fix dealing with "HTTP/1.1 000 " responses --- .../Component/HttpClient/Response/CurlResponse.php | 11 ++--------- .../Component/HttpClient/Response/ResponseTrait.php | 6 +----- .../Component/HttpClient/Tests/MockHttpClientTest.php | 7 +++++++ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 341617f701f5c..cbd70e9e07ce4 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -340,15 +340,8 @@ private static function parseHeaderLine($ch, string $data, array &$info, array & } if ('' !== $data) { - try { - // Regular header line: add it to the list - self::addResponseHeaders([$data], $info, $headers); - } catch (TransportException $e) { - $multi->handlesActivity[$id][] = null; - $multi->handlesActivity[$id][] = $e; - - return \strlen($data); - } + // Regular header line: add it to the list + self::addResponseHeaders([$data], $info, $headers); if (!str_starts_with($data, 'HTTP/')) { if (0 === stripos($data, 'Location:')) { diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index b70c1e885a869..2efa82b477683 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -260,7 +260,7 @@ private static function initialize(self $response): void private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers, string &$debug = ''): void { foreach ($responseHeaders as $h) { - if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([1-9]\d\d)(?: |$)#', $h, $m)) { + if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? (\d\d\d)(?: |$)#', $h, $m)) { if ($headers) { $debug .= "< \r\n"; $headers = []; @@ -275,10 +275,6 @@ private static function addResponseHeaders(array $responseHeaders, array &$info, } $debug .= "< \r\n"; - - if (!$info['http_code']) { - throw new TransportException(sprintf('Invalid or missing HTTP status line for "%s".', implode('', $info['url']))); - } } private function checkStatusCode() diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index d56f20aec206d..714e35eaf21de 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -66,6 +66,13 @@ public function invalidResponseFactoryProvider() ]; } + public function testZeroStatusCode() + { + $client = new MockHttpClient(new MockResponse('', ['response_headers' => ['HTTP/1.1 000 ']])); + $response = $client->request('GET', 'https://foo.bar'); + $this->assertSame(0, $response->getStatusCode()); + } + public function testThrowExceptionInBodyGenerator() { $mockHttpClient = new MockHttpClient([ From 54efeab581d49b277f65db60428598f63475f8bb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Dec 2021 17:35:14 +0100 Subject: [PATCH 39/75] [Cache] workaround transient test on M1 --- src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 3ff73aeab965f..a72ae663f09d6 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -118,7 +118,7 @@ public function testGetMetadata() $metadata = $item->getMetadata(); $this->assertArrayHasKey(CacheItem::METADATA_CTIME, $metadata); - $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 10); + $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 150); $this->assertArrayHasKey(CacheItem::METADATA_EXPIRY, $metadata); $this->assertEqualsWithDelta(9 + time(), $metadata[CacheItem::METADATA_EXPIRY], 1); } From 6e529608c062f41f16f19adfbe7355ba72deeb3d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Dec 2021 15:43:09 +0100 Subject: [PATCH 40/75] [HttpClient] fix monitoring responses issued before reset() --- .../Component/HttpClient/CurlHttpClient.php | 4 +- .../HttpClient/Internal/CurlClientState.php | 57 ++++++++-------- .../HttpClient/Response/CurlResponse.php | 66 +++++++++++-------- .../HttpClient/Tests/CurlHttpClientTest.php | 15 ++++- 4 files changed, 79 insertions(+), 63 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index c925bbf8a34ca..f30c3435205c0 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -306,9 +306,9 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of CurlResponse objects, "%s" given.', __METHOD__, \is_object($responses) ? \get_class($responses) : \gettype($responses))); } - if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) { + if (\is_resource($mh = $this->multi->handles[0] ?? null) || $mh instanceof \CurlMultiHandle) { $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)) { + while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($mh, $active)) { } } diff --git a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php index ac3a29c89c02c..c0782331ad52f 100644 --- a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php @@ -23,8 +23,8 @@ */ final class CurlClientState extends ClientState { - /** @var \CurlMultiHandle|resource */ - public $handle; + /** @var array<\CurlMultiHandle|resource> */ + public $handles = []; /** @var PushedResponse[] */ public $pushedResponses = []; /** @var DnsCache */ @@ -41,20 +41,20 @@ public function __construct(int $maxHostConnections, int $maxPendingPushes) { self::$curlVersion = self::$curlVersion ?? curl_version(); - $this->handle = curl_multi_init(); + array_unshift($this->handles, $mh = curl_multi_init()); $this->dnsCache = new DnsCache(); $this->maxHostConnections = $maxHostConnections; $this->maxPendingPushes = $maxPendingPushes; // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order if (\defined('CURLPIPE_MULTIPLEX')) { - curl_multi_setopt($this->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX); + curl_multi_setopt($mh, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX); } if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) { - $maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections; + $maxHostConnections = curl_multi_setopt($mh, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections; } if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) { - curl_multi_setopt($this->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections); + curl_multi_setopt($mh, \CURLMOPT_MAXCONNECTS, $maxHostConnections); } // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535 @@ -67,45 +67,40 @@ public function __construct(int $maxHostConnections, int $maxPendingPushes) return; } - curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, function ($parent, $pushed, array $requestHeaders) use ($maxPendingPushes) { - return $this->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes); + // Clone to prevent a circular reference + $multi = clone $this; + $multi->handles = [$mh]; + $multi->pushedResponses = &$this->pushedResponses; + $multi->logger = &$this->logger; + $multi->handlesActivity = &$this->handlesActivity; + $multi->openHandles = &$this->openHandles; + $multi->lastTimeout = &$this->lastTimeout; + + curl_multi_setopt($mh, \CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes) { + return $multi->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes); }); } public function reset() { - if ($this->logger) { - foreach ($this->pushedResponses as $url => $response) { - $this->logger->debug(sprintf('Unused pushed response: "%s"', $url)); + foreach ($this->pushedResponses as $url => $response) { + $this->logger && $this->logger->debug(sprintf('Unused pushed response: "%s"', $url)); + + foreach ($this->handles as $mh) { + curl_multi_remove_handle($mh, $response->handle); } + curl_close($response->handle); } $this->pushedResponses = []; $this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals; $this->dnsCache->removals = $this->dnsCache->hostnames = []; - if (\is_resource($this->handle) || $this->handle instanceof \CurlMultiHandle) { - if (\defined('CURLMOPT_PUSHFUNCTION')) { - curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, null); - } - - curl_multi_close($this->handle); - $this->__construct($this->maxHostConnections, $this->maxPendingPushes); + if (\defined('CURLMOPT_PUSHFUNCTION')) { + curl_multi_setopt($this->handles[0], \CURLMOPT_PUSHFUNCTION, null); } - } - - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); - } - public function __destruct() - { - foreach ($this->openHandles as [$ch]) { - if (\is_resource($ch) || $ch instanceof \CurlHandle) { - curl_setopt($ch, \CURLOPT_VERBOSE, false); - } - } + $this->__construct($this->maxHostConnections, $this->maxPendingPushes); } private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 341617f701f5c..04e21f8aeb966 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -150,7 +150,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, // Schedule the request in a non-blocking way $multi->lastTimeout = null; $multi->openHandles[$id] = [$ch, $options]; - curl_multi_add_handle($multi->handle, $ch); + curl_multi_add_handle($multi->handles[0], $ch); $this->canary = new Canary(static function () use ($ch, $multi, $id) { unset($multi->openHandles[$id], $multi->handlesActivity[$id]); @@ -160,7 +160,9 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, return; } - curl_multi_remove_handle($multi->handle, $ch); + foreach ($multi->handles as $mh) { + curl_multi_remove_handle($mh, $ch); + } curl_setopt_array($ch, [ \CURLOPT_NOPROGRESS => true, \CURLOPT_PROGRESSFUNCTION => null, @@ -242,7 +244,7 @@ public function __destruct() */ private static function schedule(self $response, array &$runningResponses): void { - if (isset($runningResponses[$i = (int) $response->multi->handle])) { + if (isset($runningResponses[$i = (int) $response->multi->handles[0]])) { $runningResponses[$i][1][$response->id] = $response; } else { $runningResponses[$i] = [$response->multi, [$response->id => $response]]; @@ -274,39 +276,47 @@ private static function perform(ClientState $multi, array &$responses = null): v try { self::$performing = true; - $active = 0; - while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))) { - } - - if (\CURLM_OK !== $err) { - throw new TransportException(curl_multi_strerror($err)); - } - while ($info = curl_multi_info_read($multi->handle)) { - if (\CURLMSG_DONE !== $info['msg']) { - continue; + foreach ($multi->handles as $i => $mh) { + $active = 0; + while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($mh, $active))) { } - $result = $info['result']; - $id = (int) $ch = $info['handle']; - $waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0'; - if (\in_array($result, [\CURLE_SEND_ERROR, \CURLE_RECV_ERROR, /*CURLE_HTTP2*/ 16, /*CURLE_HTTP2_STREAM*/ 92], true) && $waitFor[1] && 'C' !== $waitFor[0]) { - curl_multi_remove_handle($multi->handle, $ch); - $waitFor[1] = (string) ((int) $waitFor[1] - 1); // decrement the retry counter - curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor); - curl_setopt($ch, \CURLOPT_FORBID_REUSE, true); + if (\CURLM_OK !== $err) { + throw new TransportException(curl_multi_strerror($err)); + } - if (0 === curl_multi_add_handle($multi->handle, $ch)) { + while ($info = curl_multi_info_read($mh)) { + if (\CURLMSG_DONE !== $info['msg']) { continue; } - } + $result = $info['result']; + $id = (int) $ch = $info['handle']; + $waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0'; + + if (\in_array($result, [\CURLE_SEND_ERROR, \CURLE_RECV_ERROR, /*CURLE_HTTP2*/ 16, /*CURLE_HTTP2_STREAM*/ 92], true) && $waitFor[1] && 'C' !== $waitFor[0]) { + curl_multi_remove_handle($mh, $ch); + $waitFor[1] = (string) ((int) $waitFor[1] - 1); // decrement the retry counter + curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor); + curl_setopt($ch, \CURLOPT_FORBID_REUSE, true); + + if (0 === curl_multi_add_handle($mh, $ch)) { + continue; + } + } + + if (\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) { + $multi->handlesActivity[$id][] = new FirstChunk(); + } - if (\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) { - $multi->handlesActivity[$id][] = new FirstChunk(); + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) ? null : new TransportException(sprintf('%s for "%s".', curl_strerror($result), curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); } - $multi->handlesActivity[$id][] = null; - $multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) ? null : new TransportException(sprintf('%s for "%s".', curl_strerror($result), curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); + if (!$active && 0 < $i) { + curl_multi_close($mh); + unset($multi->handles[$i]); + } } } finally { self::$performing = false; @@ -325,7 +335,7 @@ private static function select(ClientState $multi, float $timeout): int $timeout = min($timeout, 0.01); } - return curl_multi_select($multi->handle, $timeout); + return curl_multi_select($multi->handles[array_key_last($multi->handles)], $timeout); } /** diff --git a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php index 34e4b38e722df..c8bb52cd139d2 100644 --- a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php @@ -143,9 +143,20 @@ public function testHandleIsReinitOnReset() $r = new \ReflectionProperty($httpClient, 'multi'); $r->setAccessible(true); $clientState = $r->getValue($httpClient); - $initialHandleId = (int) $clientState->handle; + $initialHandleId = (int) $clientState->handles[0]; $httpClient->reset(); - self::assertNotSame($initialHandleId, (int) $clientState->handle); + self::assertNotSame($initialHandleId, (int) $clientState->handles[0]); + } + + public function testProcessAfterReset() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://127.0.0.1:8057/json'); + + $client->reset(); + + $this->assertSame(['application/json'], $response->getHeaders()['content-type']); } private function getVulcainClient(): CurlHttpClient From 26d51e8f25182777320352a2515d75352062aa89 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 15 Dec 2021 10:43:29 +0100 Subject: [PATCH 41/75] Fix CI on macos-11 --- .github/workflows/unit-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index d35f38d52d087..d5f6c8f7c6cbb 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -148,7 +148,7 @@ jobs: echo "::endgroup::" - name: Patch return types - if: "matrix.php == '8.1' && ! matrix.mode && matrix.os == 'ubuntu-20.04'" + if: "matrix.php == '8.1' && ! matrix.mode && matrix.os != 'macos-11'" run: | sed -i 's/"\*\*\/Tests\/"//' composer.json composer install -q --optimize-autoloader @@ -222,7 +222,7 @@ jobs: [[ ! $X ]] || (exit 1) - name: Run tests with SIGCHLD enabled PHP - if: "matrix.php == '7.2' && ! matrix.mode" + if: "matrix.php == '7.2' && ! matrix.mode && matrix.os != 'macos-11'" run: | mkdir build cd build From b1426b4df886acbe22dbfb5473cfa0f4092fc109 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 15 Dec 2021 11:32:07 +0100 Subject: [PATCH 42/75] Try making tests a bit less transient --- .appveyor.yml | 4 ++-- .../Component/Console/Tests/ApplicationTest.php | 6 ++++++ .../Iterator/RecursiveDirectoryIteratorTest.php | 8 ++++---- .../Component/Lock/Tests/Store/PdoDbalStoreTest.php | 2 +- .../Contracts/HttpClient/Test/HttpClientTestCase.php | 12 ++++++------ 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7fe5b25c3686e..cbb0098bcffbe 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -60,7 +60,7 @@ test_script: - SET SYMFONY_PHPUNIT_SKIPPED_TESTS=phpunit.skipped - copy /Y c:\php\php.ini-min c:\php\php.ini - IF %APPVEYOR_REPO_BRANCH:~-2% neq .x (rm -Rf src\Symfony\Bridge\PhpUnit) - - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data || SET X=!errorlevel! + - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel! - copy /Y c:\php\php.ini-max c:\php\php.ini - - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data || SET X=!errorlevel! + - php phpunit src\Symfony --exclude-group tty,benchmark,intl-data,network,transient-on-windows || SET X=!errorlevel! - exit %X% diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 1634c01991b0a..6e9953dd27a7b 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -894,6 +894,9 @@ public function testRenderExceptionLineBreaks() $this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks'); } + /** + * @group transient-on-windows + */ public function testRenderAnonymousException() { $application = new Application(); @@ -917,6 +920,9 @@ public function testRenderAnonymousException() $this->assertStringContainsString('Dummy type "class@anonymous" is invalid.', $tester->getDisplay(true)); } + /** + * @group transient-on-windows + */ public function testRenderExceptionStackTraceContainsRootException() { $application = new Application(); diff --git a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php index 037810aea799f..f48cc941f8ad3 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php @@ -21,7 +21,7 @@ class RecursiveDirectoryIteratorTest extends IteratorTestCase public function testRewindOnFtp() { try { - $i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS); + $i = new RecursiveDirectoryIterator('ftp://speedtest:speedtest@ftp.otenet.gr/', \RecursiveDirectoryIterator::SKIP_DOTS); } catch (\UnexpectedValueException $e) { $this->markTestSkipped('Unsupported stream "ftp".'); } @@ -37,14 +37,14 @@ public function testRewindOnFtp() public function testSeekOnFtp() { try { - $i = new RecursiveDirectoryIterator('ftp://speedtest.tele2.net/', \RecursiveDirectoryIterator::SKIP_DOTS); + $i = new RecursiveDirectoryIterator('ftp://speedtest:speedtest@ftp.otenet.gr/', \RecursiveDirectoryIterator::SKIP_DOTS); } catch (\UnexpectedValueException $e) { $this->markTestSkipped('Unsupported stream "ftp".'); } $contains = [ - 'ftp://speedtest.tele2.net'.\DIRECTORY_SEPARATOR.'1000GB.zip', - 'ftp://speedtest.tele2.net'.\DIRECTORY_SEPARATOR.'100GB.zip', + 'ftp://speedtest:speedtest@ftp.otenet.gr'.\DIRECTORY_SEPARATOR.'test100Mb.db', + 'ftp://speedtest:speedtest@ftp.otenet.gr'.\DIRECTORY_SEPARATOR.'test100k.db', ]; $actual = []; diff --git a/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php index 264c99829c98f..49c2daf45c377 100644 --- a/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/PdoDbalStoreTest.php @@ -44,7 +44,7 @@ public static function tearDownAfterClass(): void */ protected function getClockDelay() { - return 1000000; + return 1500000; } /** diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 7ebf055d75701..fd7ea1a007dde 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -813,16 +813,16 @@ public function testTimeoutWithActiveConcurrentStream() public function testTimeoutOnInitialize() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8077); + $p2 = TestHttpServer::start(8078); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); try { foreach ($responses as $response) { @@ -846,16 +846,16 @@ public function testTimeoutOnInitialize() public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8077); + $p2 = TestHttpServer::start(8078); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); try { while ($response = array_shift($responses)) { From 8fe5fce3cf6171da1b883fde8d02363918fcb364 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 15 Dec 2021 13:10:27 +0100 Subject: [PATCH 43/75] [DependencyInjection] Cast tag value to string DOMElement::setAttribute(): Passing null to parameter #2 ($value) of type string is deprecated This happens when a tag value is `null` on PHP 8.1. --- src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php | 2 +- .../Tests/Fixtures/containers/container9.php | 1 + .../DependencyInjection/Tests/Fixtures/xml/services9.xml | 1 + .../DependencyInjection/Tests/Fixtures/yaml/services9.yml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index 8017fc579aaa2..17cf2c1a74a68 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -138,7 +138,7 @@ private function addService(Definition $definition, ?string $id, \DOMElement $pa $tag = $this->document->createElement('tag'); $tag->setAttribute('name', $name); foreach ($attributes as $key => $value) { - $tag->setAttribute($key, $value); + $tag->setAttribute($key, $value ?? ''); } $service->appendChild($tag); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php index 3ea49503e9753..f4606815cd705 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php @@ -17,6 +17,7 @@ ->register('foo', FooClass::class) ->addTag('foo', ['foo' => 'foo']) ->addTag('foo', ['bar' => 'bar', 'baz' => 'baz']) + ->addTag('nullable', ['bar' => 'bar', 'baz' => null]) ->setFactory(['Bar\\FooClass', 'getInstance']) ->setArguments(['foo', new Reference('foo.baz'), ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%'], true, new Reference('service_container')]) ->setProperties(['foo' => 'bar', 'moo' => new Reference('foo.baz'), 'qux' => ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%']]) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml index 55ec20ee10059..13fb730237136 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml @@ -10,6 +10,7 @@ + foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index fd2be046f8cd6..f9f987e8546cc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -13,6 +13,7 @@ services: tags: - { name: foo, foo: foo } - { name: foo, bar: bar, baz: baz } + - { name: nullable, bar: bar, baz: ~ } arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', foobar: '%foo%' }, true, '@service_container'] properties: { foo: bar, moo: '@foo.baz', qux: { '%foo%': 'foo is %foo%', foobar: '%foo%' } } calls: From 880988cb0b9c17d7e7c7b1df9f609d8887c35686 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 15 Dec 2021 14:33:45 +0100 Subject: [PATCH 44/75] Skip transient tests on macos --- .github/workflows/unit-tests.yml | 2 +- .../HttpClient/Test/HttpClientTestCase.php | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index d5f6c8f7c6cbb..ee8ffee658f5b 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -74,7 +74,7 @@ jobs: ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" echo COLUMNS=120 >> $GITHUB_ENV - echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV + echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data$([[ ${{ matrix.os }} = macos* ]] && echo ',transient-on-macos')" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index fd7ea1a007dde..648c9174e21a5 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -810,19 +810,22 @@ public function testTimeoutWithActiveConcurrentStream() } } + /** + * @group transient-on-macos + */ public function testTimeoutOnInitialize() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8078); + $p2 = TestHttpServer::start(8077); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); try { foreach ($responses as $response) { @@ -843,19 +846,22 @@ public function testTimeoutOnInitialize() } } + /** + * @group transient-on-macos + */ public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8078); + $p2 = TestHttpServer::start(8077); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); try { while ($response = array_shift($responses)) { From ee211c4dca3102075ed5cea36f4c5b3f385c8442 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 15 Dec 2021 15:16:35 +0100 Subject: [PATCH 45/75] [VarDumper] add more "transient-on-macos" groups --- .../Component/VarDumper/Tests/Dumper/ServerDumperTest.php | 3 +++ .../Component/VarDumper/Tests/Server/ConnectionTest.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php index 447d4856f7329..ff4727538399c 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php @@ -37,6 +37,9 @@ public function testDumpForwardsToWrappedDumperWhenServerIsUnavailable() $dumper->dump($data); } + /** + * @group transient-on-macos + */ public function testDump() { $wrappedDumper = $this->createMock(DataDumperInterface::class); diff --git a/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php b/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php index 70629a221569a..ee89d74d0af3d 100644 --- a/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php @@ -22,6 +22,9 @@ class ConnectionTest extends TestCase { private const VAR_DUMPER_SERVER = 'tcp://127.0.0.1:9913'; + /** + * @group transient-on-macos + */ public function testDump() { $cloner = new VarCloner(); From 77267c0598e98be201eb9c79e928079e4f62fefa Mon Sep 17 00:00:00 2001 From: Rhodri Pugh Date: Mon, 6 Dec 2021 15:17:42 +0000 Subject: [PATCH 46/75] restore the overriden locale on tearDown - avoid interfering with any configured value Previously this change was not resetting the locale after changing it to 'en' - which affected other tests which relied on this value being the configured value (however it was configured). This mirrors the pattern used for the timezone, storing it to be reset on tearDown. --- .../Component/Validator/Test/ConstraintValidatorTestCase.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php index 7e18d71fa607d..087bbf140fb2a 100644 --- a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php @@ -58,6 +58,7 @@ abstract class ConstraintValidatorTestCase extends TestCase protected $propertyPath; protected $constraint; protected $defaultTimezone; + private $defaultLocale; private function doSetUp() { @@ -76,6 +77,7 @@ private function doSetUp() $this->validator = $this->createValidator(); $this->validator->initialize($this->context); + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('en'); $this->setDefaultTimezone('UTC'); @@ -84,6 +86,8 @@ private function doSetUp() private function doTearDown() { $this->restoreDefaultTimezone(); + + \Locale::setDefault($this->defaultLocale); } protected function setDefaultTimezone($defaultTimezone) From b968514286f9cc1590067c77e9ac7f77aa417e0d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 16 Dec 2021 17:21:22 +0100 Subject: [PATCH 47/75] [Cache] disable lock on CLI --- .../Tests/Adapter/TagAwareAdapterTest.php | 20 ------------------- .../Component/Cache/Traits/ContractsTrait.php | 16 +++++++++++++-- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php index 4b7c64058c958..2ac5a459e7cbf 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php @@ -14,12 +14,10 @@ use PHPUnit\Framework\MockObject\MockObject; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; -use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\TagAwareAdapter; -use Symfony\Component\Cache\LockRegistry; use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter; /** @@ -198,24 +196,6 @@ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags $this->assertFalse($item->isHit()); } - public function testLog() - { - $lockFiles = LockRegistry::setFiles([__FILE__]); - - $logger = $this->createMock(LoggerInterface::class); - $logger - ->expects($this->atLeastOnce()) - ->method($this->anything()); - - $cache = new TagAwareAdapter(new ArrayAdapter()); - $cache->setLogger($logger); - - // Computing will produce at least one log - $cache->get('foo', static function (): string { return 'ccc'; }); - - LockRegistry::setFiles($lockFiles); - } - /** * @return MockObject&PruneableCacheInterface */ diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php index 06070c970cac5..49a96eed359f5 100644 --- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php +++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php @@ -31,7 +31,7 @@ trait ContractsTrait doGet as private contractsGet; } - private $callbackWrapper = [LockRegistry::class, 'compute']; + private $callbackWrapper; private $computing = []; /** @@ -41,8 +41,16 @@ trait ContractsTrait */ public function setCallbackWrapper(?callable $callbackWrapper): callable { + if (!isset($this->callbackWrapper)) { + $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']); + + if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { + $this->setCallbackWrapper(null); + } + } + $previousWrapper = $this->callbackWrapper; - $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) { + $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) { return $callback($item, $save); }; @@ -82,6 +90,10 @@ static function (CacheItem $item, float $startTime, ?array &$metadata) { $this->computing[$key] = $key; $startTime = microtime(true); + if (!isset($this->callbackWrapper)) { + $this->setCallbackWrapper($this->setCallbackWrapper(null)); + } + try { $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { $setMetadata($item, $startTime, $metadata); From 6e3b71125ad3222b4c8bead5a9bbb83464162143 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 16 Dec 2021 22:17:20 +0100 Subject: [PATCH 48/75] CS fixes --- .php-cs-fixer.dist.php | 1 + .../Messenger/DoctrinePingConnectionMiddleware.php | 2 +- .../Doctrine/PropertyInfo/DoctrineExtractor.php | 2 +- .../Bridge/Doctrine/Validator/DoctrineLoader.php | 2 +- src/Symfony/Component/Cache/Traits/PdoTrait.php | 2 +- src/Symfony/Component/DomCrawler/Crawler.php | 4 ++-- src/Symfony/Component/Dotenv/Dotenv.php | 8 ++++---- .../Session/Storage/Handler/PdoSessionHandler.php | 4 ++-- .../HttpKernel/Controller/ControllerResolver.php | 4 ++-- src/Symfony/Component/Lock/Store/PdoStore.php | 2 +- .../Messenger/Transport/Doctrine/Connection.php | 4 ++-- .../Transport/Doctrine/DoctrineReceiver.php | 12 ++++++------ .../Messenger/Transport/Doctrine/DoctrineSender.php | 2 +- .../Component/Process/Pipes/AbstractPipes.php | 2 +- src/Symfony/Component/Process/Tests/ProcessTest.php | 3 ++- .../Provider/UserAuthenticationProvider.php | 2 +- ...sernamePasswordFormAuthenticationListenerTest.php | 2 +- 17 files changed, 30 insertions(+), 28 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index fdb481fd190a8..3e8de34c124cb 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -11,6 +11,7 @@ '@Symfony' => true, '@Symfony:risky' => true, 'protected_to_private' => false, + 'native_constant_invocation' => ['strict' => false], 'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false], ]) ->setRiskyAllowed(true) diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php index c6b219aa795ab..30f12129c2719 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php @@ -40,7 +40,7 @@ private function pingConnection(EntityManagerInterface $entityManager) try { $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); - } catch (DBALException | Exception $e) { + } catch (DBALException|Exception $e) { $connection->close(); $connection->connect(); } diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 879e87979499c..769beae70ba25 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -230,7 +230,7 @@ private function getMetadata(string $class): ?ClassMetadata { try { return $this->entityManager ? $this->entityManager->getClassMetadata($class) : $this->classMetadataFactory->getMetadataFor($class); - } catch (MappingException | OrmMappingException $exception) { + } catch (MappingException|OrmMappingException $exception) { return null; } } diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php index f0f9a95652399..b3ab046ebd42b 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php @@ -49,7 +49,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool $className = $metadata->getClassName(); try { $doctrineMetadata = $this->entityManager->getClassMetadata($className); - } catch (MappingException | OrmMappingException $exception) { + } catch (MappingException|OrmMappingException $exception) { return false; } diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php index 5b0461409cfb5..4d5e123005877 100644 --- a/src/Symfony/Component/Cache/Traits/PdoTrait.php +++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php @@ -412,7 +412,7 @@ protected function doSave(array $values, int $lifetime) if (null === $driver && !(\is_object($result) ? $result->rowCount() : $stmt->rowCount())) { try { $insertStmt->execute(); - } catch (DBALException | Exception $e) { + } catch (DBALException|Exception $e) { } catch (\PDOException $e) { // A concurrent write won, let it be } diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index de7b3aedc37ae..0d876b7878820 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -1222,11 +1222,11 @@ private function convertToHtmlEntities(string $htmlContent, string $charset = 'U try { return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset); - } catch (\Exception | \ValueError $e) { + } catch (\Exception|\ValueError $e) { try { $htmlContent = iconv($charset, 'UTF-8', $htmlContent); $htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'); - } catch (\Exception | \ValueError $e) { + } catch (\Exception|\ValueError $e) { } return $htmlContent; diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 8180f4bfa10ba..16a252df4f87d 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -54,8 +54,8 @@ public function __construct(bool $usePutenv = true) /** * Loads one or several .env files. * - * @param string $path A file to load - * @param ...string $extraPaths A list of additional files to load + * @param string $path A file to load + * @param string[] ...$extraPaths A list of additional files to load * * @throws FormatException when a file has a syntax error * @throws PathException when a file does not exist or is not readable @@ -112,8 +112,8 @@ public function loadEnv(string $path, string $varName = 'APP_ENV', string $defau /** * Loads one or several .env files and enables override existing vars. * - * @param string $path A file to load - * @param ...string $extraPaths A list of additional files to load + * @param string $path A file to load + * @param string[] ...$extraPaths A list of additional files to load * * @throws FormatException when a file has a syntax error * @throws PathException when a file does not exist or is not readable diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index e234d147e41a1..ed09f72944495 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -626,7 +626,7 @@ protected function doRead($sessionId) $selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $insertStmt = null; - do { + while (true) { $selectStmt->execute(); $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); @@ -675,7 +675,7 @@ protected function doRead($sessionId) } return ''; - } while (true); + } } /** diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php index c3df8f9571d44..7b8deeff1ba7e 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php @@ -47,7 +47,7 @@ public function getController(Request $request) if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) { try { $controller[0] = $this->instantiateController($controller[0]); - } catch (\Error | \LogicException $e) { + } catch (\Error|\LogicException $e) { try { // We cannot just check is_callable but have to use reflection because a non-static method // can still be called statically in PHP but we don't want that. This is deprecated in PHP 7, so we @@ -120,7 +120,7 @@ protected function createController($controller) try { $controller = [$this->instantiateController($class), $method]; - } catch (\Error | \LogicException $e) { + } catch (\Error|\LogicException $e) { try { if ((new \ReflectionMethod($class, $method))->isStatic()) { return $class.'::'.$method; diff --git a/src/Symfony/Component/Lock/Store/PdoStore.php b/src/Symfony/Component/Lock/Store/PdoStore.php index cd24c4def6602..7ee02b48fd419 100644 --- a/src/Symfony/Component/Lock/Store/PdoStore.php +++ b/src/Symfony/Component/Lock/Store/PdoStore.php @@ -127,7 +127,7 @@ public function save(Key $key) try { $stmt->execute(); - } catch (DBALException | Exception $e) { + } catch (DBALException|Exception $e) { // the lock is already acquired. It could be us. Let's try to put off. $this->putOffExpiration($key, $this->initialTtl); } catch (\PDOException $e) { diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 063724b976219..48d00c4be5ede 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -225,7 +225,7 @@ public function ack(string $id): bool { try { return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0; - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } } @@ -234,7 +234,7 @@ public function reject(string $id): bool { try { return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0; - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } } diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php index 2845943c1f035..3624a875218ae 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php @@ -59,7 +59,7 @@ public function get(): iterable } return []; - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } @@ -77,7 +77,7 @@ public function ack(Envelope $envelope): void { try { $this->connection->ack($this->findDoctrineReceivedStamp($envelope)->getId()); - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } } @@ -89,7 +89,7 @@ public function reject(Envelope $envelope): void { try { $this->connection->reject($this->findDoctrineReceivedStamp($envelope)->getId()); - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } } @@ -101,7 +101,7 @@ public function getMessageCount(): int { try { return $this->connection->getMessageCount(); - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } } @@ -113,7 +113,7 @@ public function all(int $limit = null): iterable { try { $doctrineEnvelopes = $this->connection->findAll($limit); - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } @@ -129,7 +129,7 @@ public function find($id): ?Envelope { try { $doctrineEnvelope = $this->connection->find($id); - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php index 95f886c12e6a0..bd0cda175d2af 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php @@ -48,7 +48,7 @@ public function send(Envelope $envelope): Envelope try { $id = $this->connection->send($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay); - } catch (DBALException | Exception $exception) { + } catch (DBALException|Exception $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } diff --git a/src/Symfony/Component/Process/Pipes/AbstractPipes.php b/src/Symfony/Component/Process/Pipes/AbstractPipes.php index 21ab3e389c5be..b0654f13ac431 100644 --- a/src/Symfony/Component/Process/Pipes/AbstractPipes.php +++ b/src/Symfony/Component/Process/Pipes/AbstractPipes.php @@ -133,7 +133,7 @@ protected function write(): ?array } if ($input) { - for (;;) { + while (true) { $data = fread($input, self::CHUNK_SIZE); if (!isset($data[0])) { break; diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 806afbab0948c..6cd41ebcbe15c 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -772,7 +772,8 @@ public function testIterateOverProcessWithTimeout() $start = microtime(true); try { $process->start(); - foreach ($process as $buffer); + foreach ($process as $buffer) { + } $this->fail('A RuntimeException should have been raised'); } catch (RuntimeException $e) { } diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php index e2af5020ec672..e569691612e73 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php @@ -81,7 +81,7 @@ public function authenticate(TokenInterface $token) $this->userChecker->checkPreAuth($user); $this->checkAuthentication($user, $token); $this->userChecker->checkPostAuth($user); - } catch (AccountStatusException | BadCredentialsException $e) { + } catch (AccountStatusException|BadCredentialsException $e) { if ($this->hideUserNotFoundExceptions) { throw new BadCredentialsException('Bad credentials.', 0, $e); } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php index e6d9e06d8b698..f98551f36ad08 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php @@ -160,7 +160,7 @@ public function testHandleNonStringUsernameWithObject(bool $postOnly) /** * @dataProvider postOnlyDataProvider */ - public function testHandleNonStringUsernameWith__toString(bool $postOnly) + public function testHandleNonStringUsernameWithToString(bool $postOnly) { $usernameClass = $this->createMock(DummyUserClass::class); $usernameClass From 08127269752aef65b8201afc197a899982e84f2d Mon Sep 17 00:00:00 2001 From: Sergey Belyshkin Date: Sun, 12 Dec 2021 18:50:26 +0700 Subject: [PATCH 49/75] [Cache] Fix saving items with no expiration through ProxyAdapter --- .../Cache/Adapter/AbstractAdapter.php | 2 +- .../Cache/Adapter/AbstractTagAwareAdapter.php | 2 +- .../Component/Cache/Adapter/ArrayAdapter.php | 14 ++-- .../Component/Cache/Adapter/ProxyAdapter.php | 2 +- .../ProxyAdapterAndRedisAdapterTest.php | 72 +++++++++++++++++++ 5 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index edbdc3ea92a11..3b281bc87e8a8 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -74,7 +74,7 @@ static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifet $key = (string) $key; if (null === $item->expiry) { $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; - } elseif (0 === $item->expiry) { + } elseif (!$item->expiry) { $ttl = 0; } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { $expiredIds[] = $getId($key); diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php index 106d8821b862c..16029f3608ce7 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php @@ -80,7 +80,7 @@ static function ($deferred, &$expiredIds) use ($getId, $tagPrefix, $defaultLifet $key = (string) $key; if (null === $item->expiry) { $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; - } elseif (0 === $item->expiry) { + } elseif (!$item->expiry) { $ttl = 0; } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { $expiredIds[] = $getId($key); diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php index 8fba15b32fd3b..157043abef188 100644 --- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php @@ -124,14 +124,14 @@ public function save(CacheItemInterface $item) $value = $item["\0*\0value"]; $expiry = $item["\0*\0expiry"]; - if (0 === $expiry) { - $expiry = \PHP_INT_MAX; - } - - if (null !== $expiry && $expiry <= microtime(true)) { - $this->deleteItem($key); + if (null !== $expiry) { + if (!$expiry) { + $expiry = \PHP_INT_MAX; + } elseif ($expiry <= microtime(true)) { + $this->deleteItem($key); - return true; + return true; + } } if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) { return false; diff --git a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php index d5b0593353ae9..3a1e658bc0ac4 100644 --- a/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ProxyAdapter.php @@ -88,7 +88,7 @@ static function (CacheItemInterface $innerItem, array $item) { $item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]]; } $innerItem->set($item["\0*\0value"]); - $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null); + $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null); }, null, CacheItem::class diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php new file mode 100644 index 0000000000000..46516e0095e6e --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/ProxyAdapterAndRedisAdapterTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\ProxyAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; +use Symfony\Component\Cache\CacheItem; + +/** + * @group integration + */ +class ProxyAdapterAndRedisAdapterTest extends AbstractRedisAdapterTest +{ + protected $skippedTests = [ + 'testPrune' => 'RedisAdapter does not implement PruneableInterface.', + ]; + + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST')); + } + + public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface + { + return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime); + } + + public function testSaveItemPermanently() + { + $setCacheItemExpiry = \Closure::bind( + static function (CacheItem $item, $expiry) { + $item->expiry = $expiry; + + return $item; + }, + null, + CacheItem::class + ); + + $cache = $this->createCachePool(1); + $value = rand(); + $item = $cache->getItem('foo'); + $setCacheItemExpiry($item, 0); + $cache->save($item->set($value)); + $item = $cache->getItem('bar'); + $setCacheItemExpiry($item, 0.0); + $cache->save($item->set($value)); + $item = $cache->getItem('baz'); + $cache->save($item->set($value)); + + $this->assertSame($value, $this->cache->getItem('foo')->get()); + $this->assertSame($value, $this->cache->getItem('bar')->get()); + $this->assertSame($value, $this->cache->getItem('baz')->get()); + + sleep(1); + $this->assertSame($value, $this->cache->getItem('foo')->get()); + $this->assertSame($value, $this->cache->getItem('bar')->get()); + $this->assertFalse($this->cache->getItem('baz')->isHit()); + } +} From 87097b8b1c2bfcb0200fd5b428dc07cfe09119fb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 Dec 2021 15:53:17 +0100 Subject: [PATCH 50/75] [DependencyInjection] fix linting callable classes --- .../Compiler/AbstractRecursivePass.php | 4 ++++ .../Compiler/CheckTypeDeclarationsPassTest.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php index ffd3c4e08b819..4fb467d965d8d 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AbstractRecursivePass.php @@ -203,6 +203,10 @@ protected function getReflectionMethod(Definition $definition, $method) } if (!$r->hasMethod($method)) { + if ($r->hasMethod('__call') && ($r = $r->getMethod('__call')) && $r->isPublic()) { + return new \ReflectionMethod(static function (...$arguments) {}, '__invoke'); + } + throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php index adb725cc99c7f..9de33d2f5eef3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -988,4 +988,22 @@ public function testIntersectionTypeFailsWithReference() (new CheckTypeDeclarationsPass(true))->process($container); } + + public function testCallableClass() + { + $container = new ContainerBuilder(); + $definition = $container->register('foo', CallableClass::class); + $definition->addMethodCall('callMethod', [123]); + + (new CheckTypeDeclarationsPass())->process($container); + + $this->addToAssertionCount(1); + } +} + +class CallableClass +{ + public function __call($name, $arguments) + { + } } From 07fbfbfd9898ef17fea393ecedd3117ee5150266 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Sun, 19 Dec 2021 17:27:15 +0100 Subject: [PATCH 51/75] Run `open_basedir` tests in separate processes --- .../Component/Process/Tests/ExecutableFinderTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php b/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php index 83f263ff35074..d056841fb79c5 100644 --- a/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php +++ b/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php @@ -96,6 +96,9 @@ public function testFindWithExtraDirs() $this->assertSamePath(\PHP_BINARY, $result); } + /** + * @runInSeparateProcess + */ public function testFindWithOpenBaseDir() { if ('\\' === \DIRECTORY_SEPARATOR) { @@ -114,6 +117,9 @@ public function testFindWithOpenBaseDir() $this->assertSamePath(\PHP_BINARY, $result); } + /** + * @runInSeparateProcess + */ public function testFindProcessInOpenBasedir() { if (ini_get('open_basedir')) { From 3f5a8bd4145df75bb1fbced591f6d85c586c1f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Gonz=C3=A1lez=20Montes?= Date: Mon, 20 Dec 2021 09:13:14 +0100 Subject: [PATCH 52/75] [Translations] Add missing translations for Galician (gl) --- .../Resources/translations/validators.gl.xlf | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf index 433236d789066..f8c5c0493f731 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Ningunha carpeta temporal foi configurada en php.ini. + Ningunha carpeta temporal foi configurada en php.ini, ou a carpeta non existe. Cannot write temporary file to disk. @@ -364,7 +364,7 @@ This value should be between {{ min }} and {{ max }}. - Este valor debe estar comprendido entre {{min}} e {{max}}. + Este valor debe estar comprendido entre {{ min }} e {{ max }}. This value is not a valid hostname. @@ -394,6 +394,14 @@ This value is not a valid CSS color. Este valor non é unha cor CSS válida. + + This value is not a valid CIDR notation. + Este valor non ten unha notación CIDR válida. + + + The value of the netmask should be between {{ min }} and {{ max }}. + O valor da máscara de rede debería estar entre {{ min }} e {{ max }}. + From 292fcfe8f22d32bde926b8fa0dbfa5f2929c2902 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 20 Dec 2021 10:31:34 +0100 Subject: [PATCH 53/75] [Validator] Improve French translation --- .../Validator/Resources/translations/validators.fr.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index bc03a0a3dc99e..92127773178e7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Aucun répertoire temporaire n'a été configuré dans le php.ini. + Aucun répertoire temporaire n'a été configuré dans le php.ini, ou le répertoire configuré n'existe pas. Cannot write temporary file to disk. From a58c342fffb642f174fd419ef75ea084710cec14 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Dec 2021 15:24:03 +0100 Subject: [PATCH 54/75] [Mime] Fix encoding filenames in multipart/form-data --- .../Mime/Header/ParameterizedHeader.php | 18 +++++++++++++++++- .../Tests/Header/ParameterizedHeaderTest.php | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Header/ParameterizedHeader.php b/src/Symfony/Component/Mime/Header/ParameterizedHeader.php index 2c078d14c328c..e5d4238b47654 100644 --- a/src/Symfony/Component/Mime/Header/ParameterizedHeader.php +++ b/src/Symfony/Component/Mime/Header/ParameterizedHeader.php @@ -123,6 +123,22 @@ private function createParameter(string $name, string $value): string $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'"); } + + if (\in_array($name, ['name', 'filename'], true) && 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()) && preg_match('//u', $value)) { + // WHATWG HTML living standard 4.10.21.8 2 specifies: + // For field names and filenames for file fields, the result of the + // encoding in the previous bullet point must be escaped by replacing + // any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D` + // and 0x22 (") with `%22`. + // The user agent must not perform any other escapes. + $value = str_replace(['"', "\r", "\n"], ['%22', '%0D', '%0A'], $value); + + if (\strlen($value) <= $maxValueLength) { + return $name.'="'.$value.'"'; + } + + $value = $origValue; + } } // Encode if we need to @@ -158,7 +174,7 @@ private function createParameter(string $name, string $value): string */ private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string { - $forceHttpQuoting = 'content-disposition' === strtolower($this->getName()) && 'form-data' === $this->getValue(); + $forceHttpQuoting = 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()); if ($forceHttpQuoting || !preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { $value = '"'.$value.'"'; } diff --git a/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php index e41d03857df08..ddc558435f5b6 100644 --- a/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php +++ b/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php @@ -58,6 +58,20 @@ public function testSpaceInParamResultsInQuotedString() $this->assertEquals('attachment; filename="my file.txt"', $header->getBodyAsString()); } + public function testFormDataResultsInQuotedString() + { + $header = new ParameterizedHeader('Content-Disposition', 'form-data'); + $header->setParameters(['filename' => 'file.txt']); + $this->assertEquals('form-data; filename="file.txt"', $header->getBodyAsString()); + } + + public function testFormDataUtf8() + { + $header = new ParameterizedHeader('Content-Disposition', 'form-data'); + $header->setParameters(['filename' => "déjà%\"\n\r.txt"]); + $this->assertEquals('form-data; filename="déjà%%22%0A%0D.txt"', $header->getBodyAsString()); + } + public function testLongParamsAreBrokenIntoMultipleAttributeStrings() { /* -- RFC 2231, 3. From 04ddc126f3fdf33c2e6da02acf248b5093e6c495 Mon Sep 17 00:00:00 2001 From: ThomasLandauer Date: Mon, 20 Dec 2021 17:37:07 +0100 Subject: [PATCH 55/75] [Mime] Relaxing in-reply-to header validation --- src/Symfony/Component/Mime/Header/Headers.php | 4 ++-- .../Component/Mime/Tests/Header/HeadersTest.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mime/Header/Headers.php b/src/Symfony/Component/Mime/Header/Headers.php index 1a7b4b276eee2..201a7a5f9744b 100644 --- a/src/Symfony/Component/Mime/Header/Headers.php +++ b/src/Symfony/Component/Mime/Header/Headers.php @@ -141,8 +141,8 @@ public function add(HeaderInterface $header): self 'cc' => MailboxListHeader::class, 'bcc' => MailboxListHeader::class, 'message-id' => IdentificationHeader::class, - 'in-reply-to' => IdentificationHeader::class, - 'references' => IdentificationHeader::class, + 'in-reply-to' => UnstructuredHeader::class, // `In-Reply-To` and `References` are less strict than RFC 2822 (3.6.4) to allow users entering the original email's ... + 'references' => UnstructuredHeader::class, // ... `Message-ID`, even if that is no valid `msg-id` 'return-path' => PathHeader::class, ]; diff --git a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php index 89d8be01b0181..5da27293310e8 100644 --- a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php +++ b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php @@ -243,4 +243,18 @@ public function testToArray() "Foo: =?utf-8?Q?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?=\r\n =?utf-8?Q?aaaa?=", ], $headers->toArray()); } + + public function testInReplyToAcceptsNonIdentifierValues() + { + $headers = new Headers(); + $headers->addHeader('In-Reply-To', 'foobar'); + $this->assertEquals('foobar', $headers->get('In-Reply-To')->getBody()); + } + + public function testReferencesAcceptsNonIdentifierValues() + { + $headers = new Headers(); + $headers->addHeader('References' , 'foobar'); + $this->assertEquals('foobar', $headers->get('References')->getBody()); + } } From 6ca8e30a85e455bf348b18eeb735c897ccd00f9b Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 22 Dec 2021 14:28:19 +0100 Subject: [PATCH 56/75] Remove the unused dependency on composer/package-versions-deprecated The ProxyManagerBridge depends on friendsofphp/proxy-manager-lts which has an optional dependency on the PackageVersions class to implement the `ProxyManager\Version::getVersion` method on composer 1 (with a fallback to a less precise version number). However, the bridge has stopped using that API in favor of feature detection, so the dependency is unused. --- src/Symfony/Bridge/ProxyManager/composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 09692b8c89d74..577138489e690 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -17,7 +17,6 @@ ], "require": { "php": ">=7.1.3", - "composer/package-versions-deprecated": "^1.8", "friendsofphp/proxy-manager-lts": "^1.0.2", "symfony/dependency-injection": "^4.0|^5.0", "symfony/polyfill-php80": "^1.16" From c7f6b348351dde620fa24982f0b8efc49bde2355 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Thu, 23 Dec 2021 17:49:24 +0100 Subject: [PATCH 57/75] Update security.lb.xlf --- .../Security/Core/Resources/translations/security.lb.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf index 5f707535fa723..36987bc99f37f 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf @@ -1,6 +1,6 @@ - + An authentication exception occurred. From 042c60086aa0de9a785e85275a03e9e97e720762 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 24 Dec 2021 00:01:05 +0100 Subject: [PATCH 58/75] Allow package-versions-deprecated plugin --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 5388530c16c85..0b9c72332eec8 100644 --- a/composer.json +++ b/composer.json @@ -152,6 +152,11 @@ "ocramius/proxy-manager": "<2.1", "phpunit/phpunit": "<5.4.3" }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true + } + }, "autoload": { "psr-4": { "Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/", From 5f69e86af0ada3d1794109e2eea53c8b21c20425 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 25 Dec 2021 20:39:39 +0100 Subject: [PATCH 59/75] [Mime] Fix test --- src/Symfony/Component/Mime/Tests/Header/HeadersTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php index 5da27293310e8..168d0bcbbe0d9 100644 --- a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php +++ b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php @@ -247,14 +247,14 @@ public function testToArray() public function testInReplyToAcceptsNonIdentifierValues() { $headers = new Headers(); - $headers->addHeader('In-Reply-To', 'foobar'); + $headers->addTextHeader('In-Reply-To', 'foobar'); $this->assertEquals('foobar', $headers->get('In-Reply-To')->getBody()); } public function testReferencesAcceptsNonIdentifierValues() { $headers = new Headers(); - $headers->addHeader('References' , 'foobar'); + $headers->addTextHeader('References' , 'foobar'); $this->assertEquals('foobar', $headers->get('References')->getBody()); } } From 4d95be0a2e76ed80684f1f82f2c8e6fc3fc9484c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 25 Dec 2021 20:42:09 +0100 Subject: [PATCH 60/75] [HttpClient] mark test transient --- src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index 36e76ee83b9a1..e5b86a3be96cc 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -19,6 +19,9 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase { + /** + * @group transient-on-macos + */ public function testTimeoutOnDestruct() { if (!method_exists(parent::class, 'testTimeoutOnDestruct')) { From 2d8eeabeaa3cfc97d3dab693b29c76dcfdd6c051 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 26 Dec 2021 20:04:24 +0100 Subject: [PATCH 61/75] [Cache] fix compat with apcu < 5.1.10 --- .../Component/Cache/Tests/Adapter/AdapterTestCase.php | 9 +++++++++ src/Symfony/Component/Cache/Traits/ApcuTrait.php | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index a72ae663f09d6..123cda89b8728 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -296,6 +296,15 @@ public function testWeirdDataMatchingMetadataWrappedValues() $this->assertTrue($cache->hasItem('foobar')); } + + public function testNullByteInKey() + { + $cache = $this->createCachePool(0, __FUNCTION__); + + $cache->save($cache->getItem("a\0b")->set(123)); + + $this->assertSame(123, $cache->getItem("a\0b")->get()); + } } class NotUnserializable diff --git a/src/Symfony/Component/Cache/Traits/ApcuTrait.php b/src/Symfony/Component/Cache/Traits/ApcuTrait.php index b56ae4f7c39ac..ace28c7d37bd8 100644 --- a/src/Symfony/Component/Cache/Traits/ApcuTrait.php +++ b/src/Symfony/Component/Cache/Traits/ApcuTrait.php @@ -54,7 +54,14 @@ protected function doFetch(array $ids) $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); try { $values = []; - foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) { + $ids = array_flip($ids); + foreach (apcu_fetch(array_keys($ids), $ok) ?: [] as $k => $v) { + if (!isset($ids[$k])) { + // work around https://github.com/krakjoe/apcu/issues/247 + $k = key($ids); + } + unset($ids[$k]); + if (null !== $v || $ok) { $values[$k] = $v; } From a9c9912e9de22d325eb13e1d2262802df7b66ea4 Mon Sep 17 00:00:00 2001 From: Vitali Tsyrkin Date: Mon, 27 Dec 2021 21:37:25 +0300 Subject: [PATCH 62/75] [HttpFoundation] Fix notice when HTTP_PHP_AUTH_USER passed without pass --- src/Symfony/Component/HttpFoundation/ServerBag.php | 2 +- .../Component/HttpFoundation/Tests/ServerBagTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/ServerBag.php b/src/Symfony/Component/HttpFoundation/ServerBag.php index 7af111c865154..25688d5230f4b 100644 --- a/src/Symfony/Component/HttpFoundation/ServerBag.php +++ b/src/Symfony/Component/HttpFoundation/ServerBag.php @@ -89,7 +89,7 @@ public function getHeaders() // PHP_AUTH_USER/PHP_AUTH_PW if (isset($headers['PHP_AUTH_USER'])) { - $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']); + $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.($headers['PHP_AUTH_PW'] ?? '')); } elseif (isset($headers['PHP_AUTH_DIGEST'])) { $headers['AUTHORIZATION'] = $headers['PHP_AUTH_DIGEST']; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php index 0663b118e675e..e26714bc4640a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php @@ -57,6 +57,16 @@ public function testHttpPasswordIsOptional() ], $bag->getHeaders()); } + public function testHttpPasswordIsOptionalWhenPassedWithHttpPrefix() + { + $bag = new ServerBag(['HTTP_PHP_AUTH_USER' => 'foo']); + + $this->assertEquals([ + 'AUTHORIZATION' => 'Basic '.base64_encode('foo:'), + 'PHP_AUTH_USER' => 'foo', + ], $bag->getHeaders()); + } + public function testHttpBasicAuthWithPhpCgi() { $bag = new ServerBag(['HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:bar')]); From 742279caa93c52ab69cac79d4387c413385c6a9d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Dec 2021 14:24:52 +0100 Subject: [PATCH 63/75] [Messenger] fix Redis support on 32b arch --- .appveyor.yml | 4 + .github/workflows/integration-tests.yml | 4 - phpunit.xml.dist | 1 + .../Transport/RedisExt/ConnectionTest.php | 23 +++++- .../Transport/RedisExt/Connection.php | 82 ++++++++++++------- 5 files changed, 78 insertions(+), 36 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index cbb0098bcffbe..889aafe26929b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,6 +21,8 @@ install: - cd ext - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.18-7.1-ts-vc14-x86.zip - 7z x php_apcu-5.1.18-7.1-ts-vc14-x86.zip -y >nul + - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_redis-5.1.1-7.1-ts-vc14-x86.zip + - 7z x php_redis-5.1.1-7.1-ts-vc14-x86.zip -y >nul - cd .. - copy /Y php.ini-development php.ini-min - echo memory_limit=-1 >> php.ini-min @@ -36,6 +38,7 @@ install: - echo opcache.enable_cli=1 >> php.ini-max - echo extension=php_openssl.dll >> php.ini-max - echo extension=php_apcu.dll >> php.ini-max + - echo extension=php_redis.dll >> php.ini-max - echo apc.enable_cli=1 >> php.ini-max - echo extension=php_intl.dll >> php.ini-max - echo extension=php_mbstring.dll >> php.ini-max @@ -54,6 +57,7 @@ install: - SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev - php composer.phar update --no-progress --ansi - php phpunit install + - choco install memurai-developer test_script: - SET X=0 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 9832c8a9d09a2..72002fa8998ef 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -99,15 +99,11 @@ jobs: - name: Run tests run: ./phpunit --group integration -v env: - REDIS_HOST: localhost REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' REDIS_SENTINEL_HOSTS: 'localhost:26379' REDIS_SENTINEL_SERVICE: redis_sentinel MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages - MEMCACHED_HOST: localhost - LDAP_HOST: localhost - LDAP_PORT: 3389 #- name: Run HTTP push tests # if: matrix.php == '8.0' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index c4e152a05938f..0c4dd3ee87287 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,6 +18,7 @@ + diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php index 5484664e2c4ec..70b260ad63f80 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php @@ -220,6 +220,7 @@ public function testGetAfterReject() { $redis = new \Redis(); $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', [], $redis); + $connection->cleanup(); $connection->add('1', []); $connection->add('2', []); @@ -230,7 +231,7 @@ public function testGetAfterReject() $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget'); $this->assertNotNull($connection->get()); - $redis->del('messenger-rejectthenget'); + $connection->cleanup(); } public function testGetNonBlocking() @@ -238,12 +239,30 @@ public function testGetNonBlocking() $redis = new \Redis(); $connection = Connection::fromDsn('redis://localhost/messenger-getnonblocking', [], $redis); + $connection->cleanup(); $this->assertNull($connection->get()); // no message, should return null immediately $connection->add('1', []); $this->assertNotEmpty($message = $connection->get()); $connection->reject($message['id']); - $redis->del('messenger-getnonblocking'); + + $connection->cleanup(); + } + + public function testGetDelayed() + { + $redis = new \Redis(); + + $connection = Connection::fromDsn('redis://localhost/messenger-delayed', [], $redis); + $connection->cleanup(); + + $connection->add('1', [], 100); + $this->assertNull($connection->get()); + usleep(300000); + $this->assertNotEmpty($message = $connection->get()); + $connection->reject($message['id']); + + $connection->cleanup(); } public function testJsonError() diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 4e372eecd72f8..29eb6cb12e0d9 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -141,33 +141,29 @@ public function get(): ?array if ($this->autoSetup) { $this->setup(); } + $now = microtime(); + $now = substr($now, 11).substr($now, 2, 3); - try { - $queuedMessageCount = $this->connection->zcount($this->queue, 0, $this->getCurrentTimeInMilliseconds()); - } catch (\RedisException $e) { - throw new TransportException($e->getMessage(), 0, $e); - } + $queuedMessageCount = $this->rawCommand('ZCOUNT', 0, $now); - if ($queuedMessageCount) { - for ($i = 0; $i < $queuedMessageCount; ++$i) { - try { - $queuedMessages = $this->connection->zpopmin($this->queue, 1); - } catch (\RedisException $e) { - throw new TransportException($e->getMessage(), 0, $e); - } + while ($queuedMessageCount--) { + if (![$queuedMessage, $expiry] = $this->rawCommand('ZPOPMIN', 1)) { + break; + } + + if (\strlen($expiry) === \strlen($now) ? $expiry > $now : \strlen($expiry) < \strlen($now)) { + // if a future-placed message is popped because of a race condition with + // another running consumer, the message is readded to the queue - foreach ($queuedMessages as $queuedMessage => $time) { - $queuedMessage = json_decode($queuedMessage, true); - // if a futured placed message is actually popped because of a race condition with - // another running message consumer, the message is readded to the queue by add function - // else its just added stream and will be available for all stream consumers - $this->add( - $queuedMessage['body'], - $queuedMessage['headers'], - $time - $this->getCurrentTimeInMilliseconds() - ); + if (!$this->rawCommand('ZADD', 'NX', $expiry, $queuedMessage)) { + throw new TransportException('Could not add a message to the redis stream.'); } + + break; } + + $queuedMessage = json_decode($queuedMessage, true); + $this->add($queuedMessage['body'], $queuedMessage['headers'], 0); } $messageId = '>'; // will receive new messages @@ -255,7 +251,7 @@ public function add(string $body, array $headers, int $delayInMs = 0): void } try { - if ($delayInMs > 0) { // the delay could be smaller 0 in a queued message + if ($delayInMs > 0) { // the delay is <= 0 for queued messages $message = json_encode([ 'body' => $body, 'headers' => $headers, @@ -267,8 +263,18 @@ public function add(string $body, array $headers, int $delayInMs = 0): void throw new TransportException(json_last_error_msg()); } - $score = $this->getCurrentTimeInMilliseconds() + $delayInMs; - $added = $this->connection->zadd($this->queue, ['NX'], $score, $message); + $now = explode(' ', microtime(), 2); + $now[0] = str_pad($delayInMs + substr($now[0], 2, 3), 3, '0', \STR_PAD_LEFT); + if (3 < \strlen($now[0])) { + $now[1] += substr($now[0], 0, -3); + $now[0] = substr($now[0], -3); + + if (\is_float($now[1])) { + throw new TransportException("Message delay is too big: {$delayInMs}ms."); + } + } + + $added = $this->rawCommand('ZADD', 'NX', $now[1].$now[0], $message); } else { $message = json_encode([ 'body' => $body, @@ -316,14 +322,30 @@ public function setup(): void $this->autoSetup = false; } - private function getCurrentTimeInMilliseconds(): int - { - return (int) (microtime(true) * 1000); - } - public function cleanup(): void { $this->connection->del($this->stream); $this->connection->del($this->queue); } + + /** + * @return mixed + */ + private function rawCommand(string $command, ...$arguments) + { + try { + $result = $this->connection->rawCommand($command, $this->queue, ...$arguments); + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + if (false === $result) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + throw new TransportException($error ?? sprintf('Could not run "%s" on Redis queue.', $command)); + } + + return $result; + } } From be8cbd2aec5c99d901e611945ecfb33e569cb1c9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 28 Dec 2021 11:59:47 +0100 Subject: [PATCH 64/75] [Cache] Don't lock when doing nested computations --- src/Symfony/Component/Cache/LockRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php index 70fcac9cc12af..20fba4d3d4da4 100644 --- a/src/Symfony/Component/Cache/LockRegistry.php +++ b/src/Symfony/Component/Cache/LockRegistry.php @@ -88,7 +88,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1; - if ($key < 0 || (self::$lockedFiles[$key] ?? false) || !$lock = self::open($key)) { + if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) { return $callback($item, $save); } From 89232ee5ea7bf86b97503d8ed58b83cd1612b67b Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Tue, 28 Dec 2021 14:37:08 +0100 Subject: [PATCH 65/75] [HttpKernel] Do not attempt to register enum arguments in controller service locator --- ...RegisterControllerArgumentLocatorsPass.php | 5 ++++ ...sterControllerArgumentLocatorsPassTest.php | 27 +++++++++++++++++++ .../HttpKernel/Tests/Fixtures/Suit.php | 20 ++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Suit.php diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index cf4ab60284408..eef09fa82298e 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -127,6 +127,11 @@ public function process(ContainerBuilder $container) $type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\'); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; + if (is_subclass_of($type, \UnitEnum::class, true)) { + // do not attempt to register enum typed arguments + continue; + } + if (isset($arguments[$r->name][$p->name])) { $target = $arguments[$r->name][$p->name]; if ('?' !== $target[0]) { diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index 5a0964f6c21ca..0207703d94c88 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -23,6 +23,7 @@ use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass; +use Symfony\Component\HttpKernel\Tests\Fixtures\Suit; class RegisterControllerArgumentLocatorsPassTest extends TestCase { @@ -369,6 +370,25 @@ public function testNotTaggedControllerServiceReceivesLocatorArgument() $this->assertInstanceOf(Reference::class, $locatorArgument); } + + /** + * @requires PHP 8.1 + */ + public function testEnumArgumentIsIgnored() + { + $container = new ContainerBuilder(); + $resolver = $container->register('argument_resolver.service')->addArgument([]); + + $container->register('foo', NonNullableEnumArgumentWithDefaultController::class) + ->addTag('controller.service_arguments') + ; + + $pass = new RegisterControllerArgumentLocatorsPass(); + $pass->process($container); + + $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); + $this->assertEmpty(array_keys($locator), 'enum typed argument is ignored'); + } } class RegisterTestController @@ -430,3 +450,10 @@ public function fooAction(string $someArg) { } } + +class NonNullableEnumArgumentWithDefaultController +{ + public function fooAction(Suit $suit = Suit::Spades) + { + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Suit.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Suit.php new file mode 100644 index 0000000000000..5d9623b22598d --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Suit.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures; + +enum Suit: string +{ + case Hearts = 'H'; + case Diamonds = 'D'; + case Clubs = 'C'; + case Spades = 'S'; +} From a1d33da66df573ac87d836b76a8e256a777992c3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 28 Dec 2021 15:43:46 +0100 Subject: [PATCH 66/75] cs fix --- .../RegisterControllerArgumentLocatorsPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index eef09fa82298e..daba47315164b 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -127,7 +127,7 @@ public function process(ContainerBuilder $container) $type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\'); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; - if (is_subclass_of($type, \UnitEnum::class, true)) { + if (is_subclass_of($type, \UnitEnum::class)) { // do not attempt to register enum typed arguments continue; } From 53b3e40ab51d946c93b390a0b1ddc940dd8900d8 Mon Sep 17 00:00:00 2001 From: Titouan Galopin Date: Sun, 21 Nov 2021 14:26:08 +0100 Subject: [PATCH 67/75] [DomCrawler] Fix HTML5 parser charset option --- src/Symfony/Component/DomCrawler/Crawler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 70a4b607dcdca..d1c7a9690a07e 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -1107,7 +1107,7 @@ protected function sibling($node, $siblingDir = 'nextSibling') private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument { - return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset), [], $charset); + return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset)); } private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument From 0f96dd0775c9ecb785c14ef9b3dcbff89960a3a3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Dec 2021 09:46:54 +0100 Subject: [PATCH 68/75] Fix transient test --- .../Tests/Transport/Doctrine/DoctrineIntegrationTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index 2bc70871baf5c..45ca47af4882a 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -21,6 +21,7 @@ /** * @requires extension pdo_sqlite + * @group transient-on-macos */ class DoctrineIntegrationTest extends TestCase { From dbc3eea99b04dc685088f37b6ae4e0700f5f4558 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Wed, 29 Dec 2021 09:18:46 +0100 Subject: [PATCH 69/75] Suppress psalm error for UndefinedDocblockClass for PHP 8.1 classes --- psalm.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/psalm.xml b/psalm.xml index 015c0ed18b21b..3fb94145699cf 100644 --- a/psalm.xml +++ b/psalm.xml @@ -27,5 +27,13 @@ + + + + + + + + From 39064fe631568901f04bb4fa43cbeb66f87890f6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Dec 2021 10:28:53 +0100 Subject: [PATCH 70/75] [CI] Remove macOS jobs --- .github/workflows/unit-tests.yml | 20 ++++--------------- .../HttpClient/Tests/HttpClientTestCase.php | 3 --- .../Doctrine/DoctrineIntegrationTest.php | 1 - .../Tests/Dumper/ServerDumperTest.php | 3 --- .../VarDumper/Tests/Server/ConnectionTest.php | 3 --- .../HttpClient/Test/HttpClientTestCase.php | 6 ------ 6 files changed, 4 insertions(+), 32 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index ee8ffee658f5b..712657bd3d3c7 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -20,23 +20,16 @@ jobs: matrix: include: - php: '7.2' - os: ubuntu-20.04 - php: '7.4' - os: ubuntu-20.04 - - php: '8.0' - os: macos-11 - php: '8.0' mode: high-deps - os: ubuntu-20.04 - php: '8.1' mode: low-deps - os: ubuntu-20.04 - php: '8.2' mode: experimental - os: ubuntu-20.04 fail-fast: false - runs-on: "${{ matrix.os }}" + runs-on: ubuntu-20.04 steps: - name: Checkout @@ -58,11 +51,6 @@ jobs: extensions: "${{ env.extensions }}" tools: flex - - name: Install Homebrew packages - if: "matrix.os == 'macos-11'" - run: | - brew install parallel - - name: Configure environment run: | git config --global user.email "" @@ -74,7 +62,7 @@ jobs: ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" echo COLUMNS=120 >> $GITHUB_ENV - echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data$([[ ${{ matrix.os }} = macos* ]] && echo ',transient-on-macos')" >> $GITHUB_ENV + echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) @@ -148,7 +136,7 @@ jobs: echo "::endgroup::" - name: Patch return types - if: "matrix.php == '8.1' && ! matrix.mode && matrix.os != 'macos-11'" + if: "matrix.php == '8.1' && ! matrix.mode" run: | sed -i 's/"\*\*\/Tests\/"//' composer.json composer install -q --optimize-autoloader @@ -222,7 +210,7 @@ jobs: [[ ! $X ]] || (exit 1) - name: Run tests with SIGCHLD enabled PHP - if: "matrix.php == '7.2' && ! matrix.mode && matrix.os != 'macos-11'" + if: "matrix.php == '7.2' && ! matrix.mode" run: | mkdir build cd build diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index e5b86a3be96cc..36e76ee83b9a1 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -19,9 +19,6 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase { - /** - * @group transient-on-macos - */ public function testTimeoutOnDestruct() { if (!method_exists(parent::class, 'testTimeoutOnDestruct')) { diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index 45ca47af4882a..2bc70871baf5c 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -21,7 +21,6 @@ /** * @requires extension pdo_sqlite - * @group transient-on-macos */ class DoctrineIntegrationTest extends TestCase { diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php index ff4727538399c..447d4856f7329 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php @@ -37,9 +37,6 @@ public function testDumpForwardsToWrappedDumperWhenServerIsUnavailable() $dumper->dump($data); } - /** - * @group transient-on-macos - */ public function testDump() { $wrappedDumper = $this->createMock(DataDumperInterface::class); diff --git a/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php b/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php index ee89d74d0af3d..70629a221569a 100644 --- a/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php @@ -22,9 +22,6 @@ class ConnectionTest extends TestCase { private const VAR_DUMPER_SERVER = 'tcp://127.0.0.1:9913'; - /** - * @group transient-on-macos - */ public function testDump() { $cloner = new VarCloner(); diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 648c9174e21a5..7ebf055d75701 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -810,9 +810,6 @@ public function testTimeoutWithActiveConcurrentStream() } } - /** - * @group transient-on-macos - */ public function testTimeoutOnInitialize() { $p1 = TestHttpServer::start(8067); @@ -846,9 +843,6 @@ public function testTimeoutOnInitialize() } } - /** - * @group transient-on-macos - */ public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); From c32d749a558b93d4b730c5e06824170e84d2559f Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Wed, 29 Dec 2021 10:49:04 +0100 Subject: [PATCH 71/75] [DependencyInjection][HttpKernel] Fix enum typed bindings --- .../Compiler/ResolveBindingsPass.php | 5 ++++ .../Compiler/ResolveBindingsPassTest.php | 23 +++++++++++++++++++ .../Tests/Fixtures/NamedEnumArgumentDummy.php | 19 +++++++++++++++ ...RegisterControllerArgumentLocatorsPass.php | 8 +++---- 4 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php index 59c15cf2382c1..88355eb7f04c7 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php @@ -133,6 +133,11 @@ protected function processValue($value, $isRoot = false) continue; } + if (is_subclass_of($m[1], \UnitEnum::class)) { + $bindingNames[substr($key, \strlen($m[0]))] = $binding; + continue; + } + if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) { throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, \gettype($bindingValue))); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php index 199961a10d6fb..5d4f5ef9bb5f4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php @@ -24,7 +24,9 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; +use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedEnumArgumentDummy; use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists; use Symfony\Component\DependencyInjection\TypedReference; @@ -63,6 +65,27 @@ public function testProcess() $this->assertEquals([['setSensitiveClass', [new Reference('foo')]]], $definition->getMethodCalls()); } + /** + * @requires PHP 8.1 + */ + public function testProcessEnum() + { + $container = new ContainerBuilder(); + + $bindings = [ + FooUnitEnum::class.' $bar' => new BoundArgument(FooUnitEnum::BAR), + ]; + + $definition = $container->register(NamedEnumArgumentDummy::class, NamedEnumArgumentDummy::class); + $definition->setBindings($bindings); + + $pass = new ResolveBindingsPass(); + $pass->process($container); + + $expected = [FooUnitEnum::BAR]; + $this->assertEquals($expected, $definition->getArguments()); + } + public function testUnusedBinding() { $this->expectException(InvalidArgumentException::class); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.php new file mode 100644 index 0000000000000..c172c996a7fb7 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NamedEnumArgumentDummy.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\DependencyInjection\Tests\Fixtures; + +class NamedEnumArgumentDummy +{ + public function __construct(FooUnitEnum $bar) + { + } +} diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index daba47315164b..871e3807c6b3e 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -127,11 +127,6 @@ public function process(ContainerBuilder $container) $type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\'); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; - if (is_subclass_of($type, \UnitEnum::class)) { - // do not attempt to register enum typed arguments - continue; - } - if (isset($arguments[$r->name][$p->name])) { $target = $arguments[$r->name][$p->name]; if ('?' !== $target[0]) { @@ -156,6 +151,9 @@ public function process(ContainerBuilder $container) $args[$p->name] = $bindingValue; } + continue; + } elseif (is_subclass_of($type, \UnitEnum::class)) { + // do not attempt to register enum typed arguments if not already present in bindings continue; } elseif (!$type || !$autowire || '\\' !== $target[0]) { continue; From ad9ca5a9f520f9e59a2f9d128a2c7d10ccf3f992 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Dec 2021 11:52:31 +0100 Subject: [PATCH 72/75] Allow symfony/runtime plugin --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0b9c72332eec8..c2933d54031f7 100644 --- a/composer.json +++ b/composer.json @@ -154,7 +154,8 @@ }, "config": { "allow-plugins": { - "composer/package-versions-deprecated": true + "composer/package-versions-deprecated": true, + "symfony/runtime": true } }, "autoload": { From 2e86de545f248705a574b2b3929809d30ee60521 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 29 Dec 2021 13:48:28 +0100 Subject: [PATCH 73/75] Update CHANGELOG for 4.4.36 --- CHANGELOG-4.4.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index 10a473cffdec6..e3c35bfafa5ad 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,42 @@ 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.36 (2021-12-29) + + * bug #44838 [DependencyInjection][HttpKernel] Fix enum typed bindings (ogizanagi) + * bug #44826 [HttpKernel] Do not attempt to register enum arguments in controller service locator (ogizanagi) + * 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 #44799 [Cache] fix compat with apcu < 5.1.10 (nicolas-grekas) + * bug #44732 [Mime] Relaxing in-reply-to header validation (ThomasLandauer) + * bug #44728 [Mime] Fix encoding filenames in multipart/form-data (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 #44577 [Cache] Fix proxy no expiration to the Redis (Sergey Belyshkin) + * bug #44669 [Cache] disable lock on CLI (nicolas-grekas) + * bug #44537 [Config] In XmlUtils, avoid converting from octal every string starting with a 0 (alexandre-daubois) + * 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 #44601 [HttpClient] Fix closing curl-multi handle too early on destruct (nicolas-grekas) + * 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 #43164 [FrameworkBundle] Fix cache pool configuration with one adapter and one provider (fancyweb) + * 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 #44502 [HttpFoundation] do not call preg_match() on null (xabbuh) + * bug #44467 [Console] Fix parameter types for `ProcessHelper::mustRun()` (derrabus) + * bug #44399 Prevent infinite nesting of lazy `ObjectManager` instances when `ObjectManager` is reset (Ocramius) + * bug #44375 [DoctrineBridge] fix calling get_class on non-object (kbond) + * bug #44361 [HttpClient] Fix handling error info in MockResponse (fancyweb) + * 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 #44269 [DoctrineBridge] Revert " add support for the JSON type" (dunglas) + * 4.4.35 (2021-11-24) * security #cve-2021-41270 [Serializer] Use single quote to escape formulas (jderusse) From 86371d3208c6755c7d5b6782cdb0fa5de4a359e5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 29 Dec 2021 13:48:32 +0100 Subject: [PATCH 74/75] Update CONTRIBUTORS for 4.4.36 --- CONTRIBUTORS.md | 100 ++++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b5e87ad1280f4..48ae19030db84 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -12,15 +12,15 @@ The Symfony Connect username in parenthesis allows to get more information - Tobias Schultze (tobion) - Robin Chalas (chalas_r) - Christophe Coevoet (stof) - - Jérémy DERUSSÉ (jderusse) - Wouter De Jong (wouterj) + - Jérémy DERUSSÉ (jderusse) - Grégoire Pineau (lyrixx) - Maxime Steinhausser (ogizanagi) - Kévin Dunglas (dunglas) - Jordi Boggiano (seldaek) + - Thomas Calvet (fancyweb) - Victor Berchet (victor) - Javier Eguiluz (javier.eguiluz) - - Thomas Calvet (fancyweb) - Ryan Weaver (weaverryan) - Roland Franssen (ro0) - Jakub Zalas (jakubzalas) @@ -54,19 +54,19 @@ The Symfony Connect username in parenthesis allows to get more information - Valentin Udaltsov (vudaltsov) - Iltar van der Berg (kjarli) - Jonathan Wage (jwage) + - Jérôme Tamarelle (gromnan) - Matthias Pigulla (mpdude) - Diego Saint Esteben (dosten) - Grégoire Paris (greg0ire) - Alexandre Salomé (alexandresalome) - - Jérôme Tamarelle (gromnan) - William Durand (couac) - ornicar + - Titouan Galopin (tgalopin) - Konstantin Myakshin (koc) - Dany Maillard (maidmaid) - Francis Besset (francisbesset) - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - - Titouan Galopin (tgalopin) - Laurent VOULLEMIER (lvo) - Vasilij Dusko | CREATION - Bulat Shakirzyanov (avalanche123) @@ -79,10 +79,10 @@ The Symfony Connect username in parenthesis allows to get more information - Miha Vrhovnik - Diego Saint Esteben (dii3g0) - Mathieu Piot (mpiot) + - Antoine M (amakdessi) - Konstantin Kudryashov (everzet) - Vladimir Reznichenko (kalessil) - Bilal Amarni (bamarni) - - Antoine M (amakdessi) - Florin Patan (florinpatan) - Jáchym Toušek (enumag) - Alex Pott @@ -107,24 +107,24 @@ The Symfony Connect username in parenthesis allows to get more information - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) + - Mathieu Santostefano (welcomattic) - Daniel Holmes (dholmes) - Sebastiaan Stok (sstok) + - HypeMC (hypemc) - Toni Uebernickel (havvg) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) - - Mathieu Santostefano (welcomattic) - John Wards (johnwards) - Tomas Norkūnas (norkunas) + - Alexandre Daubois (alexandre-daubois) - Baptiste Clavié (talus) - - HypeMC (hypemc) - Antoine Hérault (herzult) - Paráda József (paradajozsef) - - Alexandre Daubois (alexandre-daubois) - Vincent Langlet (deviling) + - Julien Falque (julienfalque) - Massimiliano Arione (garak) - Arnaud Le Blanc (arnaud-lb) - Przemysław Bogusz (przemyslaw-bogusz) - - Julien Falque (julienfalque) - Maxime STEINHAUSSER - Michal Piotrowski (eventhorizon) - Tomáš Votruba (tomas_votruba) @@ -143,6 +143,7 @@ The Symfony Connect username in parenthesis allows to get more information - Włodzimierz Gajda (gajdaw) - Christian Scheb - Adrien Brault (adrienbrault) + - Maxime Helias (maxhelias) - Yanick Witschi (toflar) - Jacob Dreesen (jdreesen) - Malte Schlüter (maltemaltesich) @@ -152,6 +153,7 @@ The Symfony Connect username in parenthesis allows to get more information - Teoh Han Hui (teohhanhui) - Colin Frei - Javier Spagnoletti (phansys) + - Ruud Kamphuis (ruudk) - Joshua Thijssen - Daniel Wehner (dawehner) - Tugdual Saunier (tucksaun) @@ -159,15 +161,13 @@ The Symfony Connect username in parenthesis allows to get more information - Gordon Franke (gimler) - Saif Eddin Gmati (azjezz) - Richard van Laak (rvanlaak) - - Maxime Helias (maxhelias) + - Gary PEGEOT (gary-p) - Jesse Rushlow (geeshoe) - Fabien Pennequin (fabienpennequin) - Olivier Dolbeau (odolbeau) - Smaine Milianni (ismail1432) - Eric GELOEN (gelo) - - Gary PEGEOT (gary-p) - Matthieu Napoli (mnapoli) - - Ruud Kamphuis (ruudk) - Ion Bazan (ionbazan) - Jannik Zschiesche (apfelbox) - Robert Schönthal (digitalkaoz) @@ -190,6 +190,7 @@ The Symfony Connect username in parenthesis allows to get more information - Albert Casademont (acasademont) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) + - Marco Pivetta (ocramius) - SpacePossum - Alexander Menshchikov (zmey_kk) - Pablo Godel (pgodel) @@ -203,20 +204,23 @@ The Symfony Connect username in parenthesis allows to get more information - jwdeitch - Jeroen Spee (jeroens) - Jérôme Parmentier (lctrs) - - Marco Pivetta (ocramius) - Fabien Bourigault (fbourigault) - Joe Bennett (kralos) - Mikael Pajunen - Andreas Schempp (aschempp) - Alessandro Lai (jean85) - Romaric Drigon (romaricdrigon) + - Christopher Hertel (chertel) - Arman Hosseini (arman) + - Rokas Mikalkėnas (rokasm) - Niels Keurentjes (curry684) - Vyacheslav Pavlov + - Andreas Möller (localheinz) - Richard Shank (iampersistent) - Wouter J - Thomas Rabaix (rande) - Chi-teck + - Baptiste Leduc (korbeil) - Timo Bakx (timobakx) - Vincent Touzet (vincenttouzet) - Nate Wiebe (natewiebe13) @@ -225,16 +229,13 @@ The Symfony Connect username in parenthesis allows to get more information - Ben Davies (bendavies) - Clemens Tolboom - Helmer Aaviksoo - - Christopher Hertel (chertel) - Remon van de Kamp (rpkamp) - - Rokas Mikalkėnas (rokasm) - Filippo Tessarotto (slamdunk) - Hiromi Hishida (77web) - Michael Käfer (michael_kaefer) - Matthieu Ouellette-Vachon (maoueh) - Michał Pipa (michal.pipa) - Dawid Nowak - - Andreas Möller (localheinz) - Roman Martinuk (a2a4) - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) @@ -244,7 +245,6 @@ The Symfony Connect username in parenthesis allows to get more information - Samuel NELA (snela) - David Prévot - Hugo Monteiro (monteiro) - - Baptiste Leduc (korbeil) - Dmitrii Poddubnyi (karser) - zairig imad (zairigimad) - Tien Vo (tienvx) @@ -275,6 +275,7 @@ The Symfony Connect username in parenthesis allows to get more information - Thibaut Cheymol (tcheymol) - Sebastien Morel (plopix) - mcfedr (mcfedr) + - Colin O'Dell (colinodell) - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) - Baptiste Lafontaine (magnetik) @@ -311,7 +312,6 @@ The Symfony Connect username in parenthesis allows to get more information - Matthieu Auger (matthieuauger) - Leszek Prabucki (l3l0) - Nicolas Philippe (nikophil) - - Colin O'Dell (colinodell) - Emanuele Panzeri (thepanz) - François Zaninotto (fzaninotto) - Dustin Whittle (dustinwhittle) @@ -325,6 +325,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sven Paulus (subsven) - Daniel STANCU - Maxime Veber (nek-) + - Sylvain Fabre (sylfabre) - Loick Piera (pyrech) - Clara van Miert - Valentine Boineau (valentineboineau) @@ -340,6 +341,7 @@ The Symfony Connect username in parenthesis allows to get more information - Victor Bocharsky (bocharsky_bw) - Bozhidar Hristov (warxcell) - Marcel Beerta (mazen) + - Thomas Landauer (thomas-landauer) - Pavel Batanov (scaytrase) - Mantis Development - Loïc Faugeron @@ -373,10 +375,11 @@ The Symfony Connect username in parenthesis allows to get more information - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) - Mickaël Andrieu (mickaelandrieu) + - Soner Sayakci - Xavier Perez - Arjen Brouwer (arjenjb) - Katsuhiro OGAWA - - Sylvain Fabre (sylfabre) + - Artem Lopata - Patrick McDougle (patrick-mcdougle) - Marc Weistroff (futurecat) - Alif Rachmawadi @@ -402,7 +405,6 @@ The Symfony Connect username in parenthesis allows to get more information - Jhonny Lidfors (jhonne) - Diego Agulló (aeoris) - jdhoek - - Thomas Landauer (thomas-landauer) - Jurica Vlahoviček (vjurica) - Bob den Otter (bopp) - Thomas Schulz (king2500) @@ -436,7 +438,6 @@ The Symfony Connect username in parenthesis allows to get more information - Wouter Van Hecke - Iker Ibarguren (ikerib) - Bob van de Vijver (bobvandevijver) - - Soner Sayakci - Peter Kruithof (pkruithof) - Michael Holm (hollo) - Arjen van der Meijden @@ -459,6 +460,7 @@ The Symfony Connect username in parenthesis allows to get more information - Manuel Kiessling (manuelkiessling) - Dimitri Gritsajuk (ottaviano) - Alexey Kopytko (sanmai) + - Gijs van Lammeren - Pol Dellaiera (drupol) - Atsuhiro KUBO (iteman) - Alireza Mirsepassi (alirezamirsepassi) @@ -535,7 +537,6 @@ The Symfony Connect username in parenthesis allows to get more information - Christian Gärtner (dagardner) - Dmytro Borysovskyi (dmytr0) - Tomasz Kowalczyk (thunderer) - - Artem Lopata - Artur Eshenbrener - Thomas Perez (scullwm) - Yoann RENARD (yrenard) @@ -553,6 +554,7 @@ The Symfony Connect username in parenthesis allows to get more information - hossein zolfi (ocean) - Clément Gautier (clementgautier) - Koen Reiniers (koenre) + - Hugo Alliaume (kocal) - Sanpi - Eduardo Gulias (egulias) - giulio de donato (liuggio) @@ -560,10 +562,12 @@ The Symfony Connect username in parenthesis allows to get more information - ShinDarth - Stéphane PY (steph_py) - Philipp Kräutli (pkraeutli) + - Rhodri Pugh (rodnaph) - Grzegorz Zdanowski (kiler129) - Kirill chEbba Chebunin (chebba) - - Fabien Villepinte + - SiD (plbsid) - Matthew Grasmick - Greg Thornton (xdissent) - BENOIT POLASZEK (bpolaszek) @@ -575,12 +579,12 @@ The Symfony Connect username in parenthesis allows to get more information - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) - Vyacheslav Salakhutdinov (megazoll) + - Antoine Lamirault - Phil Taylor (prazgod) - Hassan Amouhzi - Tamas Szijarto - Michele Locati - Pavel Volokitin (pvolok) - - Gijs van Lammeren - Arthur de Moulins (4rthem) - Matthias Althaus (althaus) - Nicolas Dewez (nicolas_dewez) @@ -650,6 +654,7 @@ The Symfony Connect username in parenthesis allows to get more information - scyzoryck - Matthias Krauser (mkrauser) - Erkhembayar Gantulga (erheme318) + - Alexis Lefebvre - Lorenzo Millucci (lmillucci) - Jérôme Tamarelle (jtamarelle-prismamedia) - Andrii Popov (andrii-popov) @@ -677,6 +682,7 @@ The Symfony Connect username in parenthesis allows to get more information - Chris Sedlmayr (catchamonkey) - Indra Gunawan (indragunawan) - Mathias STRASSER (roukmoute) + - simon chrzanowski (simonch) - Kamil Kokot (pamil) - Seb Koelen - Christoph Mewes (xrstf) @@ -719,7 +725,6 @@ The Symfony Connect username in parenthesis allows to get more information - Marek Zajac - Adam Harvey - Anton Bakai - - Rhodri Pugh (rodnaph) - battye - Sam Fleming (sam_fleming) - William Arslett @@ -749,7 +754,6 @@ The Symfony Connect username in parenthesis allows to get more information - Sebastian Bergmann - Miroslav Sustek - Pablo Díez (pablodip) - - SiD (plbsid) - Michel Roca (mroca) - Kevin McBride - Sergio Santoro @@ -780,6 +784,7 @@ The Symfony Connect username in parenthesis allows to get more information - Markus Lanthaler (lanthaler) - Remi Collet - Vicent Soria Durá (vicentgodella) + - Daniel Gorgan - Michael Moravec - Carlos Buenosvinos (carlosbuenosvinos) - Leevi Graham (leevigraham) @@ -799,6 +804,7 @@ The Symfony Connect username in parenthesis allows to get more information - Scott Arciszewski - Xavier HAUSHERR - Norbert Orzechowicz (norzechowicz) + - stlrnz - Denis Charrier (brucewouaigne) - Matthijs van den Bos (matthijs) - Simon Podlipsky (simpod) @@ -912,8 +918,8 @@ The Symfony Connect username in parenthesis allows to get more information - vitaliytv - Nicolas Martin (cocorambo) - Adrian Nguyen (vuphuong87) + - Khoo Yong Jun - Sebastian Blum - - Alexis Lefebvre - Laurent Clouet - aubx - Julien Turby @@ -930,6 +936,7 @@ The Symfony Connect username in parenthesis allows to get more information - pizzaminded - Stéphane Escandell (sescandell) - Konstantin S. M. Möllers (ksmmoellers) + - Fractal Zombie - linh - James Johnston - Sinan Eldem @@ -978,6 +985,7 @@ The Symfony Connect username in parenthesis allows to get more information - Evgeny Anisiforov - smoench - Max Grigorian (maxakawizard) + - Martins Sipenko - Guilherme Augusto Henschel - Rostyslav Kinash - Cristoforo Cervino (cristoforocervino) @@ -1021,9 +1029,11 @@ The Symfony Connect username in parenthesis allows to get more information - Tomas Javaisis - Ivan Grigoriev - Johann Saunier (prophet777) + - Kevin SCHNEKENBURGER - Fabien Salles (blacked) - Andreas Erhard - John VanDeWeghe + - Sergey Belyshkin - Michael Devery (mickadoo) - Antoine Corcy - Ahmed Ashraf (ahmedash95) @@ -1085,6 +1095,7 @@ The Symfony Connect username in parenthesis allows to get more information - Roromix - Maxime AILLOUD (mailloud) - Richard van den Brand (ricbra) + - Toon Verwerft (veewee) - mohammadreza honarkhah - develop - flip111 @@ -1191,6 +1202,7 @@ The Symfony Connect username in parenthesis allows to get more information - Julien Pauli - Dominik Piekarski (dompie) - Rares Sebastian Moldovan (raresmldvn) + - Jérémy REYNAUD (babeuloula) - Mathieu Rochette (mathroc) - Victor Garcia - Jérôme Tanghe (deuchnord) @@ -1239,7 +1251,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tito Costa - Jan Prieser - GDIBass - - Antoine Lamirault + - Maximilian Bösing - Thiago Melo - Adrien Lucas (adrienlucas) - Zhuravlev Alexander (scif) @@ -1300,7 +1312,6 @@ The Symfony Connect username in parenthesis allows to get more information - Loïc Beurlet - Sébastien COURJEAN - Ana Raro - - Daniel Gorgan - Ana Raro - Tony Malzhacker - Pchol @@ -1380,13 +1391,14 @@ The Symfony Connect username in parenthesis allows to get more information - Forfarle (forfarle) - Harry Walter (haswalt) - Johnson Page (jwpage) + - Kuba Werłos (kuba) - Ruben Gonzalez (rubenruateltek) - Michael Roterman (wtfzdotnet) + - Philipp Keck - Arno Geurts - Adán Lobato (adanlobato) - Ian Jenkins (jenkoian) - Kai Eichinger (kai_eichinger) - - Hugo Alliaume (kocal) - Marcos Gómez Vilches (markitosgv) - Matthew Davis (mdavis1982) - Paulo Ribeiro (paulo) @@ -1396,7 +1408,6 @@ The Symfony Connect username in parenthesis allows to get more information - Antoine LA - den - Pavol Tuka - - stlrnz - pawel-lewtak - omerida - Gábor Tóth @@ -1476,9 +1487,7 @@ The Symfony Connect username in parenthesis allows to get more information - neghmurken - xaav - Mahmoud Mostafa (mahmoud) - - Fractal Zombie - Ahmed Abdou - - Khoo Yong Jun - shreyadenny - Daniel Iwaniec - Pieter @@ -1509,6 +1518,7 @@ The Symfony Connect username in parenthesis allows to get more information - LHommet Nicolas (nicolaslh) - fabios - Sander Coolen (scoolen) + - Emil Masiakowski - Amirreza Shafaat (amirrezashafaat) - Adoni Pavlakis (adoni) - Nicolas Le Goff (nlegoff) @@ -1628,6 +1638,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jean-Guilhem Rouel (jean-gui) - Yoann MOROCUTTI - jfcixmedia + - Tomasz Kusy - Dominic Tubach - Nikita Konstantinov - Martijn Evers @@ -1635,6 +1646,7 @@ The Symfony Connect username in parenthesis allows to get more information - Philipp Fritsche - tarlepp - Benjamin Paap (benjaminpaap) + - Guillaume Aveline - Christian - Denis Golubovskiy (bukashk0zzz) - Arkadiusz Rzadkowolski (flies) @@ -1647,7 +1659,6 @@ The Symfony Connect username in parenthesis allows to get more information - hugofonseca (fonsecas72) - Marc Duboc (icemad) - Martynas Narbutas - - Toon Verwerft (veewee) - Bailey Parker - Eddie Jaoude - Antanas Arvasevicius @@ -1716,6 +1727,7 @@ The Symfony Connect username in parenthesis allows to get more information - Charles Sanquer (csanquer) - Albert Ganiev (helios-ag) - Neil Katin + - Oleg Mifle - David Otton - Will Donohoe - gnito-org @@ -1740,13 +1752,13 @@ The Symfony Connect username in parenthesis allows to get more information - Amine Yakoubi - Eduardo García Sanz (coma) - Sergio (deverad) - - simon chrzanowski (simonch) - Makdessi Alex - James Gilliland - fduch (fduch) - Juan Miguel Besada Vidal (soutlink) - dlorek - Stuart Fyfe + - Jason Schilling (chapterjason) - David de Boer (ddeboer) - Eno Mullaraj (emullaraj) - Nathan PAGE (nathix) @@ -1765,6 +1777,7 @@ The Symfony Connect username in parenthesis allows to get more information - Roger Webb - Dmitriy Simushev - Pawel Smolinski + - Simon Watiau (simonwatiau) - Oxan van Leeuwen - pkowalczyk - Soner Sayakci @@ -1815,6 +1828,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dmitri Petmanson - heccjj - Alexandre Melard + - PierreRebeilleau - Jay Klehr - Sergey Yuferev - Tobias Stöckler @@ -1954,7 +1968,6 @@ The Symfony Connect username in parenthesis allows to get more information - Wojciech Błoszyk (wbloszyk) - Giorgio Premi - abunch - - Sergey Belyshkin - tamcy - Mikko Pesari - ncou @@ -1982,6 +1995,7 @@ The Symfony Connect username in parenthesis allows to get more information - Raphaëll Roussel - Tadcka - Beth Binkovitz + - Maxim Semkin - Gonzalo Míguez - Fabian Haase - Romain Geissler @@ -2027,6 +2041,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tony Vermeiren (tony) - Bart Wach - Jos Elstgeest + - Kirill Lazarev - Thomas Counsell - BilgeXA - r1pp3rj4ck @@ -2197,6 +2212,7 @@ The Symfony Connect username in parenthesis allows to get more information - Matt Farmer - catch - aetxebeste + - Vitali Tsyrkin - Juga Paazmaya - Alexandre Segura - afaricamp @@ -2249,6 +2265,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andreas - Markus - agaktr + - Mostafa - kernig - Thomas Chmielowiec - shdev @@ -2276,6 +2293,7 @@ The Symfony Connect username in parenthesis allows to get more information - Christoph Nissle (derstoffel) - Denys Voronin (hurricane) - Ionel Scutelnicu (ionelscutelnicu) + - Juan Gonzalez Montes (juanwilde) - Mathieu Dewet (mdewet) - Nicolas Tallefourtané (nicolab) - Botond Dani (picur) @@ -2294,7 +2312,6 @@ The Symfony Connect username in parenthesis allows to get more information - Christopher Parotat - Dennis Haarbrink - me_shaon - - Maximilian Bösing - 蝦米 - Grayson Koonce (breerly) - Andrey Helldar (helldar) @@ -2373,6 +2390,7 @@ The Symfony Connect username in parenthesis allows to get more information - Cyril Pascal (paxal) - Cédric Dugat (ph3nol) - Philip Dahlstrøm (phidah) + - Pierre Rebeilleau (pierrereb) - Milos Colakovic (project2481) - Raphael de Almeida (raphaeldealmeida) - Rénald Casagraude (rcasagraude) @@ -2435,6 +2453,7 @@ The Symfony Connect username in parenthesis allows to get more information - Peter Breuls - Chansig - Tischoi + - divinity76 - Andreas Hasenack - J Bruni - Alexey Prilipko @@ -2468,6 +2487,7 @@ The Symfony Connect username in parenthesis allows to get more information - Pedro Magalhães (pmmaga) - Rares Vlaseanu (raresvla) - Sergii Dolgushev (serhey) + - Rein Baarsma (solidwebcode) - tante kinast (tante) - Stephen Lewis (tehanomalousone) - Ahmed Hannachi (tiecoders) @@ -2525,6 +2545,7 @@ The Symfony Connect username in parenthesis allows to get more information - grifx - Robert Campbell - Matt Lehner + - Olexandr Kalaidzhy - Helmut Januschka - Hein Zaw Htet™ - Ruben Kruiswijk @@ -2585,6 +2606,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gerrit Drost - Linnaea Von Lavia - Bastien Clément + - Julius Šakalys - Javan Eskander - Lenar Lõhmus - Cristian Gonzalez @@ -2596,7 +2618,6 @@ The Symfony Connect username in parenthesis allows to get more information - Pavinthan - Sylvain METAYER - ddebree - - Kuba Werłos - Gyula Szucs - Tomas Liubinas - Ivo Valchev @@ -2664,7 +2685,6 @@ The Symfony Connect username in parenthesis allows to get more information - Geordie - Exploit.cz - GuillaumeVerdon - - Philipp Keck - Angel Fernando Quiroz Campos - Ondrej Mirtes - akimsko @@ -2726,6 +2746,7 @@ The Symfony Connect username in parenthesis allows to get more information - arend - Vincent Godé - Dusan Kasan + - helmi - Michael Steininger - Nardberjean - Karolis @@ -2865,6 +2886,7 @@ The Symfony Connect username in parenthesis allows to get more information - Babichev Maxim - Edvin Hultberg - Benjamin Long + - Kévin Gonella - Ben Miller - Peter Gribanov - Ash014 @@ -2896,6 +2918,7 @@ The Symfony Connect username in parenthesis allows to get more information - Steve Marvell - Dawid Nowak - Lesnykh Ilia + - Shyim - sabruss - darnel - Karolis Daužickas @@ -2943,6 +2966,7 @@ The Symfony Connect username in parenthesis allows to get more information - Christian Gripp (core23) - Christoph Schaefer (cvschaefer) - Damon Jones (damon__jones) + - Alexandre Fiocre (demos77) - Łukasz Giza (destroyer) - Daniel Londero (dlondero) - Sebastian Landwehr (dword123) From b12261d022182de649af4af8b00849dd924eae97 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 29 Dec 2021 13:48:41 +0100 Subject: [PATCH 75/75] Update VERSION for 4.4.36 --- 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 398f4c102cca0..021f6c8cfd9c4 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.36-DEV'; + public const VERSION = '4.4.36'; public const VERSION_ID = 40436; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 36; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023';