Cache
The following example shows a typical usage of the cache:
Symfony supports the Cache Contracts, PSR-6/16 and Doctrine Cache interfaces.You can read more about these at the component documentation.
New in version 4.2: The cache contracts were introduced in Symfony 4.2.
When configuring the cache component there are a few concepts you should knowof:
- Pool
- This is a service that you will interact with. Each pool will always haveits own namespace and cache items. There is never a conflict between pools.
- Adapter
- An adapter is a template that you use to create Pools.
- Provider
- A provider is a service that some adapters are using to connect to the storage.Redis and Memcached are example of such adapters. If a DSN is used as theprovider then a service is automatically created.There are two pools that are always enabled by default. They are and
cache.system
. The system cache is used for things like annotations, serializer,and validation. Thecache.app
can be used in your code. You can configure whichadapter (template) they use by using theapp
andsystem
key like:
- YAML
- # config/packages/cache.yaml
- framework:
- cache:
- app: cache.adapter.filesystem
- system: cache.adapter.system
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <framework:cache app="cache.adapter.filesystem"
- system="cache.adapter.system"
- />
- </framework:config>
- </container>
- PHP
- // config/packages/cache.php
- $container->loadFromExtension('framework', [
- 'cache' => [
- 'app' => 'cache.adapter.filesystem',
- 'system' => 'cache.adapter.system',
- ],
- ]);
The Cache component comes with a series of adapters pre-configured:
- cache.adapter.array
- cache.adapter.filesystem
- cache.adapter.pdo
- cache.adapter.redisSome of these adapters could be configured via shortcuts. Using these shortcutswill create pool with service id of
cache.[type]
- YAML
- # config/packages/cache.yaml
- framework:
- cache:
- directory: '%kernel.cache_dir%/pools' # Only used with cache.adapter.filesystem
- # service: cache.doctrine
- default_doctrine_provider: 'app.doctrine_cache'
- # service: cache.psr6
- default_psr6_provider: 'app.my_psr6_service'
- # service: cache.redis
- default_redis_provider: 'redis://localhost'
- # service: cache.memcached
- default_memcached_provider: 'memcached://localhost'
- # service: cache.pdo
- default_pdo_provider: 'doctrine.dbal.default_connection'
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <!--
- default_doctrine_provider: Service: cache.doctrine
- default_psr6_provider: Service: cache.psr6
- default_redis_provider: Service: cache.redis
- default_memcached_provider: Service: cache.memcached
- default_pdo_provider: Service: cache.pdo
- -->
- <framework:cache directory="%kernel.cache_dir%/pools"
- default_doctrine_provider="app.doctrine_cache"
- default_psr6_provider="app.my_psr6_service"
- default_redis_provider="redis://localhost"
- default_memcached_provider="memcached://localhost"
- default_pdo_provider="doctrine.dbal.default_connection"
- />
- </framework:config>
- </container>
- PHP
- // config/packages/cache.php
- $container->loadFromExtension('framework', [
- 'cache' => [
- // Only used with cache.adapter.filesystem
- 'directory' => '%kernel.cache_dir%/pools',
- // Service: cache.doctrine
- 'default_doctrine_provider' => 'app.doctrine_cache',
- // Service: cache.psr6
- 'default_psr6_provider' => 'app.my_psr6_service',
- // Service: cache.redis
- 'default_redis_provider' => 'redis://localhost',
- // Service: cache.memcached
- 'default_memcached_provider' => 'memcached://localhost',
- // Service: cache.pdo
- 'default_pdo_provider' => 'doctrine.dbal.default_connection',
- ],
- ]);
Creating Custom (Namespaced) Pools
You can also create more customized pools:
- YAML
- # config/packages/cache.yaml
- framework:
- cache:
- default_memcached_provider: 'memcached://localhost'
- pools:
- # creates a "custom_thing.cache" service
- # autowireable via "CacheInterface $customThingCache"
- # uses the "app" cache configuration
- custom_thing.cache:
- adapter: cache.app
- # creates a "my_cache_pool" service
- # autowireable via "CacheInterface $myCachePool"
- my_cache_pool:
- adapter: cache.adapter.array
- # uses the default_memcached_provider from above
- acme.cache:
- adapter: cache.adapter.memcached
- # control adapter's configuration
- foobar.cache:
- adapter: cache.adapter.memcached
- provider: 'memcached://user:[email protected]'
- # uses the "foobar.cache" pool as its backend but controls
- # the lifetime and (like all pools) has a separate cache namespace
- short_cache:
- default_lifetime: 60
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <framework:cache default_memcached_provider="memcached://localhost">
- <framework:pool name="custom_thing.cache" adapter="cache.app"/>
- <framework:pool name="my_cache_pool" adapter="cache.adapter.array"/>
- <framework:pool name="acme.cache" adapter="cache.adapter.memcached"/>
- <framework:pool name="foobar.cache" adapter="cache.adapter.memcached" provider="memcached://user:"/>
- <framework:pool name="short_cache" adapter="foobar.cache" default_lifetime="60"/>
- </framework:cache>
- </framework:config>
- </container>
- PHP
Each pool manages a set of independent cache keys: keys of different poolsnever collide, even if they share the same backend. This is achieved by prefixingkeys with a namespace that's generated by hashing the name of the pool, the nameof the compiled container class and a configurable seedthat defaults to the project directory.
Each custom pool becomes a service where the service id is the name of the pool(e.g. custom_thing.cache
). An autowiring alias is also created for each poolusing the camel case version of its name - e.g. custom_thing.cache
can beinjected automatically by naming the argument $customThingCache
and type-hinting itwith either orPsr\Cache\CacheItemPoolInterface
:
- use Symfony\Contracts\Cache\CacheInterface;
- // from a controller method
- public function listProducts(CacheInterface $customThingCache)
- {
- // ...
- }
- // in a service
- public function __construct(CacheInterface $customThingCache)
- {
- // ...
- }
Some providers have specific options that can be configured. The allows you tocreate providers with option timeout
, retry_interval
. etc. To use theseoptions with non-default values you need to create your own \Redis
providerand use that when configuring the pool.
- YAML
- # config/packages/cache.yaml
- framework:
- cache:
- pools:
- cache.my_redis:
- adapter: cache.adapter.redis
- provider: app.my_custom_redis_provider
- services:
- app.my_custom_redis_provider:
- class: \Redis
- factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
- arguments:
- - 'redis://localhost'
- - { retry_interval: 2, timeout: 10 }
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <framework:cache>
- <framework:pool name="cache.my_redis" adapter="cache.adapter.redis" provider="app.my_custom_redis_provider"/>
- </framework:cache>
- </framework:config>
- <services>
- <service id="app.my_custom_redis_provider" class="\Redis">
- <argument>redis://localhost</argument>
- <argument type="collection">
- <argument key="retry_interval">2</argument>
- <argument key="timeout">10</argument>
- </argument>
- </service>
- </services>
- </container>
- PHP
- // config/packages/cache.php
- $container->loadFromExtension('framework', [
- 'cache' => [
- 'pools' => [
- 'cache.my_redis' => [
- 'adapter' => 'cache.adapter.redis',
- 'provider' => 'app.my_custom_redis_provider',
- ],
- ],
- ],
- ]);
- $container->getDefinition('app.my_custom_redis_provider', \Redis::class)
- ->addArgument('redis://localhost')
- ->addArgument([
- 'retry_interval' => 2,
- 'timeout' => 10
- ]);
Creating a Cache Chain
Different cache adapters have different strengths and weaknesses. Some might be reallyquick but small and some may be able to contain a lot of data but are quite slow.To get the best of both worlds you may use a chain of adapters. The idea is tofirst look at the quick adapter and then move on to slower adapters. In the worstcase the value needs to be recalculated.
- YAML
- # config/packages/cache.yaml
- framework:
- cache:
- pools:
- my_cache_pool:
- adapter: cache.adapter.psr6
- provider: app.my_cache_chain_adapter
- cache.my_redis:
- adapter: cache.adapter.redis
- provider: 'redis://user:'
- cache.apcu:
- adapter: cache.adapter.apcu
- cache.array:
- adapter: cache.adapter.array
- services:
- app.my_cache_chain_adapter:
- class: Symfony\Component\Cache\Adapter\ChainAdapter
- arguments:
- - ['@cache.array', '@cache.apcu', '@cache.my_redis']
- - 31536000 # One year
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <framework:cache>
- <framework:pool name="my_cache_pool" adapter="cache.adapter.psr6" provider="app.my_cache_chain_adapter"/>
- <framework:pool name="cache.my_redis" adapter="cache.adapter.redis" provider="redis://user:[email protected]"/>
- <framework:pool name="cache.apcu" adapter="cache.adapter.apcu"/>
- <framework:pool name="cache.array" adapter="cache.adapter.array"/>
- </framework:cache>
- </framework:config>
- <services>
- <service id="app.my_cache_chain_adapter" class="Symfony\Component\Cache\Adapter\ChainAdapter">
- <argument type="collection">
- <argument type="service" value="cache.array"/>
- <argument type="service" value="cache.apcu"/>
- </argument>
- <argument>31536000</argument>
- </service>
- </services>
- </container>
- PHP
- // config/packages/cache.php
- $container->loadFromExtension('framework', [
- 'cache' => [
- 'pools' => [
- 'my_cache_pool' => [
- 'adapter' => 'cache.adapter.psr6',
- 'provider' => 'app.my_cache_chain_adapter',
- ],
- 'cache.my_redis' => [
- 'adapter' => 'cache.adapter.redis',
- 'provider' => 'redis://user:',
- ],
- 'cache.apcu' => [
- 'adapter' => 'cache.adapter.apcu',
- ],
- 'cache.array' => [
- 'adapter' => 'cache.adapter.array',
- ],
- ],
- ],
- ]);
- $container->getDefinition('app.my_cache_chain_adapter', \Symfony\Component\Cache\Adapter\ChainAdapter::class)
- ->addArgument([
- new Reference('cache.array'),
- new Reference('cache.apcu'),
- new Reference('cache.my_redis'),
- ])
- ->addArgument(31536000);
Note
In this configuration the my_cache_pool
pool is using the cache.adapter.psr6
adapter and the app.my_cache_chain_adapter
service as a provider. That isbecause ChainAdapter
does not support the tag. So it is decoratedwith the ProxyAdapter
.
In applications with many cache keys it could be useful to organize the data storedto be able to invalidate the cache more efficient. One way to achieve that is touse cache tags. One or more tags could be added to the cache item. All items withthe same key could be invalidate with one function call:
- use Symfony\Contracts\Cache\ItemInterface;
- use Symfony\Contracts\Cache\TagAwareCacheInterface;
- class SomeClass
- {
- private $myCachePool;
- // using autowiring to inject the cache pool
- public function __construct(TagAwareCacheInterface $myCachePool)
- {
- $this->myCachePool = $myCachePool;
- }
- public function someMethod()
- {
- $value0 = $this->myCachePool->get('item_0', function (ItemInterface $item) {
- $item->tag(['foo', 'bar']);
- return 'debug';
- });
- $value1 = $this->myCachePool->get('item_1', function (ItemInterface $item) {
- $item->tag('foo');
- return 'debug';
- });
- // Remove all cache keys tagged with "bar"
- $this->myCachePool->invalidateTags(['bar']);
- }
- }
The cache adapter needs to implement TagAwareCacheInterface`
to enable this feature. This could be added by using the following configuration.
- YAML
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <framework:cache>
- <framework:pool name="my_cache_pool" adapter="cache.adapter.redis" tags="true"/>
- </framework:cache>
- </framework:config>
- </container>
- PHP
- // config/packages/cache.php
- $container->loadFromExtension('framework', [
- 'cache' => [
- 'pools' => [
- 'my_cache_pool' => [
- 'adapter' => 'cache.adapter.redis',
- 'tags' => true,
- ],
- ],
- ],
- ]);
Tags are stored in the same pool by default. This is good in most scenarios. Butsometimes it might be better to store the tags in a different pool. That could beachieved by specifying the adapter.
- YAML
- # config/packages/cache.yaml
- framework:
- cache:
- pools:
- my_cache_pool:
- adapter: cache.adapter.redis
- tags: tag_pool
- tag_pool:
- adapter: cache.adapter.apcu
- XML
- <!-- config/packages/cache.xml -->
- <?xml version="1.0" encoding="UTF-8" ?>
- <container xmlns="http://symfony.com/schema/dic/services"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:framework="http://symfony.com/schema/dic/symfony"
- xsi:schemaLocation="http://symfony.com/schema/dic/services
- https://symfony.com/schema/dic/services/services-1.0.xsd">
- <framework:config>
- <framework:cache>
- <framework:pool name="my_cache_pool" adapter="cache.adapter.redis" tags="tag_pool"/>
- <framework:pool name="tag_pool" adapter="cache.adapter.apcu"/>
- </framework:cache>
- </framework:config>
- </container>
- PHP
- // config/packages/cache.php
- $container->loadFromExtension('framework', [
- 'cache' => [
- 'pools' => [
- 'my_cache_pool' => [
- 'adapter' => 'cache.adapter.redis',
- 'tags' => 'tag_pool',
- ],
- 'tag_pool' => [
- 'adapter' => 'cache.adapter.apcu',
- ],
- ],
- ],
- ]);
Note
Clearing the Cache
To clear the cache you can use the bin/console cache:pool:clear [pool]
command.That will remove all the entries from your storage and you will have to recalculateall values. You can also group your pools into "cache clearers". There are 3 cacheclearers by default:
cache.global_clearer
cache.system_clearer
cache.app_clearer
The global clearer clears all the cache in every pool. The system cache cleareris used in the command. The app clearer is the defaultclearer.
To see all available cache pools:
- $ php bin/console cache:pool:list
New in version 4.3: The cache:pool:list
command was introduced in Symfony 4.3.
Clear one pool:
- $ php bin/console cache:pool:clear my_cache_pool
Clear all custom pools:
Clear all caches everywhere: