Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Adding a Cache Service

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

I've got a pretty important new challenge. We're going to be rendering a lot of markdown... and we don't want to do this on every request - it's just too slow. We really need a way to cache the parsed markdown.

Hmm, so caching is yet another tool that we need. If we had a service that was really good at caching a string and letting us fetch it out later, that would be perfect! Fortunately, Symfony comes with a bundle called DoctrineCacheBundle that can give us exactly this.

Enabling DoctrineCacheBundle

First, double-check that you have the bundle in your composer.json file:

65 lines composer.json
{
... lines 2 - 17
"require": {
... lines 19 - 22
"doctrine/doctrine-cache-bundle": "^1.2",
... lines 24 - 62
}
}

If for some reason you don't, use Composer to download it.

The bundle lives in the vendor/ directory, but it isn't enabled. Do that in the AppKernel class with new DoctrineCacheBundle():

... lines 1 - 5
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
... lines 11 - 19
new Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle(),
... lines 21 - 22
);
... lines 24 - 32
}
... lines 34 - 53
}

That added a use statement on top of the class... which is great - but I'll move it down to be consistent with everything else. Awesome!

Once you've enabled a bundle, there are usually two more steps: configure it, then use it. And of course, this has its own documentation that'll explain all of this. But guys, we're already getting really good at Symfony. I bet we can figure out how to use it entirely on our own.

1) Configure the Bundle

First, we need to configure the bundle. To see what keys it has, find the terminal and run:

./bin/console config:dump-reference

The list has a new entry: doctrine_cache. Re-run the command with this:

./bin/console config:dump-reference doctrine_cache

Nice! There's our huge configuration example! Ok, ok: I don't expect you to just look at this and instantly know how to use the bundle. You really should read its documentation. But before long, you really will be able to configure new bundles really quickly - and maybe without needing their docs.

Configuring a Cache Service

Now, remember the goal: to get a cache service we can use to avoid processing markdown on each request. When we added KnpMarkdownBundle, we magically had a new service. But with this bundle, we need to configure each service we want.

Open up config.yml and add doctrine_cache. Below that, add a providers key:

... lines 1 - 72
doctrine_cache:
providers:
... lines 75 - 77

Next, the config dump has a name key. This Prototype comment above that is a confusing term that means that we can call this name anything we want. Let's make it my_markdown_cache:

... lines 1 - 72
doctrine_cache:
providers:
my_markdown_cache:
... lines 76 - 77

You'll see how that's important in a second.

Finally, tell Doctrine what type of cache this is by setting type to file_system:

... lines 1 - 72
doctrine_cache:
providers:
my_markdown_cache:
type: file_system

This is just one of the built-in types this bundle offers: its docs would tell you the others.

And that's it! In the terminal run ./bin/console debug:container and search for markdown_cache:

./bin/console debug:container markdown_cache

Et voila! We have a new service called doctrine_cache.providers.my_markdown_cache. That's the whole point of this bundle: we describe a cache system we want, and it configures a service for that. Now we're dangerous.

Leave a comment!

16
Login or Register to join the conversation
Gianluca M. Avatar
Gianluca M. Avatar Gianluca M. | posted 4 years ago | edited

I put this in my services.yml:


    memcached.doctrine:
        class: Memcached
        factory:
            Symfony\Component\Cache\Adapter\MemcachedAdapter::createConnection
        arguments: ['%memcached.servers%', '%memcached.config%']

    doctrine.cache.memcached:
        class: Doctrine\Common\Cache\MemcachedCache
        calls:
            - [ setMemcached, [ '@memcached.doctrine' ] ]

and all It's ok but now How configure my config.yml in doctrine-cache?


doctrine_cache:
    aliases:
        cache_myidentify: myidentify_cache
    providers:

Thanks

Reply

Hey Gianluca,

I think your "doctrine_cache" configuration should be like:


doctrine_cache:
    aliases:
        memcached_cache: service_connection_memcached_provider
    providers:
        service_connection_memcached_provider:
            memcached:
                connection_id: "memcached.doctrine"

And then you should be able to use the short "memcached_cache" alias to get the memcached provider, instead of using long "doctrine_cache.providers.service_connection_memcached_provider":

$memcachedCache = $this->container->get('memcached_cache');

I hope this helps!

Cheers!

Reply
Igor Avatar

I see there is a lack of doc for using caching, can you provide some simple code example:

for the type:

1- array caching
2- memcache
3- memcached
4 - redis

with some explanation, it will help me a lot for understanding it deeper

Reply

Hey Igor,

Those are just different caching systems, own has its advantages on it depends on your project to choose one or another. You can find *a lot* of information on the internet about each one. For the difference between memcache and memcached you can check this answer: https://stackoverflow.com/a... . But "array" type is something interesting, it do nothing, just simulate some kind of caching. It's useful only on your local machine when developing or testing the project, you don't need to write some conditions to cache only on production, that means you can still call caching methods but nothing will be cached, i.e. you don't need to write custom conditions to cache things only in production mode.

Cheers!

Reply
Igor Avatar

Thanks for the quick reply

I tried to find good example for cache memcache and redis and didn't found in symfony project. maybe you can point me out
Can you assist me with this?

Reply

Hey Igor,

I don't have an example of memcache, but we do talk about Redis in our Ansible tutorials:
https://knpuniversity.com/s...
https://knpuniversity.com/s...

You can find some examples in course code. But with Memcache actually the same, you just need to specify another cache provider, i.e. Memcache provider instead of Redis one, but methods of Cache Component are the same of it, so you even don't need to tweak any line of code. And of course, you need to install Memcache in your system.

Cheers!

Reply
Default user avatar
Default user avatar Rodrigo Salto | posted 5 years ago

Symfony makes automatic caching with the hole pages, what if i want to disable it for an specific route?? is there any way to make that?

Reply

Hey Rodrigo,

Are you talking about Symfony HTTP cache here? Actually, Symfony do not make any automatic caching at all. All caching layers you have to add by yourself manually. So just do not add caching on specific route you won't to be cached and that's it. Or am I misunderstand you?

Cheers!

Reply
Default user avatar
Default user avatar Rodrigo Salto | Victor | posted 5 years ago

I dont really know where or what, i didnt set any cache at all, but in a production environment all my pages are working with cache, i did clear de cache and validate that the directory is empty, but after some random visits de cache directory has some new files and the content of my pages dosent have the latest information.

Reply

Hm, it's weird. Do you use shared hosting? Probably your hosting has some caching feature out-of-the-box, so you have to disable it first. Do you mean if you manually remove the "var/cache/prod/" on production - you still won't see the new updated (latest) HTML markup for example?

Cheers!

Reply
Default user avatar
Default user avatar Rodrigo Salto | Victor | posted 5 years ago

I am working with a shared hosting, they dont have any cache, if i delete all the files at "var/cache/prod" i see the new updated html, if after that i update the html and make a new visit to the same page with out clearing the cache i got the oldest one.

Reply

Hey Rodrigo,

Ah, that's on purpose - you have to clear the prod cache when you want to apply some changes in HTML layout. Actually, this way Symfony increase its performance what is important on production. So after each deploy, you have to clear the prod cache in console: "$ bin/console cache:clear -e prod" - if you have SSH access on your shared hosting, or just remove "var/cache/prod" directory manually - it should work as well. Symfony regenerate cache only for dev environment, which is very convenience for development - you don't have to clear the dev cache by itself. Btw, take a look at How to Deploy a Symfony Application in Symfony docs.

Cheers!

Reply
Default user avatar
Default user avatar Michael Stratford | posted 5 years ago

When you said "I bet we can figure out how to use this bundle on our own", I paused the video and went to the terminal to output the bundle reference and used config:dump-reference DoctrineCacheBundle, and it printed out the reference. Firstly, I love that I didn't have to search for the reference name and was able to use the bundle name instead as it saved a step. My question is -- is that by design? Can rely on bundle names to get me a proper reference dump?

Reply

Hey Michael!

Yes, you can rely on the bundle names like this! Internally, when you pass DoctrineCacheBundle, Symfony looks for a Configuration file in that bundle, which provides the config information. And if you pass the config key instead - doctrine_cache - Symfony determines which bundle that config key is attached to (DoctrineCacheBundle) and then performs the same lookup for the Configuration file. So yes, passing the bundle name always works.

Btw, if you're curious, here is the file Symfony looks for to load the configuration tree: https://github.com/doctrine/DoctrineCacheBundle/blob/master/DependencyInjection/Configuration.php

Cheers!

2 Reply
Default user avatar
Default user avatar Nan Zhao | posted 5 years ago

How to do this in symfony 3.4.5? In the lastest version of symfony3, the config.yml is not generated by default. I tried to load the file "doctrine_cache.yaml", but failed. When I type 'php ./bin/console dubug:container markdown_cache', the command line says 'In ContainerDebugCommand.php line 211: No services found that match "markdown_cache". Can you help me ?

Reply

Hey Nan,

You probably means how to do it in Symfony Flex. Looks like this bundle somehow does not a Symfony recipe. I also wonder why, so I opened an issue: https://github.com/doctrine/DoctrineCacheBundle/issues/131 . It's not a big deal, you can install this bundle with Composer and then manually create a config file for it in "config/packages/doctrine_cache.yaml" where paste related configuration, i.e.:


# config/packages/doctrine_cache.yaml
doctrine_cache:
    providers:
        my_markdown_cache:
            type: file_system
            # ...

If you have other problems - let me know.

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.4" // 1.4.2
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0" // v3.1.3
    }
}
userVoice