From 13ab18d14eab1931c21d556004179eb7ea41a6c9 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 3 Jan 2026 19:23:38 +0100 Subject: [PATCH] Wire the Console EntityValueResolver as a service --- config/orm.php | 8 +++ src/DependencyInjection/DoctrineExtension.php | 27 ++++++++- tests/ContainerTest.php | 5 ++ .../DoctrineExtensionTest.php | 57 +++++++++++++++++++ 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/config/orm.php b/config/orm.php index 819c10f72..4cecae598 100644 --- a/config/orm.php +++ b/config/orm.php @@ -48,6 +48,7 @@ use Doctrine\Persistence\Mapping\Driver\MappingDriverChain; use Doctrine\Persistence\Mapping\Driver\PHPDriver; use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver; +use Symfony\Bridge\Doctrine\ArgumentResolver\Console\EntityValueResolver as ConsoleEntityValueResolver; use Symfony\Bridge\Doctrine\ArgumentResolver\EntityValueResolver; use Symfony\Bridge\Doctrine\CacheWarmer\ProxyCacheWarmer; use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser; @@ -267,6 +268,13 @@ ]) ->tag('controller.argument_value_resolver', ['priority' => 110, 'name' => EntityValueResolver::class]) + ->set('doctrine.orm.entity_value_resolver.console', ConsoleEntityValueResolver::class) + ->args([ + service('doctrine'), + service('doctrine.orm.entity_value_resolver.expression_language')->ignoreOnInvalid(), + ]) + ->tag('console.argument_value_resolver', ['priority' => 110, 'name' => ConsoleEntityValueResolver::class]) + ->set('doctrine.orm.entity_value_resolver.expression_language', ExpressionLanguage::class) ->set('doctrine.cache_clear_metadata_command', MetadataCommand::class) diff --git a/src/DependencyInjection/DoctrineExtension.php b/src/DependencyInjection/DoctrineExtension.php index 591cb0035..cef1ef5b4 100644 --- a/src/DependencyInjection/DoctrineExtension.php +++ b/src/DependencyInjection/DoctrineExtension.php @@ -48,6 +48,7 @@ use InvalidArgumentException; use LogicException; use ReflectionClass; +use Symfony\Bridge\Doctrine\ArgumentResolver\Console\EntityValueResolver; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator; @@ -946,8 +947,8 @@ protected function ormLoad(array $config, ContainerBuilder $container) $controllerResolverDefaults['evict_cache'] = true; } - $valueResolverDefinition = $container->getDefinition('doctrine.orm.entity_value_resolver'); - $valueResolverDefinition->setArgument(2, (new Definition(MapEntity::class))->setArguments([ + $controllerValueResolverDefinition = $container->getDefinition('doctrine.orm.entity_value_resolver'); + $controllerValueResolverDefinition->setArgument(2, (new Definition(MapEntity::class))->setArguments([ null, null, null, @@ -960,7 +961,27 @@ protected function ormLoad(array $config, ContainerBuilder $container) ])); // Symfony 7.3 and higher expose type alias support in the EntityValueResolver - $valueResolverDefinition->setArgument(3, $config['resolve_target_entities']); + $controllerValueResolverDefinition->setArgument(3, $config['resolve_target_entities']); + + // The Console EntityValueResolver is available in Symfony 8.1 and higher + if (class_exists(EntityValueResolver::class)) { + $consoleValueResolverDefinition = $container->getDefinition('doctrine.orm.entity_value_resolver.console'); + $consoleValueResolverDefinition->setArgument(2, (new Definition(MapEntity::class))->setArguments([ + null, + null, + null, + $controllerResolverDefaults['mapping'] ?? null, + null, + null, + null, + $controllerResolverDefaults['evict_cache'] ?? null, + $controllerResolverDefaults['disabled'] ?? false, + ])); + + $consoleValueResolverDefinition->setArgument(3, $config['resolve_target_entities']); + } else { + $container->removeDefinition('doctrine.orm.entity_value_resolver.console'); + } // not available in Doctrine ORM 3.0 and higher if (! class_exists(ConvertMappingCommand::class)) { diff --git a/tests/ContainerTest.php b/tests/ContainerTest.php index a2e5fffbf..00028e938 100644 --- a/tests/ContainerTest.php +++ b/tests/ContainerTest.php @@ -18,6 +18,7 @@ use Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\Mapping\Driver\MappingDriverChain; +use Symfony\Bridge\Doctrine\ArgumentResolver\Console\EntityValueResolver as ConsoleEntityValueResolver; use Symfony\Bridge\Doctrine\ArgumentResolver\EntityValueResolver; use Symfony\Bridge\Doctrine\CacheWarmer\ProxyCacheWarmer; use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector; @@ -48,6 +49,10 @@ public function testContainer(): void $this->assertInstanceOf(EntityValueResolver::class, $container->get('doctrine.orm.entity_value_resolver')); } + if (class_exists(ConsoleEntityValueResolver::class)) { + $this->assertInstanceOf(ConsoleEntityValueResolver::class, $container->get('doctrine.orm.entity_value_resolver.console')); + } + $this->assertInstanceOf(DoctrineDataCollector::class, $container->get('data_collector.doctrine')); $this->assertInstanceOf(DBALConfiguration::class, $container->get('doctrine.dbal.default_connection.configuration')); $this->assertInstanceOf(EventManager::class, $container->get('doctrine.dbal.default_connection.event_manager')); diff --git a/tests/DependencyInjection/DoctrineExtensionTest.php b/tests/DependencyInjection/DoctrineExtensionTest.php index 4e70115ce..05dbef238 100644 --- a/tests/DependencyInjection/DoctrineExtensionTest.php +++ b/tests/DependencyInjection/DoctrineExtensionTest.php @@ -47,6 +47,7 @@ use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; use ReflectionClass; +use Symfony\Bridge\Doctrine\ArgumentResolver\Console\EntityValueResolver as ConsoleEntityValueResolver; use Symfony\Bridge\Doctrine\ArgumentResolver\EntityValueResolver; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Bridge\Doctrine\Middleware\IdleConnection\Driver; @@ -1507,6 +1508,62 @@ public function testControllerResolver(bool $simpleEntityManagerConfig): void $this->assertEquals(new MapEntity(null, null, null, [], null, null, null, true, true), $container->get('controller_resolver_defaults')); } + #[IgnoreDeprecations] + #[RequiresMethod(ConsoleEntityValueResolver::class, '__construct')] + #[TestWith([true])] + #[TestWith([false])] + public function testConsoleCommandResolver(bool $simpleEntityManagerConfig): void + { + if (! interface_exists(EntityManagerInterface::class)) { + self::markTestSkipped('This test requires ORM'); + } + + $container = $this->getContainer(); + $extension = new DoctrineExtension(); + $config = BundleConfigurationBuilder::createBuilderWithBaseValues()->build(); + + if ($simpleEntityManagerConfig) { + $config['orm'] = []; + } + + $config['orm']['controller_resolver'] = ['auto_mapping' => true]; + $config['orm']['resolve_target_entities'] = ['Throwable' => 'stdClass']; + + $extension->load([DeprecationFreeConfig::get(), $config], $container); + + $controllerResolver = $container->getDefinition('doctrine.orm.entity_value_resolver.console'); + + $this->assertEquals([ + 0 => new Reference('doctrine'), + 1 => new Reference('doctrine.orm.entity_value_resolver.expression_language', $container::IGNORE_ON_INVALID_REFERENCE), + 2 => (new Definition(MapEntity::class))->setArguments([ + null, + null, + null, + null, + null, + null, + null, + null, + false, + ]), + 3 => ['Throwable' => 'stdClass'], + ], $controllerResolver->getArguments()); + + $container = $this->getContainer(); + + $config['orm']['controller_resolver'] = [ + 'enabled' => false, + 'auto_mapping' => false, + 'evict_cache' => true, + ]; + $extension->load([$config], $container); + + $container->setDefinition('controller_resolver_defaults', $container->getDefinition('doctrine.orm.entity_value_resolver.console')->getArgument(2))->setPublic(true); + $container->compile(); + $this->assertEquals(new MapEntity(null, null, null, [], null, null, null, true, true), $container->get('controller_resolver_defaults')); + } + #[TestWith(['AnnotationsBundle', 'attribute', 'Vendor'], 'Bundle without anything')] #[TestWith(['AttributesBundle', 'attribute'], 'Bundle with attributes')] #[TestWith(['RepositoryServiceBundle', 'attribute'], 'Bundle with both')]