Skip to content

Commit

Permalink
Test and fix cache compatibility layer (#1365)
Browse files Browse the repository at this point in the history
Co-authored-by: Gabriel Ostrolucký <[email protected]>
  • Loading branch information
alcaeus and ostrolucky authored Jun 5, 2021
1 parent 4decb93 commit 4202ce6
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 27 deletions.
88 changes: 63 additions & 25 deletions DependencyInjection/Compiler/CacheCompatibilityPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

use function array_keys;
use function assert;
use function is_a;
use function trigger_deprecation;

Expand All @@ -29,44 +31,80 @@ public function process(ContainerBuilder $container): void
{
foreach (array_keys($container->findTaggedServiceIds(self::CONFIGURATION_TAG)) as $id) {
foreach ($container->getDefinition($id)->getMethodCalls() as $methodCall) {
if ($methodCall[0] === 'setSecondLevelCacheConfiguration') {
$this->updateSecondLevelCache($container, $methodCall[1][0]);
continue;
}

if (! isset(self::CACHE_METHODS_PSR6_SUPPORT_MAP[$methodCall[0]])) {
continue;
}

$aliasId = (string) $methodCall[1][0];
$definitionId = (string) $container->getAlias($aliasId);
$definition = $container->getDefinition($definitionId);
$shouldBePsr6 = self::CACHE_METHODS_PSR6_SUPPORT_MAP[$methodCall[0]];

while (! $definition->getClass() && $definition instanceof ChildDefinition) {
$definition = $container->findDefinition($definition->getParent());
}
$this->wrapIfNecessary($container, $aliasId, $definitionId, $shouldBePsr6);
}
}
}

if ($shouldBePsr6 === is_a($definition->getClass(), CacheItemPoolInterface::class, true)) {
continue;
}
private function updateSecondLevelCache(ContainerBuilder $container, Definition $slcConfigDefinition): void
{
foreach ($slcConfigDefinition->getMethodCalls() as $methodCall) {
if ($methodCall[0] !== 'setCacheFactory') {
continue;
}

$targetClass = CacheProvider::class;
$targetFactory = DoctrineProvider::class;
$factoryDefinition = $methodCall[1][0];
assert($factoryDefinition instanceof Definition);
$aliasId = (string) $factoryDefinition->getArgument(1);
$this->wrapIfNecessary($container, $aliasId, (string) $container->getAlias($aliasId), false);
break;
}
}

if ($shouldBePsr6) {
$targetClass = CacheItemPoolInterface::class;
$targetFactory = CacheAdapter::class;
private function createCompatibilityLayerDefinition(ContainerBuilder $container, string $definitionId, bool $shouldBePsr6): ?Definition
{
$definition = $container->getDefinition($definitionId);

trigger_deprecation(
'doctrine/doctrine-bundle',
'2.4',
'Configuring doctrine/cache is deprecated. Please update the cache service "%s" to use a PSR-6 cache.',
$definitionId
);
}
while (! $definition->getClass() && $definition instanceof ChildDefinition) {
$definition = $container->findDefinition($definition->getParent());
}

$compatibilityLayerId = $definitionId . '.compatibility_layer';
$container->setAlias($aliasId, $compatibilityLayerId);
$container->register($compatibilityLayerId, $targetClass)
->setFactory([$targetFactory, 'wrap'])
->addArgument(new Reference($definitionId));
}
if ($shouldBePsr6 === is_a($definition->getClass(), CacheItemPoolInterface::class, true)) {
return null;
}

$targetClass = CacheProvider::class;
$targetFactory = DoctrineProvider::class;

if ($shouldBePsr6) {
$targetClass = CacheItemPoolInterface::class;
$targetFactory = CacheAdapter::class;

trigger_deprecation(
'doctrine/doctrine-bundle',
'2.4',
'Configuring doctrine/cache is deprecated. Please update the cache service "%s" to use a PSR-6 cache.',
$definitionId
);
}

return (new Definition($targetClass))
->setFactory([$targetFactory, 'wrap'])
->addArgument(new Reference($definitionId));
}

private function wrapIfNecessary(ContainerBuilder $container, string $aliasId, string $definitionId, bool $shouldBePsr6): void
{
$compatibilityLayer = $this->createCompatibilityLayerDefinition($container, $definitionId, $shouldBePsr6);
if ($compatibilityLayer === null) {
return;
}

$compatibilityLayerId = $definitionId . '.compatibility_layer';
$container->setAlias($aliasId, $compatibilityLayerId);
$container->setDefinition($compatibilityLayerId, $compatibilityLayer);
}
}
118 changes: 116 additions & 2 deletions Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Generator;
use InvalidArgumentException;
Expand Down Expand Up @@ -681,6 +682,120 @@ public function testSetQuoteStrategy(): void
$this->assertDICDefinitionMethodCallOnce($def2, 'setQuoteStrategy', [0 => new Reference('doctrine.orm.quote_strategy.ansi')]);
}

/**
* @dataProvider cacheConfigProvider
* @group legacy
*/
public function testCacheConfig(?string $expectedClass, string $entityManagerName, ?string $cacheGetter): void
{
if (! interface_exists(EntityManagerInterface::class)) {
self::markTestSkipped('This test requires ORM');
}

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

$entityManagerId = sprintf('doctrine.orm.%s_entity_manager', $entityManagerName);

$em = $container->get($entityManagerId);
assert($em instanceof EntityManager);

$this->assertInstanceOf(EntityManagerInterface::class, $em);

if ($cacheGetter === null) {
return;
}

$configuration = $em->getConfiguration();
$cache = $configuration->$cacheGetter();

if ($expectedClass === null) {
$this->assertNull($cache);
} else {
$this->assertInstanceOf($expectedClass, $cache);
}
}

public static function cacheConfigProvider(): Generator
{
yield 'metadata_cache_none' => [
'expectedClass' => PhpArrayAdapter::class,
'entityManagerName' => 'metadata_cache_none',
'cacheGetter' => 'getMetadataCache',
];

yield 'metadata_cache_pool' => [
'expectedClass' => ArrayAdapter::class,
'entityManagerName' => 'metadata_cache_pool',
'cacheGetter' => 'getMetadataCache',
];

yield 'metadata_cache_service_psr6' => [
'expectedClass' => ArrayAdapter::class,
'entityManagerName' => 'metadata_cache_service_psr6',
'cacheGetter' => 'getMetadataCache',
];

yield 'metadata_cache_service_doctrine' => [
'expectedClass' => ArrayAdapter::class,
'entityManagerName' => 'metadata_cache_service_doctrine',
'cacheGetter' => 'getMetadataCache',
];

yield 'query_cache_pool' => [
'expectedClass' => DoctrineProvider::class,
'entityManagerName' => 'query_cache_pool',
'cacheGetter' => 'getQueryCacheImpl',
];

yield 'query_cache_service_psr6' => [
'expectedClass' => DoctrineProvider::class,
'entityManagerName' => 'query_cache_service_psr6',
'cacheGetter' => 'getQueryCacheImpl',
];

yield 'query_cache_service_doctrine' => [
'expectedClass' => DoctrineProvider::class,
'entityManagerName' => 'query_cache_service_doctrine',
'cacheGetter' => 'getQueryCacheImpl',
];

yield 'result_cache_pool' => [
'expectedClass' => DoctrineProvider::class,
'entityManagerName' => 'result_cache_pool',
'cacheGetter' => 'getResultCacheImpl',
];

yield 'result_cache_service_psr6' => [
'expectedClass' => DoctrineProvider::class,
'entityManagerName' => 'result_cache_service_psr6',
'cacheGetter' => 'getResultCacheImpl',
];

yield 'result_cache_service_doctrine' => [
'expectedClass' => DoctrineProvider::class,
'entityManagerName' => 'result_cache_service_doctrine',
'cacheGetter' => 'getResultCacheImpl',
];

yield 'second_level_cache_pool' => [
'expectedClass' => null,
'entityManagerName' => 'second_level_cache_pool',
'cacheGetter' => null,
];

yield 'second_level_cache_service_psr6' => [
'expectedClass' => null,
'entityManagerName' => 'second_level_cache_service_psr6',
'cacheGetter' => null,
];

yield 'second_level_cache_service_doctrine' => [
'expectedClass' => null,
'entityManagerName' => 'second_level_cache_service_doctrine',
'cacheGetter' => null,
];
}

public function testSecondLevelCache(): void
{
if (! interface_exists(EntityManagerInterface::class)) {
Expand Down Expand Up @@ -723,7 +838,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, ArrayAdapter::class);
$this->assertDICDefinitionClass($cacheDriverDef, CacheProvider::class);
$this->assertDICDefinitionMethodCallOnce($configDef, 'setSecondLevelCacheConfiguration');
$this->assertDICDefinitionMethodCallCount($slcFactoryDef, 'setRegion', [], 3);
$this->assertDICDefinitionMethodCallCount($loggerChainDef, 'setLogger', [], 3);
Expand Down Expand Up @@ -1269,7 +1384,6 @@ private function loadContainer(
): ContainerBuilder {
$container = $this->getContainer($bundles);
$container->registerExtension(new DoctrineExtension());
$container->addCompilerPass(new CacheCompatibilityPass());

$this->loadFromFile($container, $fixture);

Expand Down
5 changes: 5 additions & 0 deletions Tests/DependencyInjection/DoctrineExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,9 @@ public function testShardManager(): void
$this->assertEquals($managerClass, $bazManagerDef->getClass());
}

// Disabled to prevent changing the comment below to a single-line annotation
// phpcs:disable SlevomatCodingStandard.Commenting.RequireOneLineDocComment.MultiLineDocComment

/**
* @requires PHP 8
*/
Expand Down Expand Up @@ -1118,6 +1121,8 @@ public function testAsEntityListenerAttribute()
$this->assertSame([$expected], $definition->getTag('doctrine.orm.entity_listener'));
}

// phpcs:enable

/** @param list<string> $bundles */
private function getContainer(array $bundles = ['YamlBundle'], string $vendor = ''): ContainerBuilder
{
Expand Down
71 changes: 71 additions & 0 deletions Tests/DependencyInjection/Fixtures/config/xml/orm_caches.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" ?>

<srv:container xmlns="http://symfony.com/schema/dic/doctrine"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">

<srv:services>
<srv:service id="cache.psr6" class="Symfony\Component\Cache\Adapter\ArrayAdapter"/>
<srv:service id="cache.doctrine" class="Doctrine\Common\Cache\Psr6\DoctrineProvider">
<srv:factory class="Doctrine\Common\Cache\Psr6\DoctrineProvider" method="wrap"/>
<srv:argument type="service" id="cache.psr6"/>
</srv:service>
</srv:services>

<config>
<dbal default-connection="default">
<connection name="default" dbname="db" />
</dbal>

<orm default-entity-manager="metadata_cache_none">
<entity-manager name="metadata_cache_none"/>
<entity-manager name="metadata_cache_pool">
<metadata-cache-driver type="pool" pool="cache.psr6"/>
</entity-manager>
<entity-manager name="metadata_cache_service_psr6">
<metadata-cache-driver type="service" id="cache.psr6"/>
</entity-manager>
<entity-manager name="metadata_cache_service_doctrine">
<metadata-cache-driver type="service" id="cache.doctrine"/>
</entity-manager>

<entity-manager name="query_cache_pool">
<query-cache-driver type="pool" pool="cache.psr6"/>
</entity-manager>
<entity-manager name="query_cache_service_psr6">
<query-cache-driver type="service" id="cache.psr6"/>
</entity-manager>
<entity-manager name="query_cache_service_doctrine">
<query-cache-driver type="service" id="cache.doctrine"/>
</entity-manager>

<entity-manager name="result_cache_pool">
<result-cache-driver type="pool" pool="cache.psr6"/>
</entity-manager>
<entity-manager name="result_cache_service_psr6">
<result-cache-driver type="service" id="cache.psr6"/>
</entity-manager>
<entity-manager name="result_cache_service_doctrine">
<result-cache-driver type="service" id="cache.doctrine"/>
</entity-manager>

<entity-manager name="second_level_cache_pool">
<second-level-cache enabled="true">
<region-cache-driver type="pool" pool="cache.psr6"/>
</second-level-cache>
</entity-manager>
<entity-manager name="second_level_cache_service_psr6">
<second-level-cache enabled="true">
<region-cache-driver type="service" id="cache.psr6"/>
</second-level-cache>
</entity-manager>
<entity-manager name="second_level_cache_service_doctrine">
<second-level-cache enabled="true">
<region-cache-driver type="service" id="cache.doctrine"/>
</second-level-cache>
</entity-manager>
</orm>
</config>
</srv:container>
Loading

0 comments on commit 4202ce6

Please sign in to comment.