Not unlike our space-traveling users, we are also pretty adventurous. Sure, they
might be discovering intelligent life on other planets or exploring binary planets
inside the habitable zone. But we! We are going to explore the config/ directory
and learn all of its secrets. Seriously, this is cool stuff!

Environment?

We know that Symfony is really just a set of routes and a set of services. And we
also know that the files in config/packagesconfigure those services. But,
who loads these files? And what is the importance - if any - of these
sub-directories?

Well, put on your exploring pants, because we're going on a journey!

The code that runs our app is like a machine: it shows articles and will eventually
allow people to login, comment and more. The machine always does the same work, but...
it needs some configuration in order to do its job. Like, where to write log files
or what the database name and password are.

And there's other config too, like whether to log all messages or just errors,
or whether to show a big beautiful exception page - which is great for development -
or something aimed at your end-users. Yep, the behavior of your app can change
based on its config.

Symfony has an awesome way of handling this called environments. It has two
environments out-of-the-box: dev and prod. In the dev environment, Symfony
uses a set of config that's... well... great for development: big errors, log everything
and show me the web debug toolbar. The prod environment uses a set of config that's
optimized for speed, only logs errors, and hides technical info on error pages.

How Environments Work

Ok, I know what you're thinking: this makes sense from a high level... but how does
it work? Show me the code!

Open the public/ directory and then index.php:

40 lines public/index.php

... lines 1 - 2

useApp\Kernel;

useSymfony\Component\Debug\Debug;

useSymfony\Component\Dotenv\Dotenv;

useSymfony\Component\HttpFoundation\Request;

require__DIR__.'/../vendor/autoload.php';

// The check is to ensure we don't use .env in production

if (!isset($_SERVER['APP_ENV'])) {

if (!class_exists(Dotenv::class)) {

thrownew \RuntimeException('APP_ENV environment variable is not defined. You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file.');

This is the front controller: a fancy word to mean that it is the first
file that's executed for every page. You don't normally worry about it,
but... it's kind of interesting.

It's looking for an environment variable called APP_ENV:

40 lines public/index.php

... lines 1 - 9

// The check is to ensure we don't use .env in production

if (!isset($_SERVER['APP_ENV'])) {

... lines 12 - 15

}

... lines 17 - 40

We're going to talk more about environment variables later, but they're just a way
to store config values. One confusing thing is that environment variables are
a totally different thing than what we're talking about right now: Symfony environments.

Forget how the $env variable is set for a moment, and go down to see how it's used:

40 lines public/index.php

... lines 1 - 17

$env = $_SERVER['APP_ENV'] ?? 'dev';

... lines 19 - 34

$kernel = new Kernel($env, $debug);

... lines 36 - 40

Ah! It's passed into some Kernel class! The APP_ENV variable is set in
a .env file, and right now it's set to dev. Again, more on environment variables
later.

Anyways, the string dev - is being passed into a Kernel class. The question
is... what does that do?

Debugging the Kernel Class

Well... good news! That Kernel class is not some core part of Symfony. Nope,
it lives right inside our app! Open src/Kernel.php:

When Symfony boots, it needs config: it needs to know where to log or how to connect
to the database. To get all of the config, it calls this one method. You can ignore
these first two lines: they're internal optimizations.

Right now, in the dev environment, it will load 5 additional files. The order
of how this happens is the key: any overlapping config in the environment-specific
files override those from the main files in packages/.

For example, open the main routing.yaml. This is not very important, but it sets
some strict_requirements flag to ~... which is null in YAML:

4 lines config/packages/routing.yaml

framework:

router:

strict_requirements:~

But then in the dev environment, that's overridden: strict_requirements is set
to true:

4 lines config/packages/dev/routing.yaml

framework:

router:

strict_requirements:true

To prove it, find your terminal and run:

./bin/console debug:config framework

Since we're in the dev environment right now... yep! The strict_requirements
value is true!

This also highlights something we talked about earlier: the names of the files
are not important... at all. This could be called hal9000.yaml and not change
a thing. The important part is the root key, which tells Symfony which bundle
is being configured.

Usually, the filename matches the root key... ya know for sanity. But, it doesn't
have to. The organization of these files is subjective: it's meant to make as much
sense as possible. The routing.yaml file actually configures something under
the framework key.

My big point is this: all of these files are really part of the same configuration
system and, technically, their contents could be copied into one giant file called
my_big_old_config_file.yaml.

Oh and I said earlier that Symfony comes with only two environments: dev and
prod. Well... I lied: there is also a test environment used for automated testing.
And... you can create more!

So.. yea! All of the files inside config/ either configure services or configure
routes. No biggie.

But now, with our new-found knowledge, let's tweak the cache service to behave
differently in the dev environment. And, let's learn how to change to the
prod environment.

Leave a comment!

2018-02-23Victor Bocharsky

Hey Elvism,

Well, there're a few possible ways but it depends. For example, if we're talking about controllers - you can extend Symfony base controller and then you'll have "$this->getParameter()" shortcut, or, if you have an access to the DI container - call it via "$this->container->getParameter()". Fo example, if you want to get a value of "app.pool_acct" parameters, get it with:$this->getParameter('app.pool_acct').

If we're talking about services, you need to pass parameters explicitly on service definition of as an argument like:App\Service\MyService: arguments: - '%app.pool_acct%'