Parameters
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 SubscribeWe know there's this container concept that holds all of our services... and we can see the full list of services by running:
php bin/console debug:container
Listing Parameters
Well, it turns out that the container holds one other thing: grudges. Seriously, don't expect to pull a prank on the service container and get away with it.
Ok, what it really holds, in addition to services, is parameters. These are simple configuration values, and we can see them by running a similar command:
php bin/console debug:container --parameters
These are basically variables that you can read and reference in your code. We don't need to worry about most of these, actually. They're set by internal things and used by internal things. But there are a few that start with kernel that are pretty interesting, like kernel.project_dir, which points to the directory of our project. Yep! If you ever need a way to refer to the directory of your app, this parameter can help.
Fetching Parameters from a Controller
So... how do we use these parameters? There are two ways. First, it's not super common, but you can fetch a parameter in your controller. For example, in VinylController, let's dd($this->getParameter()) - which is a shortcut method from AbstractController - and then kernel.project_dir. We even get some nice auto-completion thanks to the Symfony PhpStorm plugin!
| // ... lines 1 - 10 | |
| class VinylController extends AbstractController | |
| { | |
| // ... lines 13 - 31 | |
| public function browse(MixRepository $mixRepository, string $slug = null): Response | |
| { | |
| dd($this->getParameter('kernel.project_dir')); | |
| // ... lines 35 - 42 | |
| } | |
| } |
And when we try it... yep! There it is!
Referencing Parameters with %parameter%
Now... delete that. This works, but most of the time, the way you'll use parameters is by referencing them in your configuration files. And we've seen this before! Open up config/packages/twig.yaml:
| twig: | |
| default_path: '%kernel.project_dir%/templates' | |
| // ... lines 3 - 7 |
Remember that default_path? That's referencing the kernel.project_dir parameter. When you're in any of these .yaml configuration files and you want to reference a parameter, you can use this special syntax: %, the name of the parameter, then another %.
Creating a new Parameter
Open up cache.yaml. We're setting cache.adapter to filesystem for all environments. Then, we're overriding it to be the array adapter in the dev environment only. Let's see if we can shorten this by creating a new parameter.
How do we create parameters? In any of these files, add a root key called parameters. Below that, you can just... invent a name. I'll call it cache_adapter, and set that to our value: cache.adapter.filesystem:
| parameters: | |
| cache_adapter: 'cache.adapter.filesystem' | |
| // ... lines 3 - 28 |
If you have a root framework key, Symfony will pass all of the config to FrameworkBundle. The same is true with the twig key and TwigBundle.
But parameters is special: anything under this will create a parameter.
So yea... we now have a new cache.adapter parameter... that we're not actually using yet. But we can already see it! Run:
php bin/console debug:container --parameters
Near the top... there it is - cache_adapter! To use this, down here for app, say %cache_adapter%:
| parameters: | |
| cache_adapter: 'cache.adapter.filesystem' | |
| // ... line 3 | |
| framework: | |
| cache: | |
| // ... lines 6 - 13 | |
| app: '%cache_adapter%' | |
| // ... lines 15 - 28 |
That's it. Quick note: You may have noticed that sometimes I use quotes in YAML and sometimes I don't. Mostly, in YAML, you don't need to use quotes... but you always can. And if you're ever not sure if they're needed or not, better to be safe and use them.
Parameters are actually one example where quotes are required. If we didn't surround this with quotes, it would look like a special YAML syntax and throw an error.
Anyway, in the dev environment, instead of saying framework, cache, and app, all we need to do is override that parameter. I'll say parameters, then cache_adapter... and set it to cache.adapter.array:
| parameters: | |
| cache_adapter: 'cache.adapter.filesystem' | |
| // ... line 3 | |
| framework: | |
| cache: | |
| // ... lines 6 - 13 | |
| app: '%cache_adapter%' | |
| // ... lines 15 - 23 | |
| when@dev: | |
| parameters: | |
| cache_adapter: 'cache.adapter.array' |
To see if that's working, spin over here and run another helper command:
php bin/console debug:config framework cache
Remember, debug:config will show you what your current configuration is under the framework key, and then the cache sub-key. And you can see here that app is set to cache.adapter.array - the resolved value for the parameter.
Let's check the value in the prod environment... just to make sure it's right there too. When you run any bin/console command, that command will execute in the same environment your app is running in. So when we ran debug:config, that ran in the dev environment.
To run the command in the prod environment, we could go over here and change APP_ENV to prod temporarily... but there's an easier way. You can override the environment when running any command by adding a flag at the end. For example:
php bin/console debug:config framework cache --env=prod
But before we try that, we always need to clear our cache first to see changes in the prod environment. Do that by running:
php bin/console cache:clear --env=prod
Now try:
php bin/console debug:config framework cache --env=prod
And... beautiful! It shows cache.adapter.filesystem. So, the container also holds parameters. This isn't a super important concept in Symfony, so, as long as you understand how they work, you're good.
Ok, let's turn back to dependency injection. We know that we can autowire services into the constructor of a service or into controller methods. But what if we need to pass something that's not autowireable? Like, what if we wanted to pass one of these parameters to a service? Let's find out how that works next.
8 Comments
Previously, we saw that yaml configurations in a file are parsed in the order the declared.
Regarding parameters, this seems like an exception to this.
Regarding cache, when framework.cache.app is parsed, you would expect it to contain the previously declared cache_adapter parameter, which is not environment aware, and then when it is overridden in when@dev, that this would have no effect, because cache.app is already declared.
Isn't this a bit confusing?
Hey Alkiviadis,
Not sure I completely understand you here, but you're probably overthinking about it. First of all, in the dev env when we're changing a config file - the cache will be automatically recompiled so any new changes you made in the config will be re-parsed on the next request. In prod Symfony mode it's a bit different, when you change a config file - you will need to clear the cache manually to let the system notice your changes. So, in both cases the cache will be re-compiled and so the new parameter values will be used.
I hope this helps.
Cheers!
Thank you for your answer, but I am actually talking about the order the configurations are read, not when and if the cache is cleared.
Specifically while on (
cache.yaml) we had in the middle of course:even when we are at dev environment, framework.cache.app already got assigned a value from the first cache_adapter declaration, before the cache_adapter parameter got reassigned with new value later. But the framework.cache.app got the final value of cache_adapter, which seemed strange to me at first.
So, are all parameters parsed/set first, and then anything else?
Hey Alkiviadis,
It's important do understand that Symfony first gathers all the configuration from separate config files and only then trying to resolve parameter values. Actually, the parameter values will be resolved even later only when you fetch the service from the service container - the container will instantiate the service object and resolve all the parameter values it has.
Yeah, it probably might be confusing at first sight, but that's just an overwritten operation. Yes, when the config file is parsed - the
framework.cache.appwill be set to the%cache_adapter%(but it's just instructions, it's still not resolved actual value yet). And later if you're in adevmode, thewhen@devwill be parsed as well which will overwrite the values that were already set before (if any).If it's confusing you - you can avoid
when@devsyntax and put the dev config inside theconfig/packages/devfolder, but behind the scene it will work the same anyway: it first will gather all the default config (for all environments), and only then overwrite any whiles with env-specific config.So, even though it's an overwriting operation in some cases - that's actually really powerful and flexible: you have the default config values but can overwrite some values with other ones for specific enviroments.
I hope this clarifies things!
Cheers!
Coming from Laravel, I'm a bit confused where I can put general config for my app. In Laravel I could just create a
MyApp.phpfile in theconfigfolder and then read it from wherever. So say I have some project-wide config in my Symfony app, where should I put it? I tried creating aapp.yamlfile inconfig/packagesbut when I rundebug:config appit says "No extensions with configuration available for "app"".Hey Jim,
Yeah, that
config/packages/folder is special and contains bundle-specific configs :) Try to put your config in justconfig/dir, it should work well this way :)Cheers!
Thanks for the reply Victor. Unfortunately I still get the same error, also after clearing the cache. So in the
configdirectory I have put a fileapp.yaml, which looks a bit like this:Then when I run
debug:config appI get the error described above. And when, in a console command, I haveI get the error "You have requested a non-existent parameter "app.foo"".
Hey Jim-B,
Wait, if you drop that
app.yamlfile from theconfig/packages/and put intoconfig/- you should not have thatNo extensions with configuration available for "app"error anymore, as nobody will parse your file at all. And this means you would need to parse that file yourself.But in your second example I see you just want to add some data to the config so that system knows about your data. If so, you need to add "parameters" - that's how it's called in Symfony. For this, you can open
config/services.yamland underparameters:key add your data. Then you will be able to fetch those parameters with the code you showed in the end :)Cheers!
"Houston: no signs of life"
Start the conversation!