I have just started a new Symfony 5 project (only worked on Symfony 3 before) and I am having a hard time to understand how values in .env
and .env.local
work together.
The Symfony docs say, that values in .env.local
will override values from .env
:
If you need to override an environment value (e.g. to a different value on your local machine), you can do that in a .env.local file:
All machines I am working on use the same basic setup (same DB server, etc.) but some values are different (DB name, password, etc.). Thus I wanted to put the common configuration in .env
and the device specific values in .env.local
:
# .env ... DB_SERVER="localhost" DB_VERSION="10.4" DB_USER=${DB_DBNAME} DATABASE_URL="mysql://${DB_USER}:${DB_PASS}@${DB_SERVER}/${DB_DBNAME}?serverVersion=${DB_VERSION}"
# .env.local DB_DBNAME="someDB" DB_PASS="secretPW"
When using this setup I get an error and php bin/console debug:container --env-vars
shows DATABASE_URL "mysql://:@localhost/?serverVersion=10.4"
. Obviously DATABASE_URL
is build ignoring the values from .env.local
.
I can easily solve this by moving DATABASE_URL="mysql://...
to .env.local
but is this the intended way of using .env
and .env.local
?
I thought values of these files are merged where .env.local
values override .env
values. Is this not the case? Or did I make some error?
Advertisement
Answer
Which Symfony environment variable is available in which file (.env, .env.local, etc.)?
.env
is loaded before .env.local
, and each file is processed independently of each other.
For interpolation purposes, only the environment variables defined in the same file, or in in a file processed earlier, are available during .env
file processing.
While environment variables defined in more specific env
files do trump those defined in more general ones, in your example when DB_DBNAME
and DB_PASS
are overwritten/defined too late to be of use, since DATABASE_URL
(which depends on those) is defined earlier and not redefined in the .env.local
file .
But, you can accomplish what you want to do, you just have to do it a different way.
First, create your DATABASE_URL
environment variable with parameter placeholders, like this:
DATABASE_URL="mysql://%DB_USER%:%DB_PASS%@%DB_SERVER%/%DB_DBNAME%?serverVersion=%DB_VERSION%"
Then, in your services.yaml
file, define the container parameters for all these values:
# services.yaml parameters: DB_DBNAME: "%env(DB_DBNAME)%" DB_USER: "%env(DB_USER)%" DB_PASS: "%env(DB_PASS)%" DB_SERVER: "%env(DB_SERVER)%" DB_VERSION: "%env(DB_VERSION)%" # rest of your services.yaml file follows
It’s important that your doctrine configuration reads like this (which is the default), including the resolve
bit:
# doctrine.yaml doctrine: dbal: url: '%env(resolve:DATABASE_URL)%'
With this you’d get your desired results.