diff --git a/.symfony.bundle.yaml b/.symfony.bundle.yaml new file mode 100644 index 000000000..88f603e55 --- /dev/null +++ b/.symfony.bundle.yaml @@ -0,0 +1,9 @@ +branches: + - "1.12.x" + - "2.4.x" + - "2.5.x" +maintained_branches: + - "2.4.x" + - "2.5.x" +doc_dir: "Resources/doc/" +dev_branch: "2.5.x" diff --git a/Command/CreateDatabaseDoctrineCommand.php b/Command/CreateDatabaseDoctrineCommand.php index b43864c97..edcab6b6a 100644 --- a/Command/CreateDatabaseDoctrineCommand.php +++ b/Command/CreateDatabaseDoctrineCommand.php @@ -44,10 +44,7 @@ protected function configure() ); } - /** - * {@inheritDoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $connectionName = $input->getOption('connection'); if (empty($connectionName)) { diff --git a/Command/DropDatabaseDoctrineCommand.php b/Command/DropDatabaseDoctrineCommand.php index 31b23d63d..75dfcba7e 100644 --- a/Command/DropDatabaseDoctrineCommand.php +++ b/Command/DropDatabaseDoctrineCommand.php @@ -52,10 +52,7 @@ protected function configure() ); } - /** - * {@inheritDoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $connectionName = $input->getOption('connection'); if (empty($connectionName)) { diff --git a/Command/ImportMappingDoctrineCommand.php b/Command/ImportMappingDoctrineCommand.php index fcf8c8e09..c63a92733 100644 --- a/Command/ImportMappingDoctrineCommand.php +++ b/Command/ImportMappingDoctrineCommand.php @@ -87,10 +87,7 @@ protected function configure() ); } - /** - * {@inheritDoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $type = $input->getArgument('mapping-type') ?: 'xml'; if ($type === 'yaml') { diff --git a/Command/Proxy/DoctrineCommandHelper.php b/Command/Proxy/DoctrineCommandHelper.php index d395a280c..c1e205cbc 100644 --- a/Command/Proxy/DoctrineCommandHelper.php +++ b/Command/Proxy/DoctrineCommandHelper.php @@ -8,6 +8,7 @@ use Symfony\Bundle\FrameworkBundle\Console\Application; use function assert; +use function class_exists; /** * Provides some helper and convenience methods to configure doctrine commands in the context of bundles @@ -25,7 +26,10 @@ public static function setApplicationEntityManager(Application $application, $em $em = $application->getKernel()->getContainer()->get('doctrine')->getManager($emName); assert($em instanceof EntityManagerInterface); $helperSet = $application->getHelperSet(); - $helperSet->set(new ConnectionHelper($em->getConnection()), 'db'); + if (class_exists(ConnectionHelper::class)) { + $helperSet->set(new ConnectionHelper($em->getConnection()), 'db'); + } + $helperSet->set(new EntityManagerHelper($em), 'em'); } diff --git a/Command/Proxy/ImportDoctrineCommand.php b/Command/Proxy/ImportDoctrineCommand.php index 099c20eb2..bcdb5816a 100644 --- a/Command/Proxy/ImportDoctrineCommand.php +++ b/Command/Proxy/ImportDoctrineCommand.php @@ -28,10 +28,7 @@ protected function configure() ->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'The connection to use for this command'); } - /** - * {@inheritDoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { trigger_deprecation( 'doctrine/doctrine-bundle', diff --git a/Command/Proxy/RunSqlDoctrineCommand.php b/Command/Proxy/RunSqlDoctrineCommand.php index 74566b601..a01f8d107 100644 --- a/Command/Proxy/RunSqlDoctrineCommand.php +++ b/Command/Proxy/RunSqlDoctrineCommand.php @@ -51,10 +51,7 @@ protected function configure() $this->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'The connection to use for this command'); } - /** - * {@inheritDoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { trigger_deprecation( 'doctrine/doctrine-bundle', diff --git a/DependencyInjection/Compiler/CacheCompatibilityPass.php b/DependencyInjection/Compiler/CacheCompatibilityPass.php index 83b62d8fc..e5a88e904 100644 --- a/DependencyInjection/Compiler/CacheCompatibilityPass.php +++ b/DependencyInjection/Compiler/CacheCompatibilityPass.php @@ -60,6 +60,19 @@ private function updateSecondLevelCache(ContainerBuilder $container, Definition assert($factoryDefinition instanceof Definition); $aliasId = (string) $factoryDefinition->getArgument(1); $this->wrapIfNecessary($container, $aliasId, (string) $container->getAlias($aliasId), false); + foreach ($factoryDefinition->getMethodCalls() as $factoryMethodCall) { + if ($factoryMethodCall[0] !== 'setRegion') { + continue; + } + + $driverId = (string) $container->getDefinition($factoryMethodCall[1][0])->getArgument(1); + if (! $container->hasAlias($driverId)) { + continue; + } + + $this->wrapIfNecessary($container, $driverId, (string) $container->getAlias($driverId), false); + } + break; } } diff --git a/DependencyInjection/DoctrineExtension.php b/DependencyInjection/DoctrineExtension.php index d6a83fc38..555387363 100644 --- a/DependencyInjection/DoctrineExtension.php +++ b/DependencyInjection/DoctrineExtension.php @@ -47,6 +47,7 @@ use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransportFactory; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; +use Symfony\Component\Validator\Mapping\Loader\LoaderInterface; use function array_intersect_key; use function array_keys; @@ -498,6 +499,10 @@ protected function ormLoad(array $config, ContainerBuilder $container) $this->loadPropertyInfoExtractor($name, $container); } + if (! interface_exists(LoaderInterface::class)) { + continue; + } + $this->loadValidatorLoader($name, $container); } diff --git a/Resources/doc/entity-listeners.rst b/Resources/doc/entity-listeners.rst index edb352e5c..4b79aeb54 100644 --- a/Resources/doc/entity-listeners.rst +++ b/Resources/doc/entity-listeners.rst @@ -9,22 +9,39 @@ which entity manager it should be registered with. Full example: -.. code-block:: php +.. configuration-block:: + + .. code-block:: annotation + + + diff --git a/Tests/ConnectionFactoryTest.php b/Tests/ConnectionFactoryTest.php index b9fdfa77c..979ca32dd 100644 --- a/Tests/ConnectionFactoryTest.php +++ b/Tests/ConnectionFactoryTest.php @@ -8,9 +8,11 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\API\ExceptionConverter; +use Doctrine\DBAL\Driver\Exception as InternalDriverException; use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\MySqlPlatform; +use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Exception; use Throwable; @@ -19,6 +21,9 @@ use function class_exists; use function strpos; +// Compatibility with DBAL < 3 +class_exists(\Doctrine\DBAL\Platforms\MySqlPlatform::class); + class ConnectionFactoryTest extends TestCase { public function testContainer(): void @@ -29,9 +34,10 @@ public function testContainer(): void $config = null; $eventManager = null; $mappingTypes = ['' => '']; - $exception = class_exists(Driver\AbstractDriverException::class) ? + /** @psalm-suppress InvalidArgument */ + $exception = class_exists(Driver\AbstractDriverException::class) ? new DriverException('', $this->createMock(Driver\AbstractDriverException::class)) : - new DriverException('', $this->createMock(Driver\AbstractException::class)); + new DriverException($this->createMock(InternalDriverException::class), null); // put the mock into the fake driver FakeDriver::$exception = $exception; @@ -139,6 +145,10 @@ class FakeDriver implements Driver * So we have to fake the exception a driver would normally throw. * * @link https://github.com/doctrine/DoctrineBundle/issues/673 + * + * @psalm-suppress InvalidReturnStatement + * @psalm-suppress InvalidReturnType + * @psalm-suppress UndefinedClass */ public function getDatabasePlatform(): AbstractPlatform { @@ -146,7 +156,7 @@ public function getDatabasePlatform(): AbstractPlatform throw self::$exception; } - return static::$platform ?? new MySqlPlatform(); + return static::$platform ?? new MySQLPlatform(); } // ----- below this line follow only dummy methods to satisfy the interface requirements ---- @@ -169,6 +179,22 @@ public function getSchemaManager(Connection $conn, ?AbstractPlatform $platform = throw new Exception('not implemented'); } + /** + * @psalm-suppress InvalidReturnStatement + * @psalm-suppress InvalidReturnType + * @psalm-suppress MissingDependency + * @psalm-suppress UndefinedClass + */ + public function getExceptionConverter(): ExceptionConverter + { + return new class implements ExceptionConverter { + public function convert(InternalDriverException $exception, ?Query $query): DriverException + { + return new DriverException($exception, $query); + } + }; + } + public function getName(): string { return 'FakeDriver'; diff --git a/Tests/DependencyInjection/Compiler/CacheCompatibilityPassTest.php b/Tests/DependencyInjection/Compiler/CacheCompatibilityPassTest.php index 1d0c4ae11..f0aa01101 100644 --- a/Tests/DependencyInjection/Compiler/CacheCompatibilityPassTest.php +++ b/Tests/DependencyInjection/Compiler/CacheCompatibilityPassTest.php @@ -17,7 +17,6 @@ class CacheCompatibilityPassTest extends TestCase public function testCacheConfigUsingServiceDefinedByApplication(): void { - $this->expectNotToPerformAssertions(); (new class () extends TestKernel { public function registerContainerConfiguration(LoaderInterface $loader): void { @@ -36,6 +35,12 @@ public function registerContainerConfiguration(LoaderInterface $loader): void 'orm' => [ 'query_cache_driver' => ['type' => 'service', 'id' => 'custom_cache_service'], 'result_cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.system_cache_pool'], + 'second_level_cache' => [ + 'enabled' => true, + 'regions' => [ + 'lifelong' => ['lifetime' => 0, 'cache_driver' => ['type' => 'pool', 'pool' => 'doctrine.system_cache_pool']], + ], + ], ], ] ); @@ -48,6 +53,8 @@ public function registerContainerConfiguration(LoaderInterface $loader): void }); } })->boot(); + + $this->addToAssertionCount(1); } /** @group legacy */ diff --git a/Tests/ProfilerTest.php b/Tests/ProfilerTest.php index 67410584a..53eff5e4e 100644 --- a/Tests/ProfilerTest.php +++ b/Tests/ProfilerTest.php @@ -41,7 +41,9 @@ public function setUp(): void { $this->logger = new DebugStack(); $registry = $this->getMockBuilder(ManagerRegistry::class)->getMock(); - $registry->expects($this->once())->method('getManagers')->willReturn([]); + $registry->method('getConnectionNames')->willReturn([]); + $registry->method('getManagerNames')->willReturn([]); + $registry->method('getManagers')->willReturn([]); $this->collector = new DoctrineDataCollector($registry); $this->collector->addLogger('foo', $this->logger); @@ -62,7 +64,10 @@ public function setUp(): void $this->twig->addExtension(new CodeExtension('', '', '')); $this->twig->addExtension(new RoutingExtension($urlGenerator)); $this->twig->addExtension(new HttpKernelExtension()); - /** @psalm-suppress InternalClass */ + /** + * @psalm-suppress InternalClass + * @psalm-suppress InternalMethod + */ $this->twig->addExtension(new WebProfilerExtension()); $this->twig->addExtension(new DoctrineExtension()); diff --git a/Tests/RegistryTest.php b/Tests/RegistryTest.php index 8b5e8935c..fd0ed061e 100644 --- a/Tests/RegistryTest.php +++ b/Tests/RegistryTest.php @@ -155,8 +155,8 @@ public function testReset(): void $container->expects($this->any()) ->method('get') - ->withConsecutive(['doctrine.orm.noproxy_entity_manager'], ['doctrine.orm.proxy_entity_manager'], ['doctrine.orm.proxy_entity_manager']) - ->willReturnOnConsecutiveCalls($noProxyManager, $proxyManager, $proxyManager); + ->withConsecutive(['doctrine.orm.noproxy_entity_manager'], ['doctrine.orm.proxy_entity_manager'], ['doctrine.orm.proxy_entity_manager'], ['doctrine.orm.proxy_entity_manager']) + ->willReturnOnConsecutiveCalls($noProxyManager, $proxyManager, $proxyManager, $proxyManager); $entityManagers = [ 'uninitialized' => 'doctrine.orm.uninitialized_entity_manager', diff --git a/Tests/TestCase.php b/Tests/TestCase.php index 0ad1241f5..2154adde5 100644 --- a/Tests/TestCase.php +++ b/Tests/TestCase.php @@ -6,18 +6,28 @@ use Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension; use Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection\TestType; use Doctrine\Common\Annotations\AnnotationReader; +use Doctrine\DBAL\Platforms\MySQLPlatform; use PHPUnit\Framework\TestCase as BaseTestCase; +use ReflectionClass; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use function class_exists; use function sys_get_temp_dir; use function uniqid; +// Compatibility with DBAL < 3 +class_exists(\Doctrine\DBAL\Platforms\MySqlPlatform::class); + class TestCase extends BaseTestCase { + /** + * @psalm-suppress InvalidClass + * @psalm-suppress UndefinedClass + */ public function createXmlBundleTestContainer(): ContainerBuilder { $container = new ContainerBuilder(new ParameterBag([ @@ -69,7 +79,9 @@ public function createXmlBundleTestContainer(): ContainerBuilder ], ], $container); - $container->setDefinition('my.platform', new Definition('Doctrine\DBAL\Platforms\MySqlPlatform'))->setPublic(true); + // Fix casing: The class is named MySqlPlatform on DBAL 2. + $platformClassName = (new ReflectionClass(MySQLPlatform::class))->getName(); + $container->setDefinition('my.platform', new Definition($platformClassName))->setPublic(true); // Register dummy cache services so we don't have to load the FrameworkExtension $container->setDefinition('cache.system', (new Definition(ArrayAdapter::class))->setPublic(true)); diff --git a/composer.json b/composer.json index 6bbb0410f..57fcd900f 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ ], "require": { "php": "^7.1 || ^8.0", + "doctrine/annotations": "^1", "doctrine/cache": "^1.11 || ^2.0", "doctrine/dbal": "^2.9.0|^3.0", "doctrine/persistence": "^1.3.3|^2.0",