Cache

3.4 version

Cache

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

The following example shows a typical usage of the cache:

1
2
3
4
5
6
7
8
9
if (!$cache->has('my_cache_key')) {
    // ... do some HTTP request or heavy computations
    $cache->set('my_cache_key', 'foobar', 3600);
}

echo $cache->get('my_cache_key'); // 'foobar'

// ... and to remove the cache key
$cache->delete('my_cache_key');

Symfony supports PSR-6 and PSR-16 cache interfaces. You can read more about these at the component documentation.

Configuring Cache with FrameworkBundle

When configuring the cache component there are a few concepts you should know of:

Pool
This is a service that you will interact with. Each pool will always have its 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 the provider then a service is automatically created.

There are two pools that are always enabled by default. They are cache.app and cache.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 which adapter (template) they use by using the app and system key like:

  • YAML
    1
    2
    3
    4
    5
    # app/config/config.yml
    framework:
        cache:
            app: cache.adapter.filesystem
            system: cache.adapter.system
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- app/config/config.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
    1
    2
    3
    4
    5
    6
    7
    // app/config/config.php
    $container->loadFromExtension('framework', [
        'cache' => [
            'app' => 'cache.adapter.filesystem',
            'system' => 'cache.adapter.system',
        ],
    ]);
    

The Cache component comes with a series of adapters already created:

Some of these adapters could be configured via shortcuts. Using these shortcuts will create pool with service id of cache.[type]

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    # app/config/config.yml
    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
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <!-- app/config/config.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
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // app/config/config.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 Pools

You can also create more customized pools. All you need is an adapter:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    # app/config/config.yml
    framework:
        cache:
            default_memcached_provider: 'memcached://localhost'
            pools:
                my_cache_pool:
                    adapter: cache.adapter.filesystem
                cache.acme:
                    adapter: cache.adapter.memcached
                cache.foobar:
                    adapter: cache.adapter.memcached
                    provider: 'memcached://user:[email protected]'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- app/config/config.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="my_cache_pool" adapter="cache.adapter.filesystem"/>
                <framework:pool name="cache.acme" adapter="cache.adapter.memcached"/>
                <framework:pool name="cache.foobar" adapter="cache.adapter.memcached" provider="memcached://user:[email protected]"/>
            </framework:cache>
        </framework:config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // app/config/config.php
    $container->loadFromExtension('framework', [
        'cache' => [
            'default_memcached_provider' => 'memcached://localhost',
            'pools' => [
                'my_cache_pool' => [
                    'adapter' => 'cache.adapter.filesystem',
                ],
                'cache.acme' => [
                    'adapter' => 'cache.adapter.memcached',
                ],
                'cache.foobar' => [
                    'adapter' => 'cache.adapter.memcached',
                    'provider' => 'memcached://user:[email protected]',
                ],
            ],
        ],
    ]);
    

The configuration above will create 3 services: my_cache_pool, cache.acme and cache.foobar. The my_cache_pool pool is using the ArrayAdapter and the other two are using the MemcachedAdapter. The cache.acme pool is using the Memcached server on localhost and cache.foobar is using the Memcached server at example.com.

For advanced configurations it could sometimes be useful to use a pool as an adapter.

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # app/config/config.yml
    framework:
        cache:
            app: my_configured_app_cache
            pools:
                my_cache_pool:
                    adapter: cache.adapter.memcached
                    provider: 'memcached://user:[email protected]'
                cache.short_cache:
                    adapter: my_cache_pool
                    default_lifetime: 60
                cache.long_cache:
                    adapter: my_cache_pool
                    default_lifetime: 604800
                my_configured_app_cache:
                    # "cache.adapter.filesystem" is the default for "cache.app"
                    adapter: cache.adapter.filesystem
                    default_lifetime: 3600
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!-- app/config/config.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="my_cache_pool">
                <framework:pool name="my_cache_pool" adapter="cache.adapter.memcached" provider="memcached://user:[email protected]"/>
                <framework:pool name="cache.short_cache" adapter="my_cache_pool" default_lifetime="604800"/>
                <framework:pool name="cache.long_cache" adapter="my_cache_pool" default_lifetime="604800"/>
                <!-- "cache.adapter.filesystem" is the default for "cache.app" -->
                <framework:pool name="my_configured_app_cache" adapter="cache.adapter.filesystem" default_lifetime="3600"/>
            </framework:cache>
        </framework:config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // app/config/config.php
    $container->loadFromExtension('framework', [
        'cache' => [
            'app' => 'my_configured_app_cache',
            'pools' => [
                'my_cache_pool' => [
                    'adapter' => 'cache.adapter.memcached',
                    'provider' => 'memcached://user:[email protected]',
                ],
                'cache.short_cache' => [
                    'adapter' => 'cache.adapter.memcached',
                    'default_lifetime' => 60,
                ],
                'cache.long_cache' => [
                    'adapter' => 'cache.adapter.memcached',
                    'default_lifetime' => 604800,
                ],
                'my_configured_app_cache' => [
                    // "cache.adapter.filesystem" is the default for "cache.app"
                    'adapter' => 'cache.adapter.filesystem',
                    'default_lifetime' => 3600,
                ],
            ],
        ],
    ]);
    

Custom Provider Options

Some providers have specific options that can be configured. The RedisAdapter allows you to create providers with option timeout, retry_interval. etc. To use these options with non-default values you need to create your own \Redis provider and use that when configuring the pool.

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    # app/config/config.yml
    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
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <!-- app/config/config.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
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // app/config/config.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 really quick but optimized to store small items 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.

A cache chain combines several cache pools into a single one. When storing an item in a cache chain, Symfony stores it in all pools sequentially. When retrieving an item, Symfony tries to get it from the first pool. If it's not found, it tries the next pools until the item is found or an exception is thrown. Because of this behavior, it's recommended to define the adapters in the chain in order from the fastest to the slowest.

If an error happens when storing an item in a pool, Symfony stores it in the other pools and no exception is thrown. Later, when the item is retrieved, Symfony stores the item automatically in all the missing pools.

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # app/config/config.yml
    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:[email protected]'
                cache.apcu:
                    adapter: cache.adapter.apcu
                cache.array:
                    adapter: cache.adapter.filesystem
    
    
    services:
        app.my_cache_chain_adapter:
            class: Symfony\Component\Cache\Adapter\ChainAdapter
            arguments:
                - ['@cache.array', '@cache.apcu', '@cache.my_redis']
                - 31536000 # One year
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <!-- app/config/config.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.filesystem"/>
            </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 type="service" value="cache.my_redis"/>
                </argument>
                <argument>31536000</argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // app/config/config.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:[email protected]',
                ],
                'cache.apcu' => [
                    'adapter' => 'cache.adapter.apcu',
                ],
                'cache.array' => [
                    'adapter' => 'cache.adapter.filesystem',
                ],
            ],
        ],
    ]);
    
    $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 is because ChainAdapter does not support the cache.pool tag. So it is decorated with the ProxyAdapter.

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 recalculate all values. You can also group your pools into "cache clearers". There are 3 cache clearers by default:

  • cache.global_clearer
  • cache.system_clearer
  • cache.app_clearer

The global clearer clears all the cache in every pool. The system cache clearer is used in the bin/console cache:clear command. The app clearer is the default clearer.

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

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.