diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
index 4c56a58781..8e1e90cfac 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php
@@ -27,36 +27,47 @@ class CachePoolPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
$attributes = array(
- 'provider_service',
+ 'provider',
'namespace',
'default_lifetime',
- 'directory',
);
foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) {
$adapter = $pool = $container->getDefinition($id);
- $tags[0] += array('namespace' => $this->getNamespace($id));
-
+ if ($pool->isAbstract()) {
+ continue;
+ }
+ if (!isset($tags[0]['namespace'])) {
+ $tags[0]['namespace'] = $this->getNamespace($id);
+ }
while ($adapter instanceof DefinitionDecorator) {
$adapter = $container->findDefinition($adapter->getParent());
if ($t = $adapter->getTag('cache.pool')) {
$tags[0] += $t[0];
}
}
- if ($pool->isAbstract()) {
- continue;
+ if (isset($tags[0]['clearer'])) {
+ $clearer = $container->getDefinition($tags[0]['clearer']);
+ } else {
+ $clearer = null;
}
- if (isset($tags[0]['provider_service']) && is_string($tags[0]['provider_service'])) {
- $tags[0]['provider_service'] = new Reference($tags[0]['provider_service']);
+ unset($tags[0]['clearer']);
+
+ if (isset($tags[0]['provider']) && is_string($tags[0]['provider'])) {
+ $tags[0]['provider'] = new Reference($tags[0]['provider']);
}
$i = 0;
foreach ($attributes as $attr) {
if (isset($tags[0][$attr])) {
$pool->replaceArgument($i++, $tags[0][$attr]);
- unset($tags[0][$attr]);
}
+ unset($tags[0][$attr]);
}
if (!empty($tags[0])) {
- throw new \InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "provider_service", "namespace", "default_lifetime" and "directory", found "%s".', $id, implode('", "', array_keys($tags[0]))));
+ throw new \InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "provider", "namespace" and "default_lifetime", found "%s".', $id, implode('", "', array_keys($tags[0]))));
+ }
+
+ if (null !== $clearer) {
+ $clearer->addMethodCall('addPool', array(new Reference($id)));
}
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 20a9e8b299..e125e3096a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -561,14 +561,19 @@ class Configuration implements ConfigurationInterface
->useAttributeAsKey('name')
->prototype('array')
->children()
- ->scalarNode('adapter_service')
- ->info('The cache pool service to use as template definition.')
+ ->scalarNode('adapter')
+ ->info('The cache pool adapter service to use as template definition.')
->defaultValue('cache.adapter.default')
->end()
->booleanNode('public')->defaultFalse()->end()
- ->integerNode('default_lifetime')->defaultNull()->end()
- ->scalarNode('provider_service')->defaultNull()->end()
- ->scalarNode('directory')->defaultNull()->end()
+ ->integerNode('default_lifetime')->end()
+ ->scalarNode('provider')
+ ->info('The service name to use as provider when the specified adapter needs one.')
+ ->end()
+ ->scalarNode('namespace')
+ ->info('The namespace where cached items are stored. Auto-generated by default. Set to false to disable namespacing.')
+ ->end()
+ ->scalarNode('clearer')->defaultValue('cache.default_pools_clearer')->end()
->end()
->end()
->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index f00c2a42ae..ae9d79c414 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -1027,9 +1027,9 @@ class FrameworkExtension extends Extension
}
foreach ($config['pools'] as $name => $poolConfig) {
- $poolDefinition = new DefinitionDecorator($poolConfig['adapter_service']);
+ $poolDefinition = new DefinitionDecorator($poolConfig['adapter']);
$poolDefinition->setPublic($poolConfig['public']);
- unset($poolConfig['adapter_service'], $poolConfig['public']);
+ unset($poolConfig['adapter'], $poolConfig['public']);
$poolDefinition->addTag('cache.pool', $poolConfig);
$container->setDefinition('cache.pool.'.$name, $poolDefinition);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_pools.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_pools.xml
index bea42c651e..eef88060cf 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_pools.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache_pools.xml
@@ -6,33 +6,39 @@
+
+
+
+
-
-
+
+
+
+ %kernel.cache_dir%/pools
+
+
-
-
-
+
+
- %kernel.cache_dir%
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index 26fed333de..d8fc67ae29 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -212,10 +212,11 @@
-
+
-
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php
index f69c97ddc2..3fc66cff09 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php
@@ -49,7 +49,7 @@ class CachePoolPassTest extends \PHPUnit_Framework_TestCase
$container = new ContainerBuilder();
$cachePool = new Definition();
$cachePool->addTag('cache.pool', array(
- 'provider_service' => 'foobar',
+ 'provider' => 'foobar',
'default_lifetime' => 3,
));
$cachePool->addArgument(null);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php
index 2cbd3b51eb..7cf634b92e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php
@@ -4,23 +4,22 @@ $container->loadFromExtension('framework', array(
'cache' => array(
'pools' => array(
'foo' => array(
- 'adapter_service' => 'cache.adapter.apcu',
+ 'adapter' => 'cache.adapter.apcu',
'default_lifetime' => 30,
),
'bar' => array(
- 'adapter_service' => 'cache.adapter.doctrine',
+ 'adapter' => 'cache.adapter.doctrine',
'default_lifetime' => 5,
- 'provider_service' => 'app.doctrine_cache_provider',
+ 'provider' => 'app.doctrine_cache_provider',
),
'baz' => array(
- 'adapter_service' => 'cache.adapter.filesystem',
+ 'adapter' => 'cache.adapter.filesystem',
'default_lifetime' => 7,
- 'directory' => 'app/cache/psr',
),
'foobar' => array(
- 'adapter_service' => 'cache.adapter.psr6',
+ 'adapter' => 'cache.adapter.psr6',
'default_lifetime' => 10,
- 'provider_service' => 'app.cache_pool',
+ 'provider' => 'app.cache_pool',
),
'def' => array(
'default_lifetime' => 11,
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml
index 13b05f6718..d6f472716f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml
@@ -7,10 +7,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml
index f3c6048a77..395009f18a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml
@@ -2,19 +2,18 @@ framework:
cache:
pools:
foo:
- adapter_service: cache.adapter.apcu
+ adapter: cache.adapter.apcu
default_lifetime: 30
bar:
- adapter_service: cache.adapter.doctrine
+ adapter: cache.adapter.doctrine
default_lifetime: 5
- provider_service: app.doctrine_cache_provider
+ provider: app.doctrine_cache_provider
baz:
- adapter_service: cache.adapter.filesystem
+ adapter: cache.adapter.filesystem
default_lifetime: 7
- directory: app/cache/psr
foobar:
- adapter_service: cache.adapter.psr6
+ adapter: cache.adapter.psr6
default_lifetime: 10
- provider_service: app.cache_pool
+ provider: app.cache_pool
def:
default_lifetime: 11
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 6508fe005e..000ec8e6ff 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -683,7 +683,6 @@ abstract class FrameworkExtensionTest extends TestCase
break;
}
- $this->assertTrue($adapterDefinition->hasTag('cache.pool'), sprintf('Service definition "%s" is tagged with the "cache.pool" tag.', $adapterId));
$this->assertTrue($adapterDefinition->isAbstract(), sprintf('Service definition "%s" is abstract.', $adapterId));
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolsTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolsTest.php
new file mode 100644
index 0000000000..b35eebdb31
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolsTest.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+
+use Symfony\Component\Cache\Adapter\FilesystemAdapter;
+use Symfony\Component\Cache\Adapter\RedisAdapter;
+
+class CachePoolsTest extends WebTestCase
+{
+ public function testCachePools()
+ {
+ $this->doTestCachePools(array(), FilesystemAdapter::class);
+ }
+
+ /**
+ * @requires extension redis
+ */
+ public function testRedisCachePools()
+ {
+ try {
+ $this->doTestCachePools(array('root_config' => 'redis_config.yml', 'environment' => 'redis_cache'), RedisAdapter::class);
+ } catch (\PHPUnit_Framework_Error_Warning $e) {
+ if (0 !== strpos($e->getMessage(), 'unable to connect to 127.0.0.1')) {
+ throw $e;
+ }
+ $this->markTestSkipped($e->getMessage());
+ }
+ }
+
+ public function doTestCachePools($options, $adapterClass)
+ {
+ static::bootKernel($options);
+ $container = static::$kernel->getContainer();
+
+ $pool = $container->get('cache.pool.test');
+ $this->assertInstanceOf($adapterClass, $pool);
+
+ $key = 'foobar';
+ $pool->deleteItem($key);
+ $item = $pool->getItem($key);
+ $this->assertFalse($item->isHit());
+
+ $item->set('baz');
+ $pool->save($item);
+ $item = $pool->getItem($key);
+ $this->assertTrue($item->isHit());
+
+ $container->get('cache_clearer')->clear($container->getParameter('kernel.cache_dir'));
+ $item = $pool->getItem($key);
+ $this->assertFalse($item->isHit());
+ }
+
+ protected static function createKernel(array $options = array())
+ {
+ return parent::createKernel(array('test_case' => 'CachePools') + $options);
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php
new file mode 100644
index 0000000000..a73987bcc9
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/bundles.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
+use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+
+return array(
+ new FrameworkBundle(),
+ new TestBundle(),
+);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/config.yml
new file mode 100644
index 0000000000..25aff9cbcb
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/config.yml
@@ -0,0 +1,8 @@
+imports:
+ - { resource: ../config/default.yml }
+
+framework:
+ cache:
+ pools:
+ test:
+ public: true
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/redis_config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/redis_config.yml
new file mode 100644
index 0000000000..1bafa08c7c
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CachePools/redis_config.yml
@@ -0,0 +1,22 @@
+imports:
+ - { resource: ../config/default.yml }
+
+services:
+ cache.adapter.redis.connection:
+ public: false
+ class: Redis
+ calls:
+ - [connect, [127.0.0.1]]
+
+ cache.adapter.default:
+ abstract: true
+ parent: cache.adapter.redis
+ tags:
+ - name: cache.pool
+ provider: cache.adapter.redis.connection
+
+framework:
+ cache:
+ pools:
+ test:
+ public: true
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 689aa7d6b6..ba60449cfc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -19,7 +19,7 @@
"php": ">=5.5.9",
"symfony/asset": "~2.8|~3.0",
"symfony/class-loader": "~2.8|~3.0",
- "symfony/dependency-injection": "~2.8|~3.0",
+ "symfony/dependency-injection": "~3.1",
"symfony/config": "~2.8|~3.0",
"symfony/event-dispatcher": "~2.8|~3.0",
"symfony/http-foundation": "~3.1",
@@ -38,6 +38,7 @@
},
"require-dev": {
"symfony/browser-kit": "~2.8|~3.0",
+ "symfony/cache": "~3.1",
"symfony/console": "~2.8|~3.0",
"symfony/css-selector": "~2.8|~3.0",
"symfony/dom-crawler": "~2.8|~3.0",
diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
index 1fac6c3f65..874dec0b87 100644
--- a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
@@ -28,6 +28,9 @@ class FilesystemAdapter extends AbstractAdapter
$directory = sys_get_temp_dir().'/symfony-cache';
}
if (isset($namespace[0])) {
+ if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
+ throw new InvalidArgumentException(sprintf('FilesystemAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
+ }
$directory .= '/'.$namespace;
}
if (!file_exists($dir = $directory.'/.')) {
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTest.php b/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTest.php
index 28786501a8..15956b424b 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTest.php
@@ -25,6 +25,6 @@ class FilesystemAdapterTest extends CachePoolTest
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
}
- return new FilesystemAdapter(sys_get_temp_dir().DIRECTORY_SEPARATOR.'sf-cache');
+ return new FilesystemAdapter('sf-cache');
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
index 246529d865..e201a56b8a 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
@@ -58,8 +58,8 @@ class PassConfig
$this->removingPasses = array(
new RemovePrivateAliasesPass(),
- new RemoveAbstractDefinitionsPass(),
new ReplaceAliasByActualDefinitionPass(),
+ new RemoveAbstractDefinitionsPass(),
new RepeatedPass(array(
new AnalyzeServiceReferencesPass(),
new InlineServiceDefinitionsPass(),
@@ -102,8 +102,7 @@ class PassConfig
throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
}
- $passes = &$this->$property;
- $passes[] = $pass;
+ $this->{$property}[] = $pass;
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
index 2f94df971a..82e2925572 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
@@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
/**
* This replaces all DefinitionDecorator instances with their equivalent fully
@@ -96,11 +97,12 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
*/
private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
{
- if (!$container->hasDefinition($parent = $definition->getParent())) {
+ try {
+ $parentDef = $container->findDefinition($parent = $definition->getParent());
+ } catch (ServiceNotFoundException $e) {
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
}
- $parentDef = $container->getDefinition($parent);
if ($parentDef instanceof DefinitionDecorator) {
$id = $this->currentId;
$this->currentId = $parent;
diff --git a/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php b/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php
new file mode 100644
index 0000000000..30261b3f7c
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/CacheClearer/Psr6CacheClearer.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheClearer;
+
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * @author Nicolas Grekas
+ */
+class Psr6CacheClearer implements CacheClearerInterface
+{
+ private $pools = array();
+
+ public function addPool(CacheItemPoolInterface $pool)
+ {
+ $this->pools[] = $pool;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear($cacheDir)
+ {
+ foreach ($this->pools as $pool) {
+ $pool->clear();
+ }
+ }
+}