Symfony 3 — From mutable to immutable framework

Julien Breux
Julien Breux’s digital life
2 min readFeb 12, 2017
Amazing Symphony in Disney Concert Hall at Los Angeles

Why make Symfony 3 immutable?

In my job we work with Docker and Kubernetes, and ours applications must be immutable because we play with containers. And a container must run as read-only where possible!

How to make Symfony 3 immutable?

As you might know already, Symfony use a bundle to manage its configuration. The most troubling factor in my opinion.

How does the bundle work?

It’s very simple, you have two files ; “parameters.yml.dist” and “parameters.yml” in the “app/config” directory.

When you run composer for installing or updating, a special script handler named “buildParameters” is executed.

And this script builds a new version of “parameters.yml”.

#FAILED mutation detected!

Environment variables to the rescue!

In the world of containers, the environment variables are widespread. In fact, it’s the way to configure a container.

Since the version 3.2, Symfony introduces a new syntax to read environment variables from YAML files.

In the “app/config/parameters.yml” you can declare that:

parameters:
env(MY_ENV_VAR): "default"

In the “app/config/config.yml” you can read that:

i_need_a_value: "%env(MY_ENV_VAR)%"

#YUCK we need again the “parameters.yml” and the rest… Really? Nooooo!

Our solution!

The simple solution is before our eyes! Remove this crazy f***ing bundle.

First step, copy the “parameters” node data of “app/config/parameters.yml” in the “app/config/config.yml” and replace it by the environment variables.

Do not forget to add the default values.

parameters:
env(DATABASE_HOST): "pdo_pgsql"
...
database_driver: "%env(DATABASE_DRIVER)%"
database_host: "%env(DATABASE_HOST)%"
database_port: "%env(DATABASE_PORT)%"
database_name: "%env(DATABASE_NAME)%"
database_user: "%env(DATABASE_USER)%"
database_password: "%env(DATABASE_PASSWORD)%"
mailer_transport: "%env(SMTP_TRANSPORT)%"
mailer_host: "%env(SMTP_HOST)%"
mailer_user: "%env(SMTP_USER)%"
mailer_password: "%env(SMTP_PASSWORD)%"

secret: "%env(APP_SECRET)%"
locale: "%env(APP_LOCALE)%"
framework:
translator: { fallbacks: ["%locale%"] }
...

Remove this import line from the “app/config/config.yml”:

- { resource: parameters.yml }

Remove “app/config/parameters.*” files.

Remove these lines from your “composer.json”:

"incenteev/composer-parameter-handler": "^X.Y"..."Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",..."incenteev-parameters": {
"file": "app/config/parameters.yml"
},

Execute a small “composer(.phar) update” to clean the “vendor” directory.

Job done!

Now, you’ve just to set your environment variables to change the execution of this amazing PHP framework.

Bonus

You can create an “.env.dist” file with your different environment variables. See below:

DATABASE_DRIVER=pdo_pgsql
DATABASE_HOST=symfony
DATABASE_PORT=5432
DATABASE_NAME=symfony
DATABASE_USER=symfony
DATABASE_PASSWORD=symfony
SMTP_TRANSPORT=smtp
SMTP_HOST=0.0.0.0
SMTP_USER=symfony
SMTP_PASSWORD=symfony

APP_SECRET=HeyIAmSecret
APP_LOCALE=en

And you can use a tool (like that: https://github.com/kennethreitz/autoenv) that help you to load environment variables when you enter in directory.

In your “Dockerfile” or “docker-compose.yml” don’t forget to declare this environment variables.

I hope that this story helps you to make Symfony 3 immutable!

Next time, we will discuss about how to run Symfony 3 in a Kubernetes cluster.

--

--