New in Symfony 3.1: Cache component

Contributed by
Nicolas Grekas
in #17408.

This is the last article in the "New in Symfony 3.1" series and it introduces the most important new feature of Symfony 3.1: the Cache component.

This new component is a strict implementation of the PSR-6: Caching Interface standard. You can use it to cache arbitrary content in your application and some Symfony components use it internally to improve their performance.

The following example shows how to create, save and delete information in a filesystem-based cache:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

// available adapters: filesystem, apcu, redis, array, doctrine cache, etc.
$cache = new FilesystemAdapter();

// create a new item getting it from the cache
$numProducts = $cache->getItem('stats.num_products');

// assign a value to the item and save it
$numProducts->set(4711);
$cache->save($numProducts);

// retrieve the cache item
$numProducts = $cache->getItem('stats.num_products');
if (!$numProducts->isHit()) {
    // ... item does not exists in the cache
}
// retrieve the value stored by the item
$total = $numProducts->get();

// remove the cache item
$cache->deleteItem('stats.num_products');

The Cache component provides adapters for the most common caching backends (Redis, APCu), it's compatible with every Doctrine Cache adapter (Memcache, MongoDB, Riak, SQLite, etc.) and it also provides two special adapters (Proxy and Chain) for advanced setups.

For example, if your application uses Redis, the example shown above is still valid. You just need to change the instantiation of the cache adapter and leave the rest of the code unchanged:

1
2
3
4
use Symfony\Component\Cache\Adapter\RedisAdapter;

$cache = new RedisAdapter($redisConnection);
// ...

The documentation of the Cache component is already finished and it will be merged soon into the official Symfony docs.

Symfony Integration

The Cache component is ready to be used in any PHP application, but if you use the Symfony framework, the component is already integrated. Symfony defines two different cache pools: cache.app is where you store the information generated by your own application; cache.system is where Symfony components store their contents (e.g. the Serializer and Validator metadata).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// src/AppBundle/Controller/BlogController.php
class BlogController extends Controller
{
    public function indexAction()
    {
        $cachedCategories = $this->get('cache.app')->getItem('categories');
        if (!$cachedCategories->isHit()) {
            $categories = ... // fetch categories from the database
            $cachedCategories->set($categories);
            $this->get('cache.app')->save($cachedCategories);
        } else {
            $categories = $cachedCategories->get();
        }

        // ...
    }
}

If your server has APCu installed, the cache.system pool uses it. Otherwise, it falls back to the filesystem cache. For the cache.app pool is recommended to use a proper cache backend such as Redis:

1
2
3
4
5
# app/config/config_prod.yml
framework:
    cache:
        app: cache.adapter.redis
        default_redis_provider: "redis://localhost"

You can also create your own custom cache pools and they can even be based on the configuration of the default cache.app pool:

1
2
3
4
5
6
7
8
# app/config/config_prod.yml
framework:
    cache:
        # ...
        pools:
            app.cache.customer:
                adapter: cache.app
                default_lifetime: 600

Comments

There is a typo in the last sentence "cahe.app" (instead of "cache.app") :-)
@Michael nice catch! Fixed. Thank you.
I really appreciate easy Redis integration for cache pool. This might be great addition!
> cache.system is where Symfony components store their contents (e.g. the Serializer and Validator metadata).

This is not exactly accurate. Both system and app cache be used by external applications.

The system cache is the fastest one but isn't persistent, doesn't share the cache between servers (useful for metadata cache that can be rebuilt on every server) and is cleared when running `bin/console c:c`. For instance API Platform uses the system cache to store types of all properties exposed by the API.
Is there a major difference to the doctrineCache (https://symfony.com/doc/current/bundles/DoctrineCacheBundle/index.html)?
Seems quite similar to me...
@Christoph here's a diff:

* Symfony:
** PSR-6 implementation
** offers Doctrine cache adapter
** faster when getting many items
** will support tagging, as of Symfony 3.2

* Doctrine:
** faster when getting a single item
** supports versioning

For reference, see:

* https://speakerdeck.com/nicolasgrekas/psr-6-and-symfony-cache-de-la-perf-en-standard?slide=25
https://speakerdeck.com/nicolasgrekas/psr-6-and-symfony-cache-de-la-perf-en-standard?slide=26
* http://www.slideshare.net/andreromcke/symfony-meetup-psr6-symfony-31-cache-component#slide-9
Nice addition to Symfony stack. That's why I love using Symfony!
We finally have a well structured and generic built-in caching system in Symfony!

Just a little doubt about the second
`$numProducts = $cache->getItem('stats.num_products');`
Is it really mandatory? Or is it just more demonstrative?
As far as I know, the first one should be up-to-date after calling save().

Thanks for this great addition.
For me, It's one of the best additions in Symfony 3. Also, It's more friendly and intuitive to use than DoctrineCacheBundle.
This is a great addition, although there is still no documentation on how to configure this in Symfony (except for the very short snippets in this blog article) and how to add own cache adapters / pools with custom storage locations. Even a basic reference for the configuration and possible options / values would be great! Because right now you actually have to go through a lot of source code to find answers.
@Andreas I agree completely! We are on it and the docs will be added soon.
Good Addition! Even tag based cache in 3.2 makes it more agile and flexible. Thanks!!
app: cache.adapter.doctrine
default_doctrine_provider: ?

What do I enter as Provider

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.