Diving into Symfony’s DependencyInjection — Part 2: Symbiosis with the Config component
By: Alex Makdessi
Tags: PHP, Symfony, Dependency Injection, Web Development, Backend

Handling configuration with the Config component

Although the DependencyInjection component is itself sufficient, it’s more powerful when it’s paired with the Config component. It allows us to separate the container configuration in dedicated files, like yaml files in a standard Symfony app.

Let’s use it to draw the best potential of the DI.

composer require symfony/config

With the Config component, we are able to separate the container’s configuration in dedicated files. You can configure your container in various ways (using yaml , xml ,...). In this article, we'll use php file configuration for 2 reasons:

to limit external dependencies ( yaml configuration needs the symfony/yaml component).

configuration needs the component). to have a better understanding of what the container is doing during the configuration (which method is called, …)

The configuration will live in a config/config.php file. To load this file, we are going to use a Loader. For php files, there is a Symfony\Component\DependencyInjection\Loader\PhpFileLoader :

public/index.php

The PhpFileLoader::load() performs an include of our configuration file. The following variables will be accessible from the config/config.php file:

$container => ContainerBuilder

=> ContainerBuilder $loader => PhpFileLoader

=> PhpFileLoader $resource => config.php

=> config.php $type => null in our case (since we are using PhpFileLoader, the type does not matter).

Now, let’s create the config/config.php file.

config/config.php

Autoconfiguration

Now we have a dedicated config file, thanks to our loader, we can define some rules relative to our directories and namespaces in order to automatically configure services. To do so, we have to create a prototype definition, which will be used as the base definition of a group of classes. This prototype will be used for each class of this group. This is called autoconfiguration.

ℹ️ The DependencyInjection component will use the FQCN as the service’s id, therefore instead of doing get('access_manager') to access the AccessManager, you have to do get(AccessManager::class) .

To auto-configure services in a given directory, we use the Loader::registerClasses() function.

config/config.php

If we dump the container before the compilation, we get the following five definitions:

-definitions: array:5 [

"service_container" => Definition {}

"App\Authorization\AccessManager" => Definition {}

"App\Authorization\Voter\PostVoter" => Definition {}

"App\Entity\Post" => Definition {}

"App\Entity\User" => Definition {}

]

All classes in the src directory were automatically registered as services. However, we don't want the Entity directory to be autoconfigured. Let's exclude it by adding a third argument to the registerClasses() function.

// src/Entity directory is now excluded

$loader->registerClasses($definition, 'App\\', '../src/*', '../src/Entity');

Here is our new list of definitions:

-definitions: array:3 [

"service_container" => Definition {}

"App\Authorization\AccessManager" => Definition {}

"App\Authorization\Voter\PostVoter" => Definition {}

]

Remember, now you have to access the AccessManager through its FQCN.