Configuring the 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.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeAt your terminal, get a list of all the services in the container matching the word "markdown" by running:
php bin/console debug:container markdown
Ah, recognize markdown.parser.light
? That was what we used for our parser
key! Select "1" and hit enter to get more info. No surprise: its class name is Light
, which is the exact class that's being dump back in our browser, from our controller.
So, on a high level, by adding the parser config, we were basically telling the bundle that we want the "main" markdown parser service to be this one. In other words: when we autowire with MarkdownParserInterface
, please give us markdown.parser.light
.
Figuring out how to Configure the Cache
Anyways, one of our initial goals was to figure out how we could change the cache service to stop caching on the filesystem and instead cache somewhere else. In our controller, replace the dd()
with dump($cache)
:
// ... lines 1 - 11 | |
class QuestionController extends AbstractController | |
{ | |
// ... lines 14 - 31 | |
public function show($slug, MarkdownParserInterface $markdownParser, CacheInterface $cache) | |
{ | |
// ... lines 34 - 44 | |
dump($cache); | |
// ... lines 46 - 51 | |
} | |
} |
I'm using dump()
so that the page still renders - it'll make things easier.
Now, move over, refresh and... interesting. The cache object is an instance of TraceableAdapter
but inside it... ah, there's something called FilesystemAdapter
. So that kind of proves that the cache is being stored somewhere on the filesystem.
Ok, so how can we control that? In reality... you'll probably just Google that to find what config you need. But let's see if we can figure this out ourselves. But, hmm, we don't really know which bundle this service comes from.
Open up config/bundles.php
. When we started the project, the only bundle here was FrameworkBundle
- the core Symfony bundle:
// ... lines 1 - 2 | |
return [ | |
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], | |
// ... lines 5 - 12 | |
]; |
Every other bundle was installed by us. And... since I don't really see any "CacheBundle", it's a good guess that the cache service comes from FrameworkBundle
.
Let's test that theory! Find your terminal, pet your cat, and run:
php bin/console config:dump FrameworkBundle
Search this giant config for cache
... I'm looking to see if there is maybe a cache
section. Here it is! Under framework
, this bundle has a sub-key called cache
with quite a lot of example config. Because this is a bit hard to read, re-run this command with FrameworkBundle cache
.
php bin/console config:dump FrameworkBundle cache
This only shows the cache
section beneath framework
.
So... this give us some nice information: we can see a key called app
set to cache.adapter.filesystem
... that kind of looks like something we might want to tweak... but I'm not sure... and I don't know what I would change it to.
So this is helpful... but not that helpful.
The debug:config Command
Another way that you can look at bundle configuration is to pass the exact same arguments to another command called debug:config
:
php bin/console debug:config FrameworkBundle cache
The difference is subtle: config:dump
shows you examples of all possible config whereas debug:config
shows you your real, current values. Let's rerun this without the cache
argument to see all our FrameworkBundle
config:
php bin/console debug:config FrameworkBundle
Seeing our real values is cool... and we can see that under cache
, the app
key is set to cache.adapter.filesystem
. But... we still don't really know what config we should change... or what to change it to!
Changing the Cache Adapter to APCu
Let's go see if the config file for this bundle can help. Logically, because we're configuring the framework
key, open up config/packages/framework.yaml
:
framework: | |
secret: '%env(APP_SECRET)%' | |
#csrf_protection: true | |
#http_method_override: true | |
# Enables session support. Note that the session will ONLY be started if you read or write from it. | |
# Remove or comment this section to explicitly disable session support. | |
session: | |
handler_id: null | |
cookie_secure: auto | |
cookie_samesite: lax | |
#esi: true | |
#fragments: true | |
php_errors: | |
log: true |
Huh, I don't see a cache
key! And it's possible that there is no cache
key in our config and that the values we saw were the bundle's defaults. But actually, we do have some cache
config... it's just hiding in its own file: cache.yaml
. Inside, it has framework
then cache
:
framework: | |
cache: | |
# Unique name of your app: used to compute stable namespaces for cache keys. | |
#prefix_seed: your_vendor_name/app_name | |
# The "app" cache stores to the filesystem by default. | |
# The data in this cache should persist between deploys. | |
# Other options include: | |
# Redis | |
#app: cache.adapter.redis | |
#default_redis_provider: redis://localhost | |
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) | |
#app: cache.adapter.apcu | |
# Namespaced pools use the above "app" backend by default | |
#pools: | |
#my.dedicated.cache: null |
It's not very common for a bundle's config to be separated into two files like this, but it is totally legal. Remember: the names of these files are not important at all. The cache config was separated because it's complicated enough to have its own file.
Anyways, this file is full of useful comments: it tells us how we could use Redis for cache or how we could use APCu, which is a simple in-memory cache. Let's use that: uncomment the cache.adapter.apcu
line:
framework: | |
cache: | |
// ... lines 3 - 13 | |
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) | |
app: cache.adapter.apcu | |
// ... lines 16 - 20 |
Before we even try that, find your terminal and run the debug:config
command again:
php bin/console debug:config FrameworkBundle
Scroll up to the cache
section: yes! This sees our new config! But... what difference does that make in our app? Find your browser, refresh, then hover over the target icon on the web debug toolbar to see the dump. This time the adapter object inside is ApcuAdapter
! It's caching in memory! We made one little tweak and FrameworkBundle did all the heavy lifting to change the behavior of that service.
Oh, and if you get the error:
APCu is not enabled
It means you need to install the APCu extension. How you do that varies on each system but it's usually installed with pecl
- like:
pecl install apcu
After you install it, make sure to restart your web server. You can do that by running
symfony server:stop
And then re-run the command to start the server:
symfony server:start
If installing this is causing you problems, don't worry about it. For example purposes, you can use the key cache.adapter.array
instead. That's a service that actually does no caching, but it will allow you to see how the class changes.
Next, we've started to modify files in this config/packages/
directory. Now I want to talk more about the structure of this directory - specifically about Symfony environments, which will explain these dev/
, prod/
and test/
sub-folders.
sudo apt install php8.0-apcu
did it for me on Ubuntu 20.04In any case, I would say knowing how to set up your development environment is a reasonable prerequisite for these tutorials. But even if you can't figure out how to enable APCu support, as the tutorial says, you can use the noop Array cache for now and move on.