How to set application values for easy reuse in Symfony 5+

This article is a work in progress and will be further updated much more in the future. I don’t feel it is complete yet, I’d like to cover more details, more screenshots etc..

So how do you set/configure a value like an upload directory in one location in Symfony so that you can easily use it in your app later? It is actually easier than it even sounds.

Symfony has this handy system you can use to set parameters once and fetch them later. Here in this SymfonyCast under the section about moving an uploaded file, you will see this line.

$destination = $this->getParameter('kernel.project_dir').'/public/uploads';

Forget a moment about the full string. $this->getParameter() is what I want to focus on. The Symfony documentation metions accessing configuration parameters. And that $this->getParameters() is how you get to them.

The docs go further and say this is how you access them in the controller. To get them in your services you should autowire them and if you need them in services often you should bind them. I’ll add that below.

If you mostly need parameters in controllers, setting them as parameters like below is easy. If you need them in multiple services, then binding them is easier.

You can set your own parameters in the file /app/config/services.yaml under a section named… “Parameters”  or “bind” them globally under the _defaults section.

Mostly controllers

Lets look at how to do that really quickly. Here is what is in the top portion of my file.

# /app/config/services.yaml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.

# 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:
  app.db_user: '%env(DATABASE_USER)%'
  app.db_pass: '%env(DATABASE_PASSWORD)%'
  app.user_uploads_dir: '%kernel.project_dir%/uploads'
services:
  # default configuration for services in *this* file
  _defaults:
    autowire: true      # Automatically injects dependencies in your services.
    autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

The whole file is really long I just wanted enough to show a small section so you could identify it visually. You can find more about the configuration parameters in the docs here.

See the parameters section. There are three parameters I have set. app.user_upload_dir: ‘%kernel.project_dir%/uploads’ is one I made up for my own use. With that syntax I don’t have to add anything to the end of it like in the SymfonyCast code above.

I think it shows this type change later in the SymfonyCast too. You should read that full SymfonyCast if you are interested in learning how to work with uploads in Symfony 5+ Here is another great SymfonyCast all about configuration in Symfony 5+ I highly suggest you read it.

But anyways like the docs show, if I need the value of the uploads directory inside a controller, I simply access it like this.

$uploadsDir = $this->getParameter('app.user_uploads_dir');

And I don’t have to worry about misspelling it, and it can be changed in one location now if it ever needs to be changed.

Here is another link from the Symfony documentation about configuration overall.

Using Bind

Using bind seems to work more easily in more places. I am not sure of any disadvantages, the main advantage seems to be ease of use. The other methods require you to autowire some other service and call some specific method. My memory sucks, so this is the easier way for me . LOL

The documentation on this subject isn’t great, it quickly glosses over the subject.

The best info I could find on bind and how it works is actually in a SymfonyCast like usual.

Below is what  I have set for example.

# default configuration for services in *this* file
_defaults:
  autowire: true      # Automatically injects dependencies in your services.
  autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
  bind:
    # autowire this variable name to get the value below
    $userUploads: '%kernel.project_dir%/uploads'

Now to use the value of $userUploads all I do is add it to the Controller route definition as a parameter or add it to the __construct() of a Service class aka any other class.

Example uses

For a Controller router method.

public function save_user_image(Request $request, Security $security,
                                MessageBusInterface $messageBus, $userUploads): JsonResponse

For a Service constructor.

public function __construct(LoggerInterface $exceptionsLogger, $userUploads)
    {
        $this->exceptionLogger = $exceptionsLogger;
        $this->userUploadsDir = $userUploads . '/';
    }

How do you view the parameters?

If you are using bind, you simply look at what you have defined in the services.yaml file.
To see what parameters you can access use the following command. Only values you have defined under the “parameters” section of the services.yaml file and the parameters that symfony sets internally are visible with this command.

php bin/console debug:container --parameters

That will output a really long list of all of the parameters and info about them like this.

symfony output parameters
A list of the Symfony parameters you can use

There are literally hundreds of them. So many I am willing to bet if you need to use something or know where it is, this will show you.


Posted

in

,

by

Comments

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: