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

Config 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.

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

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

Login Subscribe

The container is a fancy, scary word for a simple concept: the object that holds all of the services in our app. But actually, the container can also hold a second type of thing: normal boring config values! These are called parameters and, it turns out they're pretty handy!

Open config/packages/framework.yaml. We configured the cache system to use this cache.adapter.apcu service:

framework:
... lines 2 - 16
cache:
... lines 18 - 28
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
app: cache.adapter.apcu

And then, in the dev environment only, we're overriding that to use cache.adapter.filesystem:

framework:
cache:
app: cache.adapter.filesystem

Creating a Parameter

Simple enough! But parameters can make this even easier. Check this out: inside any configuration file - because, remember, all of these files are loaded by the same system - you can add a parameters key. And below that, you can invent whatever keys you want.

Let's invent one called cache_adapter. Set its value to cache.adapter.apcu:

parameters:
cache_adapter: cache.adapter.apcu
... lines 3 - 34

Using a Parameter

This basically creates a variable. And now we can reference this variable in any of these configuration files. How? Remove cache.adapter.apcu and, inside quotes, replace it with %cache_adapter%:

parameters:
cache_adapter: cache.adapter.apcu
framework:
... lines 5 - 19
cache:
... lines 21 - 31
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
app: '%cache_adapter%'

Yep, whenever you surround a string with percent signs, Symfony will replace this with that parameter's value.

Overriding a Parameter

So yea... parameters are basically config variables. And, what programmer doesn't like variables!?

The cool thing is, now that we have a parameter called cache_adapter, inside of the dev config, we can shorten things. Change the key to parameters and override cache_adapter: cache.adapter.filesystem:

parameters:
cache_adapter: 'cache.adapter.filesystem'

Oh, and you may have noticed that sometimes I use quotes in YAML and sometimes I don't. Yay consistency! YAML is super friendly... and so most of the time, quotes aren't needed. But sometimes, like when a value starts with % or contains @, you do need them. Sheesh! Don't worry too much: if you're not sure, use quotes. You'll get a clear error anyways when you do need them.

Ok, let's see if this works! Open MarkdownHelper and dump($this->cache):

... lines 1 - 8
class MarkdownHelper
{
... lines 11 - 21
public function parse(string $source): string
{
... lines 24 - 27
dump($this->cache);die;
... lines 29 - 35
}
}

In your browser, wave hello to this astronaut. Then, refresh! Yes! It is still using the filesystem adapter, since we're in the dev environment.

Moving Parameters to services.yaml

Now that we know that any config file can define parameters... let's stop putting them everywhere! I mean, usually, for organization, we like to only define parameters in one-ish files: services.yaml. Let's remove the parameter from the main framework.yaml and add it there:

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
cache_adapter: cache.adapter.apcu
... lines 5 - 33

But... we have a problem. When you refresh now, woh! We're suddenly using the APCU adapter, even though we're in the dev environment! Whaaaat?

Remember the order that these files are loaded: files in config/packages are loaded first, then anything in config/packages/dev, and last, services.yaml. That means that the config in services.yaml is overriding our dev config file!

Boo! How can we fix that? Create a new config file called services_dev.yaml. This is the built-in way to create an environment-specific services file. And you can see that we actually started with one for the test environment. Inside, copy the code from the dev framework.yaml and paste it here:

parameters:
cache_adapter: 'cache.adapter.filesystem'

Oh, and delete the old framework.yaml file. Now, refresh!

Woo! It works!

And that's really it! In framework.yaml, we just reference the parameter...

framework:
... lines 2 - 16
cache:
... lines 18 - 28
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
app: '%cache_adapter%'

Which can be set in any other file. Like in this case: we set it in services.yaml and override it in services_dev.yaml:

... lines 1 - 2
parameters:
cache_adapter: cache.adapter.apcu
... lines 5 - 33

parameters:
cache_adapter: 'cache.adapter.filesystem'

Actually, if you think about it, since framework.yaml is loaded first, the parameter isn't even defined at this point. But that's ok: you can reference a parameter, even if it's not set until later. Nice!

Using a Parameter in a Service

But wait, there's more! We can also use parameters inside our code - like in MarkdownParser. Suppose that we want to completely disable caching when we're in the dev environment.

How can we do that? Add a new argument called $isDebug:

... lines 1 - 8
class MarkdownHelper
{
... lines 11 - 15
public function __construct(AdapterInterface $cache, MarkdownInterface $markdown, LoggerInterface $markdownLogger, bool $isDebug)
{
... lines 18 - 21
}
... lines 23 - 42
}

Yep, in addition to other services, if your service has any config - like isDebug or an API key - those should also be passed as constructor arguments.

The idea is that we will configure Symfony to pass true or false based on our environment. I'll press Alt+Enter and select "Initialize fields" so that PhpStorm creates and sets that property for me:

... lines 1 - 8
class MarkdownHelper
{
... lines 11 - 13
private $isDebug;
public function __construct(AdapterInterface $cache, MarkdownInterface $markdown, LoggerInterface $markdownLogger, bool $isDebug)
{
... lines 18 - 20
$this->isDebug = $isDebug;
}
... lines 23 - 42
}

Below, we can say: if $this->isDebug, then just return the uncached value:

... lines 1 - 8
class MarkdownHelper
{
... lines 11 - 13
private $isDebug;
public function __construct(AdapterInterface $cache, MarkdownInterface $markdown, LoggerInterface $markdownLogger, bool $isDebug)
{
... lines 18 - 20
$this->isDebug = $isDebug;
}
public function parse(string $source): string
{
... lines 26 - 29
// skip caching entirely in debug
if ($this->isDebug) {
return $this->markdown->transform($source);
}
... lines 34 - 41
}
}

Notice: this is the first time that we've had a constructor argument that is not a service. This is important: Symfony will not be able to autowire this value. Sure, we gave it a bool type-hint, but that's not enough for Symfony to guess what we want. Oh, and reverse my logic - I had it backwards!

... lines 1 - 8
class MarkdownHelper
{
... lines 11 - 23
public function parse(string $source): string
{
... lines 26 - 30
if ($this->isDebug) {
... line 32
}
... lines 34 - 41
}
}

To see that the argument cannot be autowired, refresh! Yep! A clear message:

Cannot autowire service MarkdownHelper: argument $isDebug must have a type-hint or be given a value explicitly.

This is the other main situation when autowiring does not work. But... just like before, it's no problem! If Symfony can't figure out what value to pass to an argument, just tell it! In services.yaml, we could configure the argument for just this one service. But that's no fun! Add another global bind instead: $isDebug and just hardcode it to true for now:

... lines 1 - 5
services:
# default configuration for services in *this* file
_defaults:
... lines 9 - 14
# setup special, global autowiring rules
bind:
... line 17
$isDebug: true
... lines 19 - 34

Ok, move over and... refresh! Yea! It works! And if you check out the caching section of the profiler... yes! No calls!

Built-in kernel.* Parameters

To set the $isDebug argument to the correct value, we could create a parameter, set it to false in services.yaml, override it in services_dev.yaml, and use it under bind.

But don't do it! Symfony already has a parameter we can use! In your terminal, the debug:container command normally lists services. But if you pass --parameters, well, you can guess what it prints:

php bin/console debug:container --parameters

Just like with services, most of these are internal values you don't care about. But, there are several that are useful: they start with kernel., like kernel.debug. That parameter is true most of the time, but is false in the prod environment.

Oh, and kernel.project_dir is also really handy. Copy kernel.debug, move back to services.yaml, and use %kernel.debug%:

... lines 1 - 5
services:
# default configuration for services in *this* file
_defaults:
... lines 9 - 14
# setup special, global autowiring rules
bind:
... line 17
$isDebug: '%kernel.debug%'
... lines 19 - 34

Try it! Refresh! It still works!

Ok, it's time to talk a little bit more about controllers. It turns out, they're services too!

Leave a comment!

33
Login or Register to join the conversation
Default user avatar
Default user avatar Yahya A. Erturan | posted 5 years ago

`bind` is a killing-feature, thank you.

Meanwhile, are you planning to make a course for MultiLingual usage of Symfony and Doctrine. (not just talking about translations :)) It'd be lovely.

Thanks for great work.

1 Reply

Hey Yahya A. Erturan!

Yea, I love bind :). We ARE planning a tutorial about everything translations... but I would love to know what you're looking for the in that tutorial, so we can make sure we cover it - it's currently in the planning stages, so the timing is perfect.

Cheers!

1 Reply
Default user avatar
Default user avatar Yahya A. Erturan | weaverryan | posted 5 years ago

I am thrilled that you are planning it already :) I am looking for a real life examples:

* redirect based on browser language or saving preferred language to a cookie. (For homepage of course)
* Slugs for each language. I think (but IMHO) hiding default language in url and displaying it in other languages is a good practice.
* to handle `article_meta` and `article_lang` tables (there is a bundle for that but I am eager to learn how it really works),
* to switch between languages,
* different language streams for frontend and backend,
* building sitemaps for each language
* etc.,

Sorry you hava asked :)

1 Reply

Hey Yahya,

Thanks for these topics! Well, most of them well be covered for sure. And I think I will reconsider others and try to include them too. Meanwhile, I'm not sure that I completely understand a few of them:
> to handle `article_meta` and `article_lang` tables (there is a bundle for that but I am eager to learn how it really works),
Just to be clear, what bundle are you talking about here?

> different language streams for frontend and backend
Can you explain a bit what "language streams" do you mean? For example, is it something like setting FR lang for admin panel but EN for the client's part? Because, I have never thought about it. Do you have a good use case where it may be really useful?

Cheers!

Reply
Default user avatar
Default user avatar Yahya A. Erturan | Victor | posted 5 years ago

I'd be really happy to see such a tutorial :)

> to handle `article_meta` and `article_lang` tables....
KnpLabs/DoctrineBehaviors, A2Lix TranslationBundle as I saw in a tutorial after digging in Google :)

> different language streams for frontend and backend
For example, website's default language is English. Other available languages are German and French. As we are mostly working for international companies, in Admin panel (which is in English), our client is entering products in English. And asking their branch in France to enter details in French via Admin panel (which is still in English). We are handling it in our current system (which is highly modified version of CI 3 - and getting resemble to Symfony more day by day (thanks to your tutorials)) but at one point (after mastering in Doctrine and MultiLingual issues) we want to switch Symfony fully :)

Reply

Hey Yahya,

About the last, so after you filled in the EN information to your products, you're just looking for a way to fill in the same information but in FR and DE languages at the same time not switching language of the admin panel, right? So probably yeah, A2LixTranslationBundle I something you need, or I think it's also possible to implement manually with KnpLabsDoctrineBehaviors. Anyway, thanks for explanation! We'll consider these topics as well.

Cheers!

Reply
Default user avatar
Default user avatar Yahya A. Erturan | Victor | posted 5 years ago

Admin Panel should have languages too :) So we have three language stream - 1: Main Data Stream (Adding pages to database via admin panel in several (if enabled) languages.) - 2: Frontend Stream (Displaying the records for selected languages in frontend) - 3: Backend Stream (Languages of Admin Panel - New Page / Nouvelle Page / Nuova Pagina / новая страница) - I have started to afraid of maybe it is too much real world for a tutorial :)

Reply

Hey Yahya,

Thanks for more detailed explanation! Haha, maybe too much. Well, I see the value to use one lang for admin panel but ability to fill in content into the DB in different langs, i.e. not changing language of admin panel each time you need to fill in content in a new lang. But what about separating langs for admin/fronted - I don't think it's worth it. If you use a lang on frontend - I think you'd 99% want to use the same lang in admin panel :)

Anyway, thanks for your ideas!

Cheers!

Reply
Simon L. Avatar
Simon L. Avatar Simon L. | posted 2 years ago

Hi there !

I am trying to set external parameters and I am trying to follow these instructions:
https://symfony.com/doc/3.2...

But I can't figure out what code must be written in the file which include_once refers to (in the above example /path/to/drupal/sites/default/settings.php).

Should I use a service to fetch the parameter and then pass it to parameters.php?

Do you have any concrete example to give me?

Sorry maybe my question sounds stupid for some of you, I am totally beginner with Symfony...

Reply
Simon L. Avatar

Just to be more specific: I would like to inject variables from the database into the config

Reply

Hey Simon L.

Just to be clear. You want to execute a query from a database to gather some parameters and then inject them into Symfony's container? If that's the case, you will have to code a script to do that query and use the service container as shown in the link you sent, and then, import that file


# app/config/config.yml
imports:
    - { resource: path/to/your_parameters.php }

Cheers!

Reply
Ricardo M. Avatar
Ricardo M. Avatar Ricardo M. | posted 3 years ago

Just would like to add a question I had and the answer I found..

How to retrieve parameters values out there wether inside our controllers or our classes?
In Symfony 4 it's done using ParameterBagInterface. So we just add it there in the depencencies of the class.

Detailed explanation can be found here: https://stackoverflow.com/a...

Reply

Hey Ricardo M.

Thanks for sharing it! However it's not a good practice to pass whole ParameterBag inside your service, probably just in few cases when you really need a big amount of parameters. If not it's better to use autowiring. BTW it's also described in link you provided.

Cheers!

Reply
Ricardo M. Avatar

Hi Vladimir. Thanks for the reply.
You meant using `bind`, right? If so, I thought it was a little bit weird, specifying the value of every constructor variable with that name in the yaml file. I mean, it makes me creating weird variable names just to match those from config.
I was also wondering that Symfony would try to match them in every single constructor it loads, and that would be even slower.
Did I get this wrong?

Thanks for your attention one more time.

Reply

I'd like to say it depends. For example if you need one parameter in many services you can use bind, but if you need a lot of different parameters in many services you can always mix autowiring with service definition for example:


services:
    #...

    App\Service\UploadHelper:
        arguments:
            $uploadPath: '%my_cool_upload_path_var%'

BTW there is a great course on Symfony 5 track: https://symfonycasts.com/screencast/symfony-fundamentals it has an awesome description of how autowiring working and how you can configure whatever you need ;)

Cheers!

Reply
Ricardo M. Avatar

Amazing, Vladimir.

Thank you a lot for this explanation. I learned about the autowiring in the course I'm taking, but didn't linked to what you said. Now it make sense.
Btw, I am currently using symfony 4.8 (LTS).

PS: I would love to take symfonycasts, but the price in USD currency broke my heart.

Reply

Hey Ricardo M.

We're sorry if it's expensive for you. We just think that it's a fair price for our job on them - we make them short but rich on information, and also give some jokes and nice animations to make learning not so boring.

But we do want to make it accessible to everyone, that's why we have some tutorials are completely free, and first few chapters of EVERY tutorial are literally free as well so you can try the course before buying. Also, the exact what we're saying in videos are described below each video in scripts, and it contains dynamic code blocks that you can expand. So you literally may code along with us for free.

Also, it depends on your learning strategy, but if our subscription prices are high for you - you can consider buying individual tutorials. Usually, they cost only about 12 USD. For example, this course you're currently on (Symfony 4 Fundamentals: Services, Config & Environments) costs only $10: https://symfonycasts.com/pr... - notice "No thanks, I just want to buy" below. But usually, with the monthly subscription you may learn more than 2 tutorials during the month, and so it might have more benefit for you. But it's up to you what to choose!

Cheers! Hope you enjoy learning!

Reply
Ricardo M. Avatar

Hi Vladimir. Please, don't get me wrong. It's not expensive. At least for those who lives there. :)
I'm an instructor myself. I try to price my courses comparing it to lunch prices in the regions of those who are buying it. Your subscription costs a lunch price in America, which is cheap. But costs 5 or 6 lunches in Brazil due to currency conversion. :)

And finally, the last option you gave me is the best one. I didn't see that at all. :)
I'm going to buy it for sure. :)
Thank you for your reply and support.

Reply

Hey Ricardo,
We are happy that you like our courses and especially found useful that small option :)

BTW we want to consider competitive pricing for different countries in the future. It's a really good idea, but we don't know exactly when it will be implemented, so no estimations yet (:

Cheers and stay safe!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | posted 3 years ago | edited

Hello Symfonycast,

So I want to write configuration parameters for my Command class (this way I do not have to enter every time I run command)

I created in project/config/commands.yaml this file


parameters:
    import_community.names: ["killarney", "bridlewood"]

commands:
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: false       # Allows optimizing the container by removing unused services; this also means

    App\Command\ImportDataCommand:
        arguments:
            $communityNames: '%import_community.names%'

And I make use of it in project/src/Command/ImportDataCommand.php like this:


class ImportDataCommand extends Command
{
    private $communityNames;

    public function __construct($communityNames)
        {
            $this->communityNames = $communityNames;
            parent::__construct();
        }

    protected function execute(InputInterface $input, OutputInterface $output): int
        {
           $communities = $this->communityNames;
        }
}

But when I run command, I got error like this:

<blockquote>
C:\xampp\htdocs\project>php bin/console import:data

In DefinitionErrorExceptionPass.php line 54:

Cannot autowire service "App\Command\ImportDataCommand": argument "$communityNames" of method "__construct()" has no type-hint, you should configure its value explicitly.
</blockquote>

So can you see what I have done wrong or is it even a possible thing to do?

Thanks in advance!

Dung.

Reply

Hey Dung L. !

Hmm. This is a good question - because your config looks good to me! You are specifying the argument by name in commands.yaml, and so I would expect that it should be passed correctly to the service and not have this error. So, the problem is probably subtle - and I think I might see it. A few things:

A) In commands.yaml, you wrote commands:. That is actually services:, correct? I think you probably have this correct in your code but had a typo in the comment.

B) Why did you create a commands.yml file instead of putting this in service.yaml? Here is what I think is happening:

1) Symfony first loads commands.yaml (because it is before services.yml alphabetically). This registers the command service with the argument.
2) Symfony *then* loads services.yaml. This file usually contains code to auto-register all classes in src/ as services. This means that it re-registers the command as a service, which *overrides* the original definition in commands.yaml. Suddenly the ImportDataCommand service is registered with *no* arguments.

Let me know if this is the issue! I don't see a lot of point in separating things into multiple files like this. But if you do want to, I would "exclude" the Command directory from the auto-registration in services.yaml and then add code to commands.yaml to auto-register src/Command. THEN, put your custom arguments code after that (so that your service is first auto-registered in commands.yaml, and THEN you override with your custom configuration).

Cheers!

Reply
Dung L. Avatar

Hi Ryan,

- Does Symfony always loads [config-files].yaml first and auto-register all classes in src/ as services before it will do anything? I asked this because when I mimic this issue today, and I tried to run command "php bin/console cache:clear" and I get the same error above:

Cannot autowire service "App\Command\ImportDataCommand": argument "$communityNames" of method "__construct()" has no type-hint, you should configure its value explicitly.

- php bin/console cache:clear command will not work until after I resolved this error.

I think my observation is correct, and all classes are essentially services in Symfony?

Thanks!

Dung.

Reply

Hey Dung L.!

Does Symfony always loads [config-files].yaml first and auto-register all classes in src/ as services before it will do anything?

Let me make sure I understand your question by giving you a full, long answer. Please tell me if I'm not understanding ;).

Yes, Symfony loads ALL the .yaml files (and auto-registers the classes in src/, because some code in services.yaml tells it to do that) in order to "build the container". This "build the container" process (sometimes called compilation) happens before Symfony starts handling a request and also before Symfony runs any console commands. So yes, ALL of the .yaml files are parsed, processeed, validated, etc before Symfony will do ANYTHING. This is actually a kill feature: it's not possible to have a typo on a service or be missing a command on a service and not realize it. In your example, if Symfony DID allow your code to continue, then you might not notice (until you tried to run that specific command) that the ImportDataCommand was broken. With the "compilation" step, nothing will work until everything is perfect.

I think my observation is correct, and all classes are essentially services in Symfony?

You're close to being correct. A more accurate way to say it is this:

All classes in "src/" are eligible to be used as a service

The code in services.yaml that auto-registers everything in src/ indeed does register everything in src/ (except for excluded directories) as a service. But, during the compilation phase, if a class in src/ is never used as a service (e.g. it's not autowired into a controller or passed as an argument to some other service), then it is removed from the container. It's a weird dance that produces a perfect result.

For example, suppose you have a src/Model/CouponCode class. This is not a service, it's just some "model" class that you have decided to use - probably in some controller - like may be $code = new CouponCode('abc123') - and then you pass it into a template (I'm just making up this example). In this situation, this CouponCode class is NOT a service - it's a model class. In fact, if its first constructor argument is required (the "abc123" coupon code), then if Symfony things it's a service, it would FAIL autowiring and throw an error.

Here's how this works inside Symfony during the compliation process:

a) Symfony registers everything in src/ a service, including CouponCode
b) It tries to autowire the "coupon code" constructor argument and fails. But it does not throw an exception, it "stores" this exception for later.
c) Near the end of the process, it notices that CouponCode was never used as a service - we never autowired it anywhere, for example. And so, Symfony removes it from the container. Because it removed it, the "autowiring error" is not thrown.

I hope that makes sense! The CouponCode is sort of "eligible" to be used as a service. But because you intend for it to be a model class, you never "use it" like a service - i.e. you never try to autowire it. And so, Symfony is smart enough to eventually make sure that it is NOT a service in the container.

Phew! Let me know if this helps!

Cheers!

Reply
Dung L. Avatar

Very good answer, I understand, its very clever behind the scene. Is this "eligible" but not registered as service for performance reason?

Reply

Hey Dung L.!

Excellent :).

> Is this "eligible" but not registered as service for performance reason?

The fact that Symfony "removes" any "unused" services from the container IS for performance, yes :). But in this situation, it's helpful for one other reason: if Symfony tries (and fails) to autowire a non-service class, when the service is later removed from the container, Symfony knows not to throw that "autowiring failed exception".

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | weaverryan | posted 3 years ago | edited

Hi weaverryan Thank you so much for your reply. You cleared it all for me and it works now. I misunderstood the material/course, I thought src/Command/* is not service just because it is a different directory than src/Service, I thought services must be under src/Service directory. Hence I created commands.yaml for it which results in the error.

So of course there was no point creating new .yaml config file :). Copying the same parameters and arguments from the mistaken commands.yaml to services.yaml bam it works ha ha. Now I know src/Command is also a service ( I should have known this because I learnt it some where on SymfonyCasts ). But thank you for your detail explanation I learnt even more with mistake/errors.

Cheers!

Reply

Woo! This sounds like a "win" all around - happy everything is making sense now! :)

1 Reply
Dung L. Avatar
Dung L. Avatar Dung L. | posted 3 years ago

Good Morning,

Sorry that I do not thing I understand Config Parameters topic. I simply want to write a config parameter in /config/services.yaml like this:

parameters:
cache_adapter: cache.adapter.apcu
locale: 'en'
import_json_data_linux: '/var/www/finish/public/data/'
import_json_data_windows: 'C:\\xampp\\htdocs\\finish\\public\\data\\'

and use it in my service class src/Service/dataImport.php

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$path = "%import_json_data_windows%";
} else {
$path = "%import_json_data_linux%";
}

$content = file_get_contents($path . $filename);

but the $path variable does not get any value as expect instead it was an error. I hope you can help me?

error looks like this:

In JsonImport.php line 60:

Warning: file_get_contents(%import_json_data_windows%myfile.json): failed to open stream: No such file or directory

Thank you for your support!

Dung.

Reply

Hey Dung L.

You have to inject all the parameters you need into your service class.


// config/services.yaml
parameters:
    path_data_linux: "..."
    path_data_windows: "..."
services:
    App\Some\Service:
        arguments:
            $pathLinux: '%path_data_linux%'  # The argument name must match to the class constructor
            $pathWindows: '%path_data_windows%'

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | MolloKhan | posted 3 years ago | edited

I got it working :) Symfony is addictive for programmer, it gets better with time, its cleaner and more powerful!
Thank you MolloKhan as usual.

Reply
Simón B. Avatar
Simón B. Avatar Simón B. | posted 3 years ago

Yeahhh it works !!! Awesome tutorial

Reply
Ayman A. Avatar
Ayman A. Avatar Ayman A. | posted 4 years ago

HELP!
At the end of this tutorial, when I set APP_ENV=prod in my .env file ( to test the cache_adapter parameter), I get the following error when I refresh: "Something is broken. Please let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused."

And my prod.log file has the following:

[2018-09-20 21:12:51] request.INFO: Matched route "article_show". {"route":"article_show","route_parameters":{"_route":"article_show","_controller":"App\\Controller\\ArticleController::show","slug":"why-asteroids-taste-like-bacons"},"request_uri":"http://127.0.0.1:8000/news/why-asteroids-taste-like-bacons","method":"GET"} []
[2018-09-20 21:12:51] request.CRITICAL: Uncaught PHP Exception RuntimeException: "Controller "App\Controller\ArticleController::show()" requires that you provide a value for the "$helper" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one." at /opt/lampp/htdocs/symfony/the_spacebar/vendor/symfony/http-kernel/Controller/ArgumentResolver.php line 78 {"exception":"[object] (RuntimeException(code: 0): Controller \"App\\Controller\\ArticleController::show()\" requires that you provide a value for the \"$helper\" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one. at /opt/lampp/htdocs/symfony/the_spacebar/vendor/symfony/http-kernel/Controller/ArgumentResolver.php:78)"} []

What have I done wrong?

Edit: OOoopss, I simply cleared my cache and it worked. I'll keep this here in case someone else does the same mistake.

Reply

Hey Ayman A.

I was about to tell you that you need to clear the cache everytime you make a change while working on prod environment.

Cheers!

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.1.4
        "symfony/asset": "^4.0", // v4.0.4
        "symfony/console": "^4.0", // v4.0.14
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/framework-bundle": "^4.0", // v4.0.14
        "symfony/lts": "^4@dev", // dev-master
        "symfony/twig-bundle": "^4.0", // v4.0.4
        "symfony/web-server-bundle": "^4.0", // v4.0.4
        "symfony/yaml": "^4.0" // v4.0.14
    },
    "require-dev": {
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.4
        "symfony/debug-bundle": "^3.3|^4.0", // v4.0.4
        "symfony/dotenv": "^4.0", // v4.0.14
        "symfony/maker-bundle": "^1.0", // v1.0.2
        "symfony/monolog-bundle": "^3.0", // v3.1.2
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.0.4
        "symfony/profiler-pack": "^1.0", // v1.0.3
        "symfony/var-dumper": "^3.3|^4.0" // v4.0.4
    }
}
userVoice