Skip to content

Commit

Permalink
Support setting PSR-6 caches with ORM 2.9+ (#1332)
Browse files Browse the repository at this point in the history
* Support setting PSR-6 caches with ORM 2.9+

* Set class names for cache definitions

* Fix checkstyle error

* Simplify cache wrapping

* Drop support for ORM < 2.9

* Fix unrelated phpcs errors

* Remove unnecessary configuration option

* Rename services for consistency
  • Loading branch information
alcaeus authored May 14, 2021
1 parent 1164630 commit abc1d3e
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 67 deletions.
73 changes: 45 additions & 28 deletions DependencyInjection/DoctrineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\Psr6\CacheAdapter;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
Expand All @@ -23,6 +26,7 @@
use Doctrine\ORM\Proxy\Autoloader;
use Doctrine\ORM\UnitOfWork;
use LogicException;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension;
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
Expand All @@ -34,9 +38,7 @@
use Symfony\Bridge\Doctrine\SchemaListener\RememberMeTokenProviderDoctrineSchemaSubscriber;
use Symfony\Bridge\Doctrine\Validator\DoctrineLoader;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
use Symfony\Component\Cache\DoctrineProvider;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ChildDefinition;
Expand All @@ -54,6 +56,7 @@
use function array_keys;
use function class_exists;
use function interface_exists;
use function is_a;
use function method_exists;
use function reset;
use function sprintf;
Expand Down Expand Up @@ -566,7 +569,7 @@ protected function loadOrmEntityManager(array $entityManager, ContainerBuilder $
}

$methods = [
'setMetadataCacheImpl' => new Reference(sprintf('doctrine.orm.%s_metadata_cache', $entityManager['name'])),
'setMetadataCache' => new Reference(sprintf('doctrine.orm.%s_metadata_cache', $entityManager['name'])),
'setQueryCacheImpl' => new Reference(sprintf('doctrine.orm.%s_query_cache', $entityManager['name'])),
'setResultCacheImpl' => new Reference(sprintf('doctrine.orm.%s_result_cache', $entityManager['name'])),
'setMetadataDriverImpl' => new Reference('doctrine.orm.' . $entityManager['name'] . '_metadata_driver'),
Expand Down Expand Up @@ -880,10 +883,10 @@ protected function getMappingResourceExtension(): string
/**
* {@inheritDoc}
*/
protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheDriver, ContainerBuilder $container): string
protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheDriver, ContainerBuilder $container, bool $usePsr6 = false): string
{
$serviceId = null;
$aliasId = $this->getObjectManagerElementName(sprintf('%s_%s', $objectManagerName, $cacheName));
$aliasId = $this->getObjectManagerElementName(sprintf('%s_%s', $objectManagerName, $cacheName));
$isPsr6 = null;

switch ($cacheDriver['type'] ?? 'pool') {
case 'service':
Expand All @@ -892,8 +895,9 @@ protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheD
break;

case 'pool':
$serviceId = $this->createPoolCacheDefinition($container, $cacheDriver['pool'] ?? $this->createArrayAdapterCachePool($container, $objectManagerName, $cacheName));

$pool = $cacheDriver['pool'] ?? $this->createArrayAdapterCachePool($container, $objectManagerName, $cacheName);
$serviceId = $pool;
$isPsr6 = true;
break;

default:
Expand All @@ -905,6 +909,32 @@ protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheD
));
}

if ($isPsr6 === null) {
$definition = $container->getDefinition($serviceId);
$isPsr6 = is_a($definition->getClass(), CacheItemPoolInterface::class, true);
}

$cacheName = str_replace('_cache', '', $cacheName);

// Create a wrapper as required
if ($isPsr6 && ! $usePsr6) {
$wrappedServiceId = sprintf('doctrine.orm.cache.provider.%s.%s', $objectManagerName, $cacheName);

$definition = $container->register($wrappedServiceId, CacheProvider::class);
$definition->setFactory([DoctrineProvider::class, 'wrap']);
$definition->addArgument(new Reference($serviceId));

$serviceId = $wrappedServiceId;
} elseif (! $isPsr6 && $usePsr6) {
$wrappedServiceId = sprintf('cache.doctrine.orm.adapter.%s.%s', $objectManagerName, $cacheName);

$definition = $container->register($wrappedServiceId, CacheItemPoolInterface::class);
$definition->setFactory([CacheAdapter::class, 'wrap']);
$definition->addArgument(new Reference($serviceId));

$serviceId = $wrappedServiceId;
}

$container->setAlias($aliasId, new Alias($serviceId, false));

return $aliasId;
Expand All @@ -917,9 +947,9 @@ protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheD
*/
protected function loadOrmCacheDrivers(array $entityManager, ContainerBuilder $container)
{
$this->loadCacheDriver('metadata_cache', $entityManager['name'], $entityManager['metadata_cache_driver'], $container);
$this->loadCacheDriver('result_cache', $entityManager['name'], $entityManager['result_cache_driver'], $container);
$this->loadCacheDriver('query_cache', $entityManager['name'], $entityManager['query_cache_driver'], $container);
$this->loadCacheDriver('metadata_cache', $entityManager['name'], $entityManager['metadata_cache_driver'], $container, true);
$this->loadCacheDriver('result_cache', $entityManager['name'], $entityManager['result_cache_driver'], $container, false);
$this->loadCacheDriver('query_cache', $entityManager['name'], $entityManager['query_cache_driver'], $container, false);

if ($container->getParameter('kernel.debug')) {
return;
Expand Down Expand Up @@ -1022,16 +1052,6 @@ private function loadMessengerServices(ContainerBuilder $container): void
$transportFactoryDefinition->addTag('messenger.transport_factory');
}

private function createPoolCacheDefinition(ContainerBuilder $container, string $poolName): string
{
$serviceId = sprintf('doctrine.orm.cache.provider.%s', $poolName);

$definition = $container->register($serviceId, DoctrineProvider::class);
$definition->addArgument(new Reference($poolName));

return $serviceId;
}

private function createArrayAdapterCachePool(ContainerBuilder $container, string $objectManagerName, string $cacheName): string
{
$id = sprintf('cache.doctrine.orm.%s.%s', $objectManagerName, str_replace('_cache', '', $cacheName));
Expand All @@ -1056,12 +1076,9 @@ private function registerMetadataPhpArrayCaching(string $entityManagerName, Cont
->addTag('kernel.cache_warmer', ['priority' => 1000]); // priority should be higher than ProxyCacheWarmer

$container->setAlias($metadataCacheAlias, $phpArrayCacheDecoratorServiceId);
$container->register($phpArrayCacheDecoratorServiceId, DoctrineProvider::class)
->addArgument(
new Definition(PhpArrayAdapter::class, [
$phpArrayFile,
new Definition(DoctrineAdapter::class, [new Reference($decoratedMetadataCacheServiceId)]),
])
);

$container->register($phpArrayCacheDecoratorServiceId, PhpArrayAdapter::class)
->addArgument($phpArrayFile)
->addArgument(new Reference($decoratedMetadataCacheServiceId));
}
}
5 changes: 3 additions & 2 deletions Tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand;
use Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection\Fixtures\DbalTestKernel;
use Doctrine\Common\Annotations\Reader;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration as DBALConfiguration;
use Doctrine\DBAL\Connection;
Expand All @@ -23,7 +24,7 @@
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;
use Symfony\Bridge\Doctrine\Validator\DoctrineLoader;
use Symfony\Component\Cache\DoctrineProvider;
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;

use function class_exists;
use function interface_exists;
Expand Down Expand Up @@ -63,7 +64,7 @@ public function testContainer(): void
$this->assertInstanceOf(Reader::class, $container->get('doctrine.orm.metadata.annotation_reader'));
$this->assertInstanceOf(Configuration::class, $container->get('doctrine.orm.default_configuration'));
$this->assertInstanceOf(MappingDriverChain::class, $container->get('doctrine.orm.default_metadata_driver'));
$this->assertInstanceOf(DoctrineProvider::class, $container->get('doctrine.orm.default_metadata_cache'));
$this->assertInstanceOf(PhpArrayAdapter::class, $container->get('doctrine.orm.default_metadata_cache'));
$this->assertInstanceOf(DoctrineProvider::class, $container->get('doctrine.orm.default_query_cache'));
$this->assertInstanceOf(DoctrineProvider::class, $container->get('doctrine.orm.default_result_cache'));
$this->assertInstanceOf(EntityManager::class, $container->get('doctrine.orm.default_entity_manager'));
Expand Down
22 changes: 12 additions & 10 deletions Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\EntityListenerPass;
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\WellKnownSchemaFilterPass;
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
Expand All @@ -17,7 +18,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\DoctrineProvider;
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down Expand Up @@ -429,16 +430,16 @@ public function testLoadMultipleConnections(): void
$this->assertEquals('doctrine.orm.em2_configuration', (string) $arguments[1]);

$definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.em1_metadata_cache'));
$this->assertEquals(DoctrineProvider::class, $definition->getClass());
$this->assertEquals(PhpArrayAdapter::class, $definition->getClass());

$definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.em1_query_cache'));
$this->assertEquals(DoctrineProvider::class, $definition->getClass());
$this->assertEquals([DoctrineProvider::class, 'wrap'], $definition->getFactory());
$arguments = $definition->getArguments();
$this->assertInstanceOf(Reference::class, $arguments[0]);
$this->assertEquals('cache.doctrine.orm.em1.query', (string) $arguments[0]);

$definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.em1_result_cache'));
$this->assertEquals(DoctrineProvider::class, $definition->getClass());
$this->assertEquals([DoctrineProvider::class, 'wrap'], $definition->getFactory());
$arguments = $definition->getArguments();
$this->assertInstanceOf(Reference::class, $arguments[0]);
$this->assertEquals('cache.doctrine.orm.em1.result', (string) $arguments[0]);
Expand Down Expand Up @@ -473,10 +474,10 @@ public function testEntityManagerMetadataCacheDriverConfiguration(): void
$container = $this->loadContainer('orm_service_multiple_entity_managers');

$definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.em1_metadata_cache'));
$this->assertDICDefinitionClass($definition, DoctrineProvider::class);
$this->assertDICDefinitionClass($definition, PhpArrayAdapter::class);

$definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.em2_metadata_cache'));
$this->assertDICDefinitionClass($definition, DoctrineProvider::class);
$this->assertDICDefinitionClass($definition, PhpArrayAdapter::class);
}

public function testDependencyInjectionImportsOverrideDefaults(): void
Expand All @@ -487,11 +488,12 @@ public function testDependencyInjectionImportsOverrideDefaults(): void

$container = $this->loadContainer('orm_imports');

$cacheDefinition = $container->getDefinition((string) $container->getAlias('doctrine.orm.default_metadata_cache'));
$this->assertEquals(DoctrineProvider::class, $cacheDefinition->getClass());

$configDefinition = $container->getDefinition('doctrine.orm.default_configuration');
$this->assertDICDefinitionMethodCallOnce($configDefinition, 'setAutoGenerateProxyClasses', ['%doctrine.orm.auto_generate_proxy_classes%']);

$cacheDefinition = $container->getDefinition((string) $container->getAlias('doctrine.orm.default_metadata_cache'));
$this->assertEquals(PhpArrayAdapter::class, $cacheDefinition->getClass());
$this->assertDICDefinitionMethodCallOnce($configDefinition, 'setMetadataCache', [new Reference('doctrine.orm.default_metadata_cache')]);
}

public function testSingleEntityManagerMultipleMappingBundleDefinitions(): void
Expand Down Expand Up @@ -717,7 +719,7 @@ public function testSecondLevelCache(): void
$this->assertDICDefinitionClass($myEntityRegionDef, '%doctrine.orm.second_level_cache.default_region.class%');
$this->assertDICDefinitionClass($loggerChainDef, '%doctrine.orm.second_level_cache.logger_chain.class%');
$this->assertDICDefinitionClass($loggerStatisticsDef, '%doctrine.orm.second_level_cache.logger_statistics.class%');
$this->assertDICDefinitionClass($cacheDriverDef, DoctrineProvider::class);
$this->assertEquals([DoctrineProvider::class, 'wrap'], $cacheDriverDef->getFactory());
$this->assertDICDefinitionMethodCallOnce($configDef, 'setSecondLevelCacheConfiguration');
$this->assertDICDefinitionMethodCallCount($slcFactoryDef, 'setRegion', [], 3);
$this->assertDICDefinitionMethodCallCount($loggerChainDef, 'setLogger', [], 3);
Expand Down
Loading

0 comments on commit abc1d3e

Please sign in to comment.