feature #26934 [FrameworkBundle] Allow configuring taggable cache pools (nicolas-grekas)
This PR was merged into the 4.2-dev branch.
Discussion
----------
[FrameworkBundle] Allow configuring taggable cache pools
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #25903
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/pull/9652
This PR adds a new configuration option for cache pools:
```yaml
framework:
cache:
pools:
app.taggable_pool:
tags: true
app.taggable_pool_with_separate_store_for_tags:
tags: app.my_pool_for_tags
```
Commits
-------
896be4cc2b
[FrameworkBundle] Allow configuring taggable cache pools
This commit is contained in:
commit
143628fa51
@ -1,6 +1,11 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
4.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Allowed configuring taggable cache pools via a new `framework.cache.pools.tags` option (bool|service-id)
|
||||||
|
|
||||||
4.1.0
|
4.1.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ final class CachePoolClearerPass implements CompilerPassInterface
|
|||||||
foreach ($container->findTaggedServiceIds('cache.pool.clearer') as $id => $attr) {
|
foreach ($container->findTaggedServiceIds('cache.pool.clearer') as $id => $attr) {
|
||||||
$clearer = $container->getDefinition($id);
|
$clearer = $container->getDefinition($id);
|
||||||
$pools = array();
|
$pools = array();
|
||||||
foreach ($clearer->getArgument(0) as $id => $ref) {
|
foreach ($clearer->getArgument(0) as $name => $ref) {
|
||||||
if ($container->hasDefinition($id)) {
|
if ($container->hasDefinition($ref)) {
|
||||||
$pools[$id] = new Reference($id);
|
$pools[$name] = new Reference($ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$clearer->replaceArgument(0, $pools);
|
$clearer->replaceArgument(0, $pools);
|
||||||
|
@ -41,6 +41,7 @@ class CachePoolPass implements CompilerPassInterface
|
|||||||
$clearers = array();
|
$clearers = array();
|
||||||
$attributes = array(
|
$attributes = array(
|
||||||
'provider',
|
'provider',
|
||||||
|
'name',
|
||||||
'namespace',
|
'namespace',
|
||||||
'default_lifetime',
|
'default_lifetime',
|
||||||
'reset',
|
'reset',
|
||||||
@ -56,8 +57,9 @@ class CachePoolPass implements CompilerPassInterface
|
|||||||
$tags[0] += $t[0];
|
$tags[0] += $t[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$name = $tags[0]['name'] ?? $id;
|
||||||
if (!isset($tags[0]['namespace'])) {
|
if (!isset($tags[0]['namespace'])) {
|
||||||
$tags[0]['namespace'] = $this->getNamespace($seed, $id);
|
$tags[0]['namespace'] = $this->getNamespace($seed, $name);
|
||||||
}
|
}
|
||||||
if (isset($tags[0]['clearer'])) {
|
if (isset($tags[0]['clearer'])) {
|
||||||
$clearer = $tags[0]['clearer'];
|
$clearer = $tags[0]['clearer'];
|
||||||
@ -67,7 +69,7 @@ class CachePoolPass implements CompilerPassInterface
|
|||||||
} else {
|
} else {
|
||||||
$clearer = null;
|
$clearer = null;
|
||||||
}
|
}
|
||||||
unset($tags[0]['clearer']);
|
unset($tags[0]['clearer'], $tags[0]['name']);
|
||||||
|
|
||||||
if (isset($tags[0]['provider'])) {
|
if (isset($tags[0]['provider'])) {
|
||||||
$tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider']));
|
$tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider']));
|
||||||
@ -86,14 +88,14 @@ class CachePoolPass implements CompilerPassInterface
|
|||||||
unset($tags[0][$attr]);
|
unset($tags[0][$attr]);
|
||||||
}
|
}
|
||||||
if (!empty($tags[0])) {
|
if (!empty($tags[0])) {
|
||||||
throw new InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "namespace", "default_lifetime" and "reset", found "%s".', $id, implode('", "', array_keys($tags[0]))));
|
throw new InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime" and "reset", found "%s".', $id, implode('", "', array_keys($tags[0]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $clearer) {
|
if (null !== $clearer) {
|
||||||
$clearers[$clearer][$id] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
$clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
$pools[$id] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
$pools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
$clearer = 'cache.global_clearer';
|
$clearer = 'cache.global_clearer';
|
||||||
|
@ -870,6 +870,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
->prototype('array')
|
->prototype('array')
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('adapter')->defaultValue('cache.app')->end()
|
->scalarNode('adapter')->defaultValue('cache.app')->end()
|
||||||
|
->scalarNode('tags')->defaultNull()->end()
|
||||||
->booleanNode('public')->defaultFalse()->end()
|
->booleanNode('public')->defaultFalse()->end()
|
||||||
->integerNode('default_lifetime')->end()
|
->integerNode('default_lifetime')->end()
|
||||||
->scalarNode('provider')
|
->scalarNode('provider')
|
||||||
|
@ -22,6 +22,7 @@ use Symfony\Bundle\FullStack;
|
|||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||||
|
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
|
||||||
use Symfony\Component\Cache\ResettableInterface;
|
use Symfony\Component\Cache\ResettableInterface;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
@ -1556,12 +1557,31 @@ class FrameworkExtension extends Extension
|
|||||||
$config['pools']['cache.'.$name] = array(
|
$config['pools']['cache.'.$name] = array(
|
||||||
'adapter' => $config[$name],
|
'adapter' => $config[$name],
|
||||||
'public' => true,
|
'public' => true,
|
||||||
|
'tags' => false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
foreach ($config['pools'] as $name => $pool) {
|
foreach ($config['pools'] as $name => $pool) {
|
||||||
|
if ($config['pools'][$pool['adapter']]['tags'] ?? false) {
|
||||||
|
$pool['adapter'] = '.'.$pool['adapter'].'.inner';
|
||||||
|
}
|
||||||
$definition = new ChildDefinition($pool['adapter']);
|
$definition = new ChildDefinition($pool['adapter']);
|
||||||
|
|
||||||
|
if ($pool['tags']) {
|
||||||
|
if ($config['pools'][$pool['tags']]['tags'] ?? false) {
|
||||||
|
$pool['tags'] = '.'.$pool['tags'].'.inner';
|
||||||
|
}
|
||||||
|
$container->register($name, TagAwareAdapter::class)
|
||||||
|
->addArgument(new Reference('.'.$name.'.inner'))
|
||||||
|
->addArgument(true !== $pool['tags'] ? new Reference($pool['tags']) : null)
|
||||||
|
->setPublic($pool['public'])
|
||||||
|
;
|
||||||
|
|
||||||
|
$pool['name'] = $name;
|
||||||
|
$pool['public'] = false;
|
||||||
|
$name = '.'.$name.'.inner';
|
||||||
|
}
|
||||||
$definition->setPublic($pool['public']);
|
$definition->setPublic($pool['public']);
|
||||||
unset($pool['adapter'], $pool['public']);
|
unset($pool['adapter'], $pool['public'], $pool['tags']);
|
||||||
|
|
||||||
$definition->addTag('cache.pool', $pool);
|
$definition->addTag('cache.pool', $pool);
|
||||||
$container->setDefinition($name, $definition);
|
$container->setDefinition($name, $definition);
|
||||||
|
@ -39,6 +39,11 @@ class CachePoolClearerPassTest extends TestCase
|
|||||||
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias'));
|
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias'));
|
||||||
$container->setDefinition('public.pool', $publicPool);
|
$container->setDefinition('public.pool', $publicPool);
|
||||||
|
|
||||||
|
$publicPool = new Definition();
|
||||||
|
$publicPool->addArgument('namespace');
|
||||||
|
$publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias', 'name' => 'pool2'));
|
||||||
|
$container->setDefinition('public.pool2', $publicPool);
|
||||||
|
|
||||||
$privatePool = new Definition();
|
$privatePool = new Definition();
|
||||||
$privatePool->setPublic(false);
|
$privatePool->setPublic(false);
|
||||||
$privatePool->addArgument('namespace');
|
$privatePool->addArgument('namespace');
|
||||||
@ -55,7 +60,11 @@ class CachePoolClearerPassTest extends TestCase
|
|||||||
$pass->process($container);
|
$pass->process($container);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertEquals(array(array('public.pool' => new Reference('public.pool'))), $clearer->getArguments());
|
$expected = array(array(
|
||||||
$this->assertEquals(array(array('public.pool' => new Reference('public.pool'))), $globalClearer->getArguments());
|
'public.pool' => new Reference('public.pool'),
|
||||||
|
'pool2' => new Reference('public.pool2'),
|
||||||
|
));
|
||||||
|
$this->assertEquals($expected, $clearer->getArguments());
|
||||||
|
$this->assertEquals($expected, $globalClearer->getArguments());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,28 @@ class CachePoolPassTest extends TestCase
|
|||||||
$this->assertSame(3, $cachePool->getArgument(2));
|
$this->assertSame(3, $cachePool->getArgument(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testWithNameAttribute()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->setParameter('kernel.debug', false);
|
||||||
|
$container->setParameter('kernel.name', 'app');
|
||||||
|
$container->setParameter('kernel.environment', 'prod');
|
||||||
|
$container->setParameter('cache.prefix.seed', 'foo');
|
||||||
|
$cachePool = new Definition();
|
||||||
|
$cachePool->addTag('cache.pool', array(
|
||||||
|
'name' => 'foobar',
|
||||||
|
'provider' => 'foobar',
|
||||||
|
));
|
||||||
|
$cachePool->addArgument(null);
|
||||||
|
$cachePool->addArgument(null);
|
||||||
|
$cachePool->addArgument(null);
|
||||||
|
$container->setDefinition('app.cache_pool', $cachePool);
|
||||||
|
|
||||||
|
$this->cachePoolPass->process($container);
|
||||||
|
|
||||||
|
$this->assertSame('9HvPgAayyh', $cachePool->getArgument(1));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \InvalidArgumentException
|
* @expectedException \InvalidArgumentException
|
||||||
* @expectedExceptionMessage Invalid "cache.pool" tag for service "app.cache_pool": accepted attributes are
|
* @expectedExceptionMessage Invalid "cache.pool" tag for service "app.cache_pool": accepted attributes are
|
||||||
|
@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
|
|||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||||
|
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
|
||||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||||
|
|
||||||
class CachePoolsTest extends WebTestCase
|
class CachePoolsTest extends WebTestCase
|
||||||
@ -94,6 +95,25 @@ class CachePoolsTest extends WebTestCase
|
|||||||
|
|
||||||
$item = $pool2->getItem($key);
|
$item = $pool2->getItem($key);
|
||||||
$this->assertTrue($item->isHit());
|
$this->assertTrue($item->isHit());
|
||||||
|
|
||||||
|
$prefix = "\0".TagAwareAdapter::class."\0";
|
||||||
|
$pool4 = $container->get('cache.pool4');
|
||||||
|
$this->assertInstanceof(TagAwareAdapter::class, $pool4);
|
||||||
|
$pool4 = (array) $pool4;
|
||||||
|
$this->assertSame($pool4[$prefix.'pool'], $pool4[$prefix.'tags'] ?? $pool4['tags']);
|
||||||
|
|
||||||
|
$pool5 = $container->get('cache.pool5');
|
||||||
|
$this->assertInstanceof(TagAwareAdapter::class, $pool5);
|
||||||
|
$pool5 = (array) $pool5;
|
||||||
|
$this->assertSame($pool2, $pool5[$prefix.'tags'] ?? $pool5['tags']);
|
||||||
|
|
||||||
|
$pool6 = $container->get('cache.pool6');
|
||||||
|
$this->assertInstanceof(TagAwareAdapter::class, $pool6);
|
||||||
|
$pool6 = (array) $pool6;
|
||||||
|
$this->assertSame($pool4[$prefix.'pool'], $pool6[$prefix.'tags'] ?? $pool6['tags']);
|
||||||
|
|
||||||
|
$pool7 = $container->get('cache.pool7');
|
||||||
|
$this->assertNotInstanceof(TagAwareAdapter::class, $pool7);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function createKernel(array $options = array())
|
protected static function createKernel(array $options = array())
|
||||||
|
@ -12,3 +12,15 @@ framework:
|
|||||||
adapter: cache.pool3
|
adapter: cache.pool3
|
||||||
cache.pool3:
|
cache.pool3:
|
||||||
clearer: ~
|
clearer: ~
|
||||||
|
cache.pool4:
|
||||||
|
tags: true
|
||||||
|
public: true
|
||||||
|
cache.pool5:
|
||||||
|
tags: cache.pool2
|
||||||
|
public: true
|
||||||
|
cache.pool6:
|
||||||
|
tags: cache.pool4
|
||||||
|
public: true
|
||||||
|
cache.pool7:
|
||||||
|
adapter: cache.pool4
|
||||||
|
public: true
|
||||||
|
@ -15,3 +15,17 @@ framework:
|
|||||||
cache.pool2:
|
cache.pool2:
|
||||||
public: true
|
public: true
|
||||||
clearer: ~
|
clearer: ~
|
||||||
|
cache.pool3:
|
||||||
|
clearer: ~
|
||||||
|
cache.pool4:
|
||||||
|
tags: true
|
||||||
|
public: true
|
||||||
|
cache.pool5:
|
||||||
|
tags: cache.pool2
|
||||||
|
public: true
|
||||||
|
cache.pool6:
|
||||||
|
tags: cache.pool4
|
||||||
|
public: true
|
||||||
|
cache.pool7:
|
||||||
|
adapter: cache.pool4
|
||||||
|
public: true
|
||||||
|
@ -26,3 +26,17 @@ framework:
|
|||||||
cache.pool2:
|
cache.pool2:
|
||||||
public: true
|
public: true
|
||||||
clearer: ~
|
clearer: ~
|
||||||
|
cache.pool3:
|
||||||
|
clearer: ~
|
||||||
|
cache.pool4:
|
||||||
|
tags: true
|
||||||
|
public: true
|
||||||
|
cache.pool5:
|
||||||
|
tags: cache.pool2
|
||||||
|
public: true
|
||||||
|
cache.pool6:
|
||||||
|
tags: cache.pool4
|
||||||
|
public: true
|
||||||
|
cache.pool7:
|
||||||
|
adapter: cache.pool4
|
||||||
|
public: true
|
||||||
|
Reference in New Issue
Block a user