From 55a926f63b9e5e3bc709b5b9dba00bac8dc324b6 Mon Sep 17 00:00:00 2001 From: Younes ENNAJI Date: Sun, 23 Nov 2025 14:47:02 +0100 Subject: [PATCH 01/17] [FrameworkBundle] Fix TypeError when traversing scalar values in debug:config --- Command/ConfigDebugCommand.php | 2 +- Tests/Functional/ConfigDebugCommandTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Command/ConfigDebugCommand.php b/Command/ConfigDebugCommand.php index fb79b39bf..fcef7c1d6 100644 --- a/Command/ConfigDebugCommand.php +++ b/Command/ConfigDebugCommand.php @@ -161,7 +161,7 @@ private function getConfigForPath(array $config, string $path, string $alias): m $steps = explode('.', $path); foreach ($steps as $step) { - if (!\array_key_exists($step, $config)) { + if (!\is_array($config) || !\array_key_exists($step, $config)) { throw new LogicException(\sprintf('Unable to find configuration for "%s.%s".', $alias, $path)); } diff --git a/Tests/Functional/ConfigDebugCommandTest.php b/Tests/Functional/ConfigDebugCommandTest.php index 2c47121c1..c0ac23c5e 100644 --- a/Tests/Functional/ConfigDebugCommandTest.php +++ b/Tests/Functional/ConfigDebugCommandTest.php @@ -264,6 +264,16 @@ public static function provideCompletionSuggestions(): \Generator yield 'option --format, debug' => [true, ['--format', ''], ['yaml', 'json']]; } + public function testDumpPathDeepIntoScalar() + { + $tester = $this->createCommandTester(true); + + $tester->execute(['name' => 'framework', 'path' => 'secret.foo']); + + $this->assertSame(1, $tester->getStatusCode()); + $this->assertStringContainsString('Unable to find configuration for "framework.secret.foo"', $tester->getDisplay()); + } + private function createCommandTester(bool $debug): CommandTester { $command = $this->createApplication($debug)->find('debug:config'); From d4a63242ca06104d5651333974d3808318d0a8b6 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Mon, 24 Nov 2025 15:56:59 +0100 Subject: [PATCH 02/17] [FrameworkBundle] fix merging of enabled locales --- DependencyInjection/FrameworkExtension.php | 4 ++-- .../Fixtures/php/translator_providers.php | 19 +++++++++++++++ .../Fixtures/xml/translator_providers.xml | 24 +++++++++++++++++++ .../Fixtures/yml/translator_providers.yml | 13 ++++++++++ .../FrameworkExtensionTestCase.php | 7 ++++++ 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 Tests/DependencyInjection/Fixtures/php/translator_providers.php create mode 100644 Tests/DependencyInjection/Fixtures/xml/translator_providers.xml create mode 100644 Tests/DependencyInjection/Fixtures/yml/translator_providers.yml diff --git a/DependencyInjection/FrameworkExtension.php b/DependencyInjection/FrameworkExtension.php index 7be9999b4..568fdd66c 100644 --- a/DependencyInjection/FrameworkExtension.php +++ b/DependencyInjection/FrameworkExtension.php @@ -1622,11 +1622,11 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder foreach ($config['providers'] as $provider) { if ($provider['locales']) { - $locales += $provider['locales']; + $locales = array_merge($locales, $provider['locales']); } } - $locales = array_unique($locales); + $locales = array_values(array_unique($locales)); $container->getDefinition('console.command.translation_pull') ->replaceArgument(4, array_merge($transPaths, [$config['default_path']])) diff --git a/Tests/DependencyInjection/Fixtures/php/translator_providers.php b/Tests/DependencyInjection/Fixtures/php/translator_providers.php new file mode 100644 index 000000000..f8314d5a5 --- /dev/null +++ b/Tests/DependencyInjection/Fixtures/php/translator_providers.php @@ -0,0 +1,19 @@ +loadFromExtension('framework', [ + 'annotations' => false, + 'http_method_override' => false, + 'handle_all_throwables' => true, + 'php_errors' => ['log' => true], + 'enabled_locales' => ['es'], + 'translator' => [ + 'providers' => [ + 'foo_provider' => [ + 'locales' => ['en', 'fr'], + ], + 'bar_provider' => [ + 'locales' => ['de', 'pl'], + ] + ] + ], +]); diff --git a/Tests/DependencyInjection/Fixtures/xml/translator_providers.xml b/Tests/DependencyInjection/Fixtures/xml/translator_providers.xml new file mode 100644 index 000000000..31510b3ed --- /dev/null +++ b/Tests/DependencyInjection/Fixtures/xml/translator_providers.xml @@ -0,0 +1,24 @@ + + + + + + + + es + + + en + fr + + + de + pl + + + + diff --git a/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml b/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml new file mode 100644 index 000000000..084a10b80 --- /dev/null +++ b/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml @@ -0,0 +1,13 @@ +framework: + annotations: false + http_method_override: false + handle_all_throwables: true + enabled_locales: [ 'es' ] + php_errors: + log: true + translator: + providers: + foo_provider: + locales: [ 'en', 'fr' ] + bar_provider: + locales: [ 'de', 'pl' ] diff --git a/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/Tests/DependencyInjection/FrameworkExtensionTestCase.php index d6df2205d..eef29da26 100644 --- a/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -1262,6 +1262,13 @@ public function testTranslator() $this->assertSame('Fixtures/translations', $options['cache_vary']['scanned_directories'][3]); } + public function testTranslatorProvidersMergedEnabledLocales() + { + $container = $this->createContainerFromFile('translator_providers'); + self::assertSame(['es', 'en', 'fr', 'de', 'pl'], $container->getDefinition('console.command.translation_pull')->getArgument(5)); + self::assertSame(['es', 'en', 'fr', 'de', 'pl'], $container->getDefinition('console.command.translation_push')->getArgument(3)); + } + public function testTranslatorMultipleFallbacks() { $container = $this->createContainerFromFile('translator_fallbacks'); From 90bc9961c54b7b20541d2ed65b6d4f8b09a0e8a1 Mon Sep 17 00:00:00 2001 From: matlec Date: Wed, 26 Nov 2025 12:16:55 +0100 Subject: [PATCH 03/17] [FrameworkBundle] Add missing `useAttributeAsKey` calls --- DependencyInjection/Configuration.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 992c265a7..ca579c49a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -1857,6 +1857,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->end() ->arrayNode('vars') ->info('Associative array: the default vars used to expand the templated URI.') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() @@ -1937,6 +1938,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->end() ->arrayNode('extra') ->info('Extra options for specific HTTP client') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() @@ -2088,6 +2090,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->end() ->arrayNode('extra') ->info('Extra options for specific HTTP client') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() From db3a0282c09e2eed5f4c421a2fbead63b466993a Mon Sep 17 00:00:00 2001 From: Bert Hekman Date: Wed, 26 Nov 2025 14:15:06 +0100 Subject: [PATCH 04/17] [FrameworkBundle] Allow backed enum to be used in initial_marking workflow configuration --- DependencyInjection/Configuration.php | 13 ++++++++++++- Tests/DependencyInjection/ConfigurationTest.php | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e8e11d071..c3f3b16c7 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -463,8 +463,19 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void ->cannotBeEmpty() ->end() ->arrayNode('initial_marking') - ->acceptAndWrap(['string']) + ->acceptAndWrap(['backed-enum', 'string']) ->defaultValue([]) + ->beforeNormalization() + ->ifArray() + ->then(static function ($markings) { + $normalizedMarkings = []; + foreach ($markings as $marking) { + $normalizedMarkings[] = $marking instanceof \BackedEnum ? $marking->value : $marking; + } + + return $normalizedMarkings; + }) + ->end() ->prototype('scalar')->end() ->end() ->arrayNode('events_to_dispatch', 'event_to_dispatch') diff --git a/Tests/DependencyInjection/ConfigurationTest.php b/Tests/DependencyInjection/ConfigurationTest.php index e921b09d8..c68b805b7 100644 --- a/Tests/DependencyInjection/ConfigurationTest.php +++ b/Tests/DependencyInjection/ConfigurationTest.php @@ -711,6 +711,7 @@ public function testWorkflowEnumArcsNormalization() 'enum' => [ 'supports' => [self::class], 'places' => Places::cases(), + 'initial_marking' => Places::A, 'transitions' => [ [ 'name' => 'one', @@ -728,6 +729,8 @@ public function testWorkflowEnumArcsNormalization() ], ]]); + $this->assertSame(['a'], $config['workflows']['workflows']['enum']['initial_marking']); + $transitions = $config['workflows']['workflows']['enum']['transitions']; $this->assertSame('one', $transitions[0]['name']); From c0b0307e160478a37235282a5b86ae7303e35f39 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 28 Nov 2025 15:12:36 +0100 Subject: [PATCH 05/17] register attribute loader arguments in a forward-compatible way --- DependencyInjection/FrameworkExtension.php | 3 ++- ...es_enabled_annotations_enabled_globally.php | 8 ++++++++ ...es_enabled_annotations_enabled_globally.xml | 10 ++++++++++ ...es_enabled_annotations_enabled_globally.yml | 4 ++++ .../FrameworkExtensionTestCase.php | 18 ++++++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Tests/DependencyInjection/Fixtures/php/serializer_attributes_enabled_annotations_enabled_globally.php create mode 100644 Tests/DependencyInjection/Fixtures/xml/serializer_attributes_enabled_annotations_enabled_globally.xml create mode 100644 Tests/DependencyInjection/Fixtures/yml/serializer_attributes_enabled_annotations_enabled_globally.yml diff --git a/DependencyInjection/FrameworkExtension.php b/DependencyInjection/FrameworkExtension.php index 7be9999b4..851e99c99 100644 --- a/DependencyInjection/FrameworkExtension.php +++ b/DependencyInjection/FrameworkExtension.php @@ -163,6 +163,7 @@ use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Serializer; @@ -1954,7 +1955,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder if (isset($config['enable_attributes']) && $config['enable_attributes']) { $annotationLoader = new Definition( AttributeLoader::class, - [new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)] + interface_exists(CacheableSupportsMethodInterface::class) ? [new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)] : [], ); $serializerLoaders[] = $annotationLoader; diff --git a/Tests/DependencyInjection/Fixtures/php/serializer_attributes_enabled_annotations_enabled_globally.php b/Tests/DependencyInjection/Fixtures/php/serializer_attributes_enabled_annotations_enabled_globally.php new file mode 100644 index 000000000..95bda0631 --- /dev/null +++ b/Tests/DependencyInjection/Fixtures/php/serializer_attributes_enabled_annotations_enabled_globally.php @@ -0,0 +1,8 @@ +loadFromExtension('framework', [ + 'annotations' => true, + 'serializer' => [ + 'enable_attributes' => true, + ], +]); diff --git a/Tests/DependencyInjection/Fixtures/xml/serializer_attributes_enabled_annotations_enabled_globally.xml b/Tests/DependencyInjection/Fixtures/xml/serializer_attributes_enabled_annotations_enabled_globally.xml new file mode 100644 index 000000000..7d228c58e --- /dev/null +++ b/Tests/DependencyInjection/Fixtures/xml/serializer_attributes_enabled_annotations_enabled_globally.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/Tests/DependencyInjection/Fixtures/yml/serializer_attributes_enabled_annotations_enabled_globally.yml b/Tests/DependencyInjection/Fixtures/yml/serializer_attributes_enabled_annotations_enabled_globally.yml new file mode 100644 index 000000000..0a56dd0bd --- /dev/null +++ b/Tests/DependencyInjection/Fixtures/yml/serializer_attributes_enabled_annotations_enabled_globally.yml @@ -0,0 +1,4 @@ +framework: + annotations: true + serializer: + enable_attributes: true diff --git a/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/Tests/DependencyInjection/FrameworkExtensionTestCase.php index d6df2205d..1445b4b13 100644 --- a/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -67,6 +67,7 @@ use Symfony\Component\Notifier\TexterInterface; use Symfony\Component\PropertyAccess\PropertyAccessor; use Symfony\Component\Security\Core\AuthenticationEvents; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; @@ -1711,6 +1712,23 @@ public function testSerializerCacheNotActivatedWithAnnotations() $this->assertFalse($container->hasDefinition('serializer.mapping.cache_class_metadata_factory')); } + /** + * @group legacy + */ + public function testSerializerAttributesEnabledAnnotationsEnabledGlobally() + { + $container = $this->createContainerFromFile('serializer_attributes_enabled_annotations_enabled_globally'); + $cacheWarmer = $container->getDefinition('serializer.mapping.cache_warmer'); + $loaders = $cacheWarmer->getArgument(0); + $attributeLoader = $loaders[0]; + + if (class_exists(AnnotationLoader::class)) { + $this->assertEquals([new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)], $attributeLoader->getArguments()); + } else { + $this->assertSame([], $attributeLoader->getArguments()); + } + } + public function testSerializerMapping() { $container = $this->createContainerFromFile('serializer_mapping_without_annotations', ['kernel.bundles_metadata' => ['TestBundle' => ['namespace' => 'Symfony\\Bundle\\FrameworkBundle\\Tests', 'path' => __DIR__.'/Fixtures/TestBundle']]]); From bb4cf32c77bd0db650b601676d9eccbd861dafe8 Mon Sep 17 00:00:00 2001 From: Silas Joisten Date: Sat, 29 Nov 2025 11:35:36 +0100 Subject: [PATCH 06/17] fix: Typehint for `createForm` in abstractController --- Controller/AbstractController.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Controller/AbstractController.php b/Controller/AbstractController.php index 4f2656688..6c9b829e2 100644 --- a/Controller/AbstractController.php +++ b/Controller/AbstractController.php @@ -20,6 +20,8 @@ use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\Flow\FormFlowInterface; +use Symfony\Component\Form\Flow\FormFlowTypeInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\JsonResponse; @@ -349,6 +351,8 @@ protected function createAccessDeniedException(string $message = 'Access Denied. /** * Creates and returns a Form instance from the type of the form. + * + * @return ($type is class-string ? FormFlowInterface : FormInterface) */ protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface { From 0af40dff1cca4bb4e73ce039e56388a4439aa0d1 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 29 Nov 2025 12:50:54 +0100 Subject: [PATCH 07/17] sync ControllerHelper docblock with latest AbstractController changes --- Controller/AbstractController.php | 6 +++--- Controller/ControllerHelper.php | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Controller/AbstractController.php b/Controller/AbstractController.php index 6c9b829e2..c07c0c055 100644 --- a/Controller/AbstractController.php +++ b/Controller/AbstractController.php @@ -17,11 +17,11 @@ use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Flow\FormFlowInterface; +use Symfony\Component\Form\Flow\FormFlowTypeInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\Flow\FormFlowInterface; -use Symfony\Component\Form\Flow\FormFlowTypeInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\JsonResponse; @@ -351,7 +351,7 @@ protected function createAccessDeniedException(string $message = 'Access Denied. /** * Creates and returns a Form instance from the type of the form. - * + * * @return ($type is class-string ? FormFlowInterface : FormInterface) */ protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface diff --git a/Controller/ControllerHelper.php b/Controller/ControllerHelper.php index f240f33f1..424ab9262 100644 --- a/Controller/ControllerHelper.php +++ b/Controller/ControllerHelper.php @@ -17,6 +17,8 @@ use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Flow\FormFlowInterface; +use Symfony\Component\Form\Flow\FormFlowTypeInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; @@ -342,6 +344,8 @@ public function createAccessDeniedException(string $message = 'Access Denied.', /** * Creates and returns a Form instance from the type of the form. + * + * @return ($type is class-string ? FormFlowInterface : FormInterface) */ public function createForm(string $type, mixed $data = null, array $options = []): FormInterface { From 62c5e1a40346e800fbb18d42932b6d17d3b8ab4d Mon Sep 17 00:00:00 2001 From: matlec Date: Thu, 27 Nov 2025 09:39:43 +0100 Subject: [PATCH 08/17] [FrameworkBundle] Dump bundles config reference first --- .../Compiler/PhpConfigReferenceDumpPass.php | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/DependencyInjection/Compiler/PhpConfigReferenceDumpPass.php b/DependencyInjection/Compiler/PhpConfigReferenceDumpPass.php index 5c468a562..9a0bf4093 100644 --- a/DependencyInjection/Compiler/PhpConfigReferenceDumpPass.php +++ b/DependencyInjection/Compiler/PhpConfigReferenceDumpPass.php @@ -95,15 +95,7 @@ public function process(ContainerBuilder $container): void $appTypes = ''; $anyEnvExtensions = []; - foreach ($container->getExtensions() as $alias => $extension) { - if (!$configuration = $this->getConfiguration($extension, $container)) { - continue; - } - - $anyEnvExtensions[$alias] = $extension; - $type = $this->camelCase($alias).'Config'; - $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree())); - } + $registeredExtensions = $container->getExtensions(); foreach ($this->bundlesDefinition as $bundle => $envs) { if (!is_subclass_of($bundle, BundleInterface::class)) { continue; @@ -111,19 +103,20 @@ public function process(ContainerBuilder $container): void if (!$extension = (new $bundle())->getContainerExtension()) { continue; } - if (!$configuration = $this->getConfiguration($extension, $container)) { - continue; - } $extensionAlias = $extension->getAlias(); - if (isset($anyEnvExtensions[$extensionAlias])) { - $extension = $anyEnvExtensions[$extensionAlias]; - } else { - $anyEnvExtensions[$extensionAlias] = $extension; - $type = $this->camelCase($extensionAlias).'Config'; - $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree())); + if (isset($registeredExtensions[$extensionAlias])) { + $extension = $registeredExtensions[$extensionAlias]; + unset($registeredExtensions[$extensionAlias]); } + if (!$configuration = $this->getConfiguration($extension, $container)) { + continue; + } + $anyEnvExtensions[$extensionAlias] = $extension; + $type = $this->camelCase($extensionAlias).'Config'; + $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree())); + foreach ($knownEnvs as $env) { if ($envs[$env] ?? $envs['all'] ?? false) { $extensionsPerEnv[$env][] = $extension; @@ -132,6 +125,14 @@ public function process(ContainerBuilder $container): void } } } + foreach ($registeredExtensions as $alias => $extension) { + if (!$configuration = $this->getConfiguration($extension, $container)) { + continue; + } + $anyEnvExtensions[$alias] = $extension; + $type = $this->camelCase($alias).'Config'; + $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree())); + } krsort($extensionsPerEnv); $r = new \ReflectionClass(AppReference::class); From c1361334eed2215d3764364216dd472830149e50 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 1 Dec 2025 11:11:17 +0100 Subject: [PATCH 09/17] fix merge --- .../Fixtures/php/translator_providers.php | 4 ---- .../Fixtures/xml/translator_providers.xml | 24 ------------------- .../Fixtures/yml/translator_providers.yml | 5 ---- 3 files changed, 33 deletions(-) delete mode 100644 Tests/DependencyInjection/Fixtures/xml/translator_providers.xml diff --git a/Tests/DependencyInjection/Fixtures/php/translator_providers.php b/Tests/DependencyInjection/Fixtures/php/translator_providers.php index f8314d5a5..9f8d36631 100644 --- a/Tests/DependencyInjection/Fixtures/php/translator_providers.php +++ b/Tests/DependencyInjection/Fixtures/php/translator_providers.php @@ -1,10 +1,6 @@ loadFromExtension('framework', [ - 'annotations' => false, - 'http_method_override' => false, - 'handle_all_throwables' => true, - 'php_errors' => ['log' => true], 'enabled_locales' => ['es'], 'translator' => [ 'providers' => [ diff --git a/Tests/DependencyInjection/Fixtures/xml/translator_providers.xml b/Tests/DependencyInjection/Fixtures/xml/translator_providers.xml deleted file mode 100644 index 31510b3ed..000000000 --- a/Tests/DependencyInjection/Fixtures/xml/translator_providers.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - es - - - en - fr - - - de - pl - - - - diff --git a/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml b/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml index 084a10b80..cb229904f 100644 --- a/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml +++ b/Tests/DependencyInjection/Fixtures/yml/translator_providers.yml @@ -1,10 +1,5 @@ framework: - annotations: false - http_method_override: false - handle_all_throwables: true enabled_locales: [ 'es' ] - php_errors: - log: true translator: providers: foo_provider: From 1ee5cfe092c30ef2d01ca539b73e076671688292 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 2 Dec 2025 09:23:48 +0100 Subject: [PATCH 10/17] [FrameworkBundle] Order alphabetically known tags of `UnusedTagsPass` --- DependencyInjection/Compiler/UnusedTagsPass.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/Compiler/UnusedTagsPass.php b/DependencyInjection/Compiler/UnusedTagsPass.php index 36e3ee1ae..c07116e26 100644 --- a/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/DependencyInjection/Compiler/UnusedTagsPass.php @@ -70,6 +70,8 @@ class UnusedTagsPass implements CompilerPassInterface 'mime.mime_type_guesser', 'monolog.logger', 'notifier.channel', + 'object_mapper.condition_callable', + 'object_mapper.transform_callable', 'property_info.access_extractor', 'property_info.constructor_extractor', 'property_info.initializable_extractor', @@ -108,8 +110,6 @@ class UnusedTagsPass implements CompilerPassInterface 'validator.group_provider', 'validator.initializer', 'workflow', - 'object_mapper.transform_callable', - 'object_mapper.condition_callable', ]; public function process(ContainerBuilder $container): void From e9d3eba8d847f525499b89051fb54e254cb7037c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 4 Dec 2025 17:04:06 +0100 Subject: [PATCH 11/17] [FrameworkBundle] Don't exclude classes with constraint/serialization attributes from being registered as services --- DependencyInjection/FrameworkExtension.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/DependencyInjection/FrameworkExtension.php b/DependencyInjection/FrameworkExtension.php index 8fb602947..2f9748cf9 100644 --- a/DependencyInjection/FrameworkExtension.php +++ b/DependencyInjection/FrameworkExtension.php @@ -1855,8 +1855,7 @@ private function registerValidationConfiguration(array $config, ContainerBuilder if (class_exists(ValidatorAttributeMetadataPass::class) && (!($config['enable_attributes'] ?? false) || !$container->getParameter('kernel.debug')) && trait_exists(ArgumentTrait::class)) { // The $reflector argument hints at where the attribute could be used $container->registerAttributeForAutoconfiguration(Constraint::class, static function (ChildDefinition $definition, Constraint $attribute, \ReflectionClass|\ReflectionMethod|\ReflectionProperty $reflector) { - $definition->addTag('validator.attribute_metadata') - ->addTag('container.excluded', ['source' => 'because it\'s a validator constraint extension']); + $definition->addTag('validator.attribute_metadata'); }); } @@ -2121,15 +2120,13 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder if (class_exists(SerializerAttributeMetadataPass::class) && (!($config['enable_attributes'] ?? false) || !$container->getParameter('kernel.debug'))) { // The $reflector argument hints at where the attribute could be used $configurator = static function (ChildDefinition $definition, object $attribute, \ReflectionClass|\ReflectionMethod|\ReflectionProperty $reflector) { - $definition->addTag('serializer.attribute_metadata') - ->addTag('container.excluded', ['source' => 'because it\'s a serializer metadata extension']); + $definition->addTag('serializer.attribute_metadata'); }; $container->registerAttributeForAutoconfiguration(SerializerMapping\Context::class, $configurator); $container->registerAttributeForAutoconfiguration(SerializerMapping\Groups::class, $configurator); $configurator = static function (ChildDefinition $definition, object $attribute, \ReflectionMethod|\ReflectionProperty $reflector) { - $definition->addTag('serializer.attribute_metadata') - ->addTag('container.excluded', ['source' => 'because it\'s a serializer metadata extension']); + $definition->addTag('serializer.attribute_metadata'); }; $container->registerAttributeForAutoconfiguration(SerializerMapping\Ignore::class, $configurator); $container->registerAttributeForAutoconfiguration(SerializerMapping\MaxDepth::class, $configurator); @@ -2137,8 +2134,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $container->registerAttributeForAutoconfiguration(SerializerMapping\SerializedPath::class, $configurator); $container->registerAttributeForAutoconfiguration(SerializerMapping\DiscriminatorMap::class, static function (ChildDefinition $definition) { - $definition->addTag('serializer.attribute_metadata') - ->addTag('container.excluded', ['source' => 'because it\'s a serializer metadata extension']); + $definition->addTag('serializer.attribute_metadata'); }); } From 7c12bc603d41d44da94271f1d9803baf437a1686 Mon Sep 17 00:00:00 2001 From: Andreas Schempp Date: Mon, 1 Dec 2025 08:32:25 +0100 Subject: [PATCH 12/17] [DependencyInjection][FrameworkBundle] fix BC break when dumping container for build/lint commands --- Command/BuildDebugContainerTrait.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Command/BuildDebugContainerTrait.php b/Command/BuildDebugContainerTrait.php index 011510095..7a279f5dd 100644 --- a/Command/BuildDebugContainerTrait.php +++ b/Command/BuildDebugContainerTrait.php @@ -64,7 +64,10 @@ protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilde $dumpedContainer = unserialize(file_get_contents(substr_replace($file, '.ser', -4))); $container->setDefinitions($dumpedContainer->getDefinitions()); $container->setAliases($dumpedContainer->getAliases()); - $container->__construct($dumpedContainer->getParameterBag()); + + $parameterBag = $container->getParameterBag(); + $parameterBag->clear(); + $parameterBag->add($dumpedContainer->getParameterBag()->all()); } else { (new XmlFileLoader($container, new FileLocator()))->load($file); $locatorPass = new ServiceLocatorTagPass(); From a595281bf87f47d9deff4f513f9788b34fbd19b8 Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Thu, 4 Dec 2025 20:13:09 +0100 Subject: [PATCH 13/17] Only register PhpConfigReferenceDumpPass in dev env with debug flag enabled --- FrameworkBundle.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FrameworkBundle.php b/FrameworkBundle.php index 3ad1dedc2..b892a825d 100644 --- a/FrameworkBundle.php +++ b/FrameworkBundle.php @@ -149,9 +149,6 @@ public function build(ContainerBuilder $container): void ]); } - if ($container->hasParameter('.kernel.config_dir') && $container->hasParameter('.kernel.bundles_definition')) { - $container->addCompilerPass(new PhpConfigReferenceDumpPass($container->getParameter('.kernel.config_dir').'/reference.php', $container->getParameter('.kernel.bundles_definition'))); - } $container->addCompilerPass(new AssetsContextPass()); $container->addCompilerPass(new LoggerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); $container->addCompilerPass(new RegisterControllerArgumentLocatorsPass()); @@ -208,6 +205,9 @@ public function build(ContainerBuilder $container): void $this->addCompilerPassIfExists($container, StreamablePass::class); if ($container->getParameter('kernel.debug')) { + if ($container->hasParameter('.kernel.config_dir') && $container->hasParameter('.kernel.bundles_definition')) { + $container->addCompilerPass(new PhpConfigReferenceDumpPass($container->getParameter('.kernel.config_dir').'/reference.php', $container->getParameter('.kernel.bundles_definition'))); + } $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2); $container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_BEFORE_REMOVING, -255); From 17d0833790bd2d953fb0727e5b5da85f1cc59c92 Mon Sep 17 00:00:00 2001 From: Lctrs Date: Thu, 4 Dec 2025 20:40:12 +0100 Subject: [PATCH 14/17] [HttpClient] CachingHttpClient must run after UriTemplate and Scoping --- DependencyInjection/FrameworkExtension.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DependencyInjection/FrameworkExtension.php b/DependencyInjection/FrameworkExtension.php index 2f9748cf9..718937376 100644 --- a/DependencyInjection/FrameworkExtension.php +++ b/DependencyInjection/FrameworkExtension.php @@ -2870,12 +2870,12 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder unset($scopeConfig['retry_failed']); // This "transport" service is decorated in the following order: - // 1. ThrottlingHttpClient (30) -> throttles requests - // 2. UriTemplateHttpClient (25) -> expands URI templates - // 3. ScopingHttpClient (20) -> resolves relative URLs and applies scope configuration - // 4. CachingHttpClient (15) -> caches responses - // 5. RetryableHttpClient (10) -> retries requests - // 6. TraceableHttpClient (5) -> traces requests + // 1. ThrottlingHttpClient (5) -> throttles requests + // 2. UriTemplateHttpClient (10) -> expands URI templates + // 3. ScopingHttpClient (15) -> resolves relative URLs and applies scope configuration + // 4. CachingHttpClient (20) -> caches responses + // 5. RetryableHttpClient (25) -> retries requests + // 6. TraceableHttpClient (100) -> traces requests $container->register($name, HttpClientInterface::class) ->setFactory('current') ->setArguments([[new Reference('http_client.transport')]]) @@ -2883,7 +2883,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder ; $scopingDefinition = $container->register($name.'.scoping', ScopingHttpClient::class) - ->setDecoratedService($name, null, 20) + ->setDecoratedService($name, null, 15) ->addTag('kernel.reset', ['method' => 'reset', 'on_invalid' => 'ignore']); if (null === $scope) { @@ -2912,7 +2912,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder $container ->register($name.'.uri_template', UriTemplateHttpClient::class) - ->setDecoratedService($name, null, 25) + ->setDecoratedService($name, null, 10) ->setArguments([ new Reference('.inner'), new Reference('http_client.uri_template_expander', ContainerInterface::NULL_ON_INVALID_REFERENCE), @@ -2951,7 +2951,7 @@ private function registerCachingHttpClient(array $options, array $defaultOptions $container ->register($name.'.caching', CachingHttpClient::class) - ->setDecoratedService($name, null, 15) + ->setDecoratedService($name, null, 20) ->setArguments([ new Reference('.inner'), new Reference($options['cache_pool']), @@ -2976,7 +2976,7 @@ private function registerThrottlingHttpClient(string $rateLimiter, string $name, $container ->register($name.'.throttling', ThrottlingHttpClient::class) - ->setDecoratedService($name, null, 30) + ->setDecoratedService($name, null, 5) ->setArguments([new Reference('.inner'), new Reference($name.'.throttling.limiter')]); } @@ -3008,7 +3008,7 @@ private function registerRetryableHttpClient(array $options, string $name, Conta $container ->register($name.'.retryable', RetryableHttpClient::class) - ->setDecoratedService($name, null, 10) + ->setDecoratedService($name, null, 25) ->setArguments([new Reference('.inner'), $retryStrategy, $options['max_retries'], new Reference('logger')]) ->addTag('monolog.logger', ['channel' => 'http_client']); } From 3f7531a6eb22738e9ff715f0a23c984d43b12508 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Fri, 5 Dec 2025 00:30:43 +0100 Subject: [PATCH 15/17] [FrameworkBundle] Fix using `FailedMessages*Command` with `SigningSerializer` --- Resources/config/console.php | 6 +++--- Resources/config/messenger.php | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Resources/config/console.php b/Resources/config/console.php index dd3f16a7a..2641586c2 100644 --- a/Resources/config/console.php +++ b/Resources/config/console.php @@ -201,7 +201,7 @@ service('messenger.routable_message_bus'), service('event_dispatcher'), service('logger')->nullOnInvalid(), - service('messenger.transport.native_php_serializer')->nullOnInvalid(), + service('.messenger.transport.native_php_serializer')->nullOnInvalid(), null, ]) ->tag('console.command') @@ -211,7 +211,7 @@ ->args([ abstract_arg('Default failure receiver name'), abstract_arg('Receivers'), - service('messenger.transport.native_php_serializer')->nullOnInvalid(), + service('.messenger.transport.native_php_serializer')->nullOnInvalid(), ]) ->tag('console.command') @@ -219,7 +219,7 @@ ->args([ abstract_arg('Default failure receiver name'), abstract_arg('Receivers'), - service('messenger.transport.native_php_serializer')->nullOnInvalid(), + service('.messenger.transport.native_php_serializer')->nullOnInvalid(), ]) ->tag('console.command') diff --git a/Resources/config/messenger.php b/Resources/config/messenger.php index be635a0f4..c4d4f8d19 100644 --- a/Resources/config/messenger.php +++ b/Resources/config/messenger.php @@ -78,7 +78,10 @@ ->set('serializer.normalizer.flatten_exception', FlattenExceptionNormalizer::class) ->tag('serializer.normalizer', ['built_in' => true, 'priority' => -880]) + ->set('.messenger.transport.native_php_serializer', PhpSerializer::class) ->set('messenger.transport.native_php_serializer', PhpSerializer::class) + ->factory('current') + ->args([[service('.messenger.transport.native_php_serializer')]]) ->alias('messenger.default_serializer', 'messenger.transport.native_php_serializer') ->alias(SerializerInterface::class, 'messenger.default_serializer') From 5d2e60f301dbafba1408e62b9838fdb58920c2ca Mon Sep 17 00:00:00 2001 From: Matijn Woudt Date: Thu, 13 Nov 2025 16:15:26 +0100 Subject: [PATCH 16/17] [TypeInfo] Simple array should be array type --- Tests/Functional/PropertyInfoTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Functional/PropertyInfoTest.php b/Tests/Functional/PropertyInfoTest.php index 18cd61b08..19ae0faaa 100644 --- a/Tests/Functional/PropertyInfoTest.php +++ b/Tests/Functional/PropertyInfoTest.php @@ -26,7 +26,7 @@ public function testPhpDocPriority() $this->markTestSkipped(); } - $this->assertEquals(Type::list(Type::int()), $propertyInfo->getType(Dummy::class, 'codes')); + $this->assertEquals(Type::array(Type::int()), $propertyInfo->getType(Dummy::class, 'codes')); } /** From 194b5edd7a00703aaf836b56bbf079cd6c4d4a87 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sat, 6 Dec 2025 17:28:30 +0100 Subject: [PATCH 17/17] [DependencyInjection] Fix broken test --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b70fcd291..efe01386e 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,7 @@ "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", "symfony/asset": "^7.4|^8.0", "symfony/asset-mapper": "^7.4|^8.0", @@ -70,7 +71,7 @@ "symfony/string": "^7.4|^8.0", "symfony/translation": "^7.4|^8.0", "symfony/twig-bundle": "^7.4|^8.0", - "symfony/type-info": "^7.4|^8.0", + "symfony/type-info": "^7.4.1|^8.0.1", "symfony/uid": "^7.4|^8.0", "symfony/validator": "^7.4|^8.0", "symfony/workflow": "^7.4|^8.0",