Cache

Using cache is a great way of making your application run quicker. The Symfony cachecomponent is shipped with many adapters to different storages. Every adapter isdeveloped for high performance.

The following example shows a typical usage of the cache:

  1. use Symfony\Contracts\Cache\ItemInterface;
  2.  
  3. // The callable will only be executed on a cache miss.
  4. $value = $pool->get('my_cache_key', function (ItemInterface $item) {
  5. $item->expiresAfter(3600);
  6.  
  7. // ... do some HTTP request or heavy computations
  8. $computedValue = 'foobar';
  9.  
  10. return $computedValue;
  11. });
  12.  
  13. echo $value; // 'foobar'
  14.  
  15. // ... and to remove the cache key
  16. $pool->delete('my_cache_key');

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.

Configuring Cache with FrameworkBundle

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 cache.app andcache.system. The system cache is used for things like annotations, serializer,and validation. The cache.app can be used in your code. You can configure whichadapter (template) they use by using the app and system key like:
  • YAML
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. app: cache.adapter.filesystem
  5. system: cache.adapter.system
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <framework:cache app="cache.adapter.filesystem"
  11. system="cache.adapter.system"
  12. />
  13. </framework:config>
  14. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. 'app' => 'cache.adapter.filesystem',
  5. 'system' => 'cache.adapter.system',
  6. ],
  7. ]);

The Cache component comes with a series of adapters pre-configured:

  • YAML
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. directory: '%kernel.cache_dir%/pools' # Only used with cache.adapter.filesystem
  5.  
  6. # service: cache.doctrine
  7. default_doctrine_provider: 'app.doctrine_cache'
  8. # service: cache.psr6
  9. default_psr6_provider: 'app.my_psr6_service'
  10. # service: cache.redis
  11. default_redis_provider: 'redis://localhost'
  12. # service: cache.memcached
  13. default_memcached_provider: 'memcached://localhost'
  14. # service: cache.pdo
  15. default_pdo_provider: 'doctrine.dbal.default_connection'
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <!--
  11. default_doctrine_provider: Service: cache.doctrine
  12. default_psr6_provider: Service: cache.psr6
  13. default_redis_provider: Service: cache.redis
  14. default_memcached_provider: Service: cache.memcached
  15. default_pdo_provider: Service: cache.pdo
  16. -->
  17. <framework:cache directory="%kernel.cache_dir%/pools"
  18. default_doctrine_provider="app.doctrine_cache"
  19. default_psr6_provider="app.my_psr6_service"
  20. default_redis_provider="redis://localhost"
  21. default_memcached_provider="memcached://localhost"
  22. default_pdo_provider="doctrine.dbal.default_connection"
  23. />
  24. </framework:config>
  25. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. // Only used with cache.adapter.filesystem
  5. 'directory' => '%kernel.cache_dir%/pools',
  6.  
  7. // Service: cache.doctrine
  8. 'default_doctrine_provider' => 'app.doctrine_cache',
  9. // Service: cache.psr6
  10. 'default_psr6_provider' => 'app.my_psr6_service',
  11. // Service: cache.redis
  12. 'default_redis_provider' => 'redis://localhost',
  13. // Service: cache.memcached
  14. 'default_memcached_provider' => 'memcached://localhost',
  15. // Service: cache.pdo
  16. 'default_pdo_provider' => 'doctrine.dbal.default_connection',
  17. ],
  18. ]);

Creating Custom (Namespaced) Pools

You can also create more customized pools:

  • YAML
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. default_memcached_provider: 'memcached://localhost'
  5.  
  6. pools:
  7. # creates a "custom_thing.cache" service
  8. # autowireable via "CacheInterface $customThingCache"
  9. # uses the "app" cache configuration
  10. custom_thing.cache:
  11. adapter: cache.app
  12.  
  13. # creates a "my_cache_pool" service
  14. # autowireable via "CacheInterface $myCachePool"
  15. my_cache_pool:
  16. adapter: cache.adapter.array
  17.  
  18. # uses the default_memcached_provider from above
  19. acme.cache:
  20. adapter: cache.adapter.memcached
  21.  
  22. # control adapter's configuration
  23. foobar.cache:
  24. adapter: cache.adapter.memcached
  25. provider: 'memcached://user:[email protected]'
  26.  
  27. # uses the "foobar.cache" pool as its backend but controls
  28. # the lifetime and (like all pools) has a separate cache namespace
  29. short_cache:
  30. adapter: foobar.cache
  31. default_lifetime: 60
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <framework:cache default_memcached_provider="memcached://localhost">
  11. <framework:pool name="custom_thing.cache" adapter="cache.app"/>
  12. <framework:pool name="my_cache_pool" adapter="cache.adapter.array"/>
  13. <framework:pool name="acme.cache" adapter="cache.adapter.memcached"/>
  14. <framework:pool name="foobar.cache" adapter="cache.adapter.memcached" provider="memcached://user:[email protected]"/>
  15. <framework:pool name="short_cache" adapter="foobar.cache" default_lifetime="60"/>
  16. </framework:cache>
  17. </framework:config>
  18. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. 'default_memcached_provider' => 'memcached://localhost',
  5. 'pools' => [
  6. 'custom_thing.cache' => [
  7. 'adapter' => 'cache.app',
  8. ],
  9. 'my_cache_pool' => [
  10. 'adapter' => 'cache.adapter.array',
  11. ],
  12. 'acme.cache' => [
  13. 'adapter' => 'cache.adapter.memcached',
  14. ],
  15. 'foobar.cache' => [
  16. 'adapter' => 'cache.adapter.memcached',
  17. 'provider' => 'memcached://user:[email protected]',
  18. ],
  19. 'short_cache' => [
  20. 'adapter' => 'foobar.cache',
  21. 'default_lifetime' => 60,
  22. ],
  23. ],
  24. ],
  25. ]);

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 CacheInterface orPsr\Cache\CacheItemPoolInterface:

  1. use Symfony\Contracts\Cache\CacheInterface;
  2.  
  3. // from a controller method
  4. public function listProducts(CacheInterface $customThingCache)
  5. {
  6. // ...
  7. }
  8.  
  9. // in a service
  10. public function __construct(CacheInterface $customThingCache)
  11. {
  12. // ...
  13. }

Custom Provider Options

Some providers have specific options that can be configured. TheRedisAdapter 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
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. pools:
  5. cache.my_redis:
  6. adapter: cache.adapter.redis
  7. provider: app.my_custom_redis_provider
  8.  
  9. services:
  10. app.my_custom_redis_provider:
  11. class: \Redis
  12. factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
  13. arguments:
  14. - 'redis://localhost'
  15. - { retry_interval: 2, timeout: 10 }
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <framework:cache>
  11. <framework:pool name="cache.my_redis" adapter="cache.adapter.redis" provider="app.my_custom_redis_provider"/>
  12. </framework:cache>
  13. </framework:config>
  14.  
  15. <services>
  16. <service id="app.my_custom_redis_provider" class="\Redis">
  17. <argument>redis://localhost</argument>
  18. <argument type="collection">
  19. <argument key="retry_interval">2</argument>
  20. <argument key="timeout">10</argument>
  21. </argument>
  22. </service>
  23. </services>
  24. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. 'pools' => [
  5. 'cache.my_redis' => [
  6. 'adapter' => 'cache.adapter.redis',
  7. 'provider' => 'app.my_custom_redis_provider',
  8. ],
  9. ],
  10. ],
  11. ]);
  12.  
  13. $container->getDefinition('app.my_custom_redis_provider', \Redis::class)
  14. ->addArgument('redis://localhost')
  15. ->addArgument([
  16. 'retry_interval' => 2,
  17. 'timeout' => 10
  18. ]);

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
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. pools:
  5. my_cache_pool:
  6. adapter: cache.adapter.psr6
  7. provider: app.my_cache_chain_adapter
  8. cache.my_redis:
  9. adapter: cache.adapter.redis
  10. provider: 'redis://user:[email protected]'
  11. cache.apcu:
  12. adapter: cache.adapter.apcu
  13. cache.array:
  14. adapter: cache.adapter.array
  15.  
  16.  
  17. services:
  18. app.my_cache_chain_adapter:
  19. class: Symfony\Component\Cache\Adapter\ChainAdapter
  20. arguments:
  21. - ['@cache.array', '@cache.apcu', '@cache.my_redis']
  22. - 31536000 # One year
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <framework:cache>
  11. <framework:pool name="my_cache_pool" adapter="cache.adapter.psr6" provider="app.my_cache_chain_adapter"/>
  12. <framework:pool name="cache.my_redis" adapter="cache.adapter.redis" provider="redis://user:[email protected]"/>
  13. <framework:pool name="cache.apcu" adapter="cache.adapter.apcu"/>
  14. <framework:pool name="cache.array" adapter="cache.adapter.array"/>
  15. </framework:cache>
  16. </framework:config>
  17.  
  18. <services>
  19. <service id="app.my_cache_chain_adapter" class="Symfony\Component\Cache\Adapter\ChainAdapter">
  20. <argument type="collection">
  21. <argument type="service" value="cache.array"/>
  22. <argument type="service" value="cache.apcu"/>
  23. <argument type="service" value="cache.my_redis"/>
  24. </argument>
  25. <argument>31536000</argument>
  26. </service>
  27. </services>
  28. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. 'pools' => [
  5. 'my_cache_pool' => [
  6. 'adapter' => 'cache.adapter.psr6',
  7. 'provider' => 'app.my_cache_chain_adapter',
  8. ],
  9. 'cache.my_redis' => [
  10. 'adapter' => 'cache.adapter.redis',
  11. 'provider' => 'redis://user:[email protected]',
  12. ],
  13. 'cache.apcu' => [
  14. 'adapter' => 'cache.adapter.apcu',
  15. ],
  16. 'cache.array' => [
  17. 'adapter' => 'cache.adapter.array',
  18. ],
  19. ],
  20. ],
  21. ]);
  22.  
  23. $container->getDefinition('app.my_cache_chain_adapter', \Symfony\Component\Cache\Adapter\ChainAdapter::class)
  24. ->addArgument([
  25. new Reference('cache.array'),
  26. new Reference('cache.apcu'),
  27. new Reference('cache.my_redis'),
  28. ])
  29. ->addArgument(31536000);

Note

In this configuration the my_cache_pool pool is using the cache.adapter.psr6adapter and the app.my_cache_chain_adapter service as a provider. That isbecause ChainAdapter does not support the cache.pool tag. So it is decoratedwith the ProxyAdapter.

Using Cache Tags

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:

  1. use Symfony\Contracts\Cache\ItemInterface;
  2. use Symfony\Contracts\Cache\TagAwareCacheInterface;
  3.  
  4. class SomeClass
  5. {
  6. private $myCachePool;
  7.  
  8. // using autowiring to inject the cache pool
  9. public function __construct(TagAwareCacheInterface $myCachePool)
  10. {
  11. $this->myCachePool = $myCachePool;
  12. }
  13.  
  14. public function someMethod()
  15. {
  16. $value0 = $this->myCachePool->get('item_0', function (ItemInterface $item) {
  17. $item->tag(['foo', 'bar']);
  18.  
  19. return 'debug';
  20. });
  21.  
  22. $value1 = $this->myCachePool->get('item_1', function (ItemInterface $item) {
  23. $item->tag('foo');
  24.  
  25. return 'debug';
  26. });
  27.  
  28. // Remove all cache keys tagged with "bar"
  29. $this->myCachePool->invalidateTags(['bar']);
  30. }
  31. }

The cache adapter needs to implement TagAwareCacheInterface`to enable this feature. This could be added by using the following configuration.

  • YAML
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. pools:
  5. my_cache_pool:
  6. adapter: cache.adapter.redis
  7. tags: true
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <framework:cache>
  11. <framework:pool name="my_cache_pool" adapter="cache.adapter.redis" tags="true"/>
  12. </framework:cache>
  13. </framework:config>
  14. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. 'pools' => [
  5. 'my_cache_pool' => [
  6. 'adapter' => 'cache.adapter.redis',
  7. 'tags' => true,
  8. ],
  9. ],
  10. ],
  11. ]);

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
  1. # config/packages/cache.yaml
  2. framework:
  3. cache:
  4. pools:
  5. my_cache_pool:
  6. adapter: cache.adapter.redis
  7. tags: tag_pool
  8. tag_pool:
  9. adapter: cache.adapter.apcu
  • XML
  1. <!-- config/packages/cache.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:framework="http://symfony.com/schema/dic/symfony"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd">
  8.  
  9. <framework:config>
  10. <framework:cache>
  11. <framework:pool name="my_cache_pool" adapter="cache.adapter.redis" tags="tag_pool"/>
  12. <framework:pool name="tag_pool" adapter="cache.adapter.apcu"/>
  13. </framework:cache>
  14. </framework:config>
  15. </container>
  • PHP
  1. // config/packages/cache.php
  2. $container->loadFromExtension('framework', [
  3. 'cache' => [
  4. 'pools' => [
  5. 'my_cache_pool' => [
  6. 'adapter' => 'cache.adapter.redis',
  7. 'tags' => 'tag_pool',
  8. ],
  9. 'tag_pool' => [
  10. 'adapter' => 'cache.adapter.apcu',
  11. ],
  12. ],
  13. ],
  14. ]);

Note

The interface TagAwareCacheInterface isautowired to the cache.app service.

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_clearerThe global clearer clears all the cache in every pool. The system cache cleareris used in the bin/console cache:clear command. The app clearer is the defaultclearer.

To see all available cache pools:

  1. $ 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:

  1. $ php bin/console cache:pool:clear my_cache_pool

Clear all custom pools:

  1. $ php bin/console cache:pool:clear cache.app_clearer

Clear all caches everywhere:

  1. $ php bin/console cache:pool:clear cache.global_clearer