Flex: [Question] The new workflow created by env vars

Created on 28 Apr 2017  路  30Comments  路  Source: symfony/flex

Here are some common scenarios for Symfony developers. Please, confirm that I got right the first one and please, tell me how to solve the other two. Thanks!

Check (in your local machine) if the app works in production

BEFORE

  1. Browse app.php instead of app_dev.php

AFTER

  1. Edit .env and change APP_ENV to prod and APP_DEBUG to 0
  2. Reload index.php
  3. Undo the .env changes to continue developing the app

Use a different database for tests

BEFORE

  1. Edit app/config/config_test.yml and change the database parameters.

AFTER

???


Deploy the application to production

BEFORE

  1. Use Incenteev Param Handler to create the production parameters.yml from
    the parameters.yml.dist
  2. Check that app/config/config_prod.yml contains the right config.

AFTER

???

The .env is gone in production. Where do I configure the production values of
that config?

Most helpful comment

For the first; you can still create that file if necessary.

For the latter two; using env vars is optional, im not sure we can even really use it as we host multiple projects on the same server, so DB_URL or so cannot be set globally.

However i dont like having .env.prod and such.. thats why we have config_prod.yml. Env vars should not become the new parameters, its goals and usecases are different. And TBH i expected https://github.com/symfony/symfony/issues/22561 to work...

All 30 comments

for production, set the env variables on your server (which depends on how your server is configured).
Note that the Incenteev Param Handler already reads config from env variables in order to fill the parameters.yml

For the test DB, I think you can do %env(DB_URL)%_test in your config_test.yml (or whatever the name of a file loaded only for the test environment is).
This will work in most cases (won't work when using a query string in the credentials URL). An alternative is to overwrite the env variable in your PHPUnit bootstrap file (which allows more complex processing of the URL)

The "use different config for testing" is solved in Laravel by creating a .env.testing file. See https://laravel.com/docs/5.4/configuration

For the first; you can still create that file if necessary.

For the latter two; using env vars is optional, im not sure we can even really use it as we host multiple projects on the same server, so DB_URL or so cannot be set globally.

However i dont like having .env.prod and such.. thats why we have config_prod.yml. Env vars should not become the new parameters, its goals and usecases are different. And TBH i expected https://github.com/symfony/symfony/issues/22561 to work...

does env vars supports array lists and hashes like yml? looks like not

No.. why should it? An env var is stringish.

See also https://github.com/symfony/symfony/issues/22151#issuecomment-289265144

In yml it is possible configure some nested structure, like

notification_emails:
  [email protected]: "name 1"
  [email protected]: "name 2"

in env it is impossible. Does we should combine env and yml?

Should probably be something like

  [email protected]: '%env(NAME1)%'
  [email protected]: '%env(NAME2)%'

i dont really like support for json formatted strings or so, which in theory can be decoded with something like %env:json(JSON_STRING)%. I prefer only simple types here; env:int etc.

@Koc as you know, the .env file is for config options that depend on the machine where the app is executed (usual case: database credentials). For the notification emails, maybe you can define them:

1) In the app/config/config.yml file as regular params:

parameters:
    notification_emails: ...

2) As constants in some mailer service (if you use PHP 7.1, you can even define them as private constants):

private const NOTIFICATION_EMAILS = ['...', '...'];

3) Then, disable the actual sending of emails in the dev machine using the SwiftMailer options.

  1. it can be some private information like api keys per hostname (multi-domain project) and we wan't share them with developers
  2. hardcode + same as 1

@ro0NL we need possibility change it per project and env

a little example of our real-life parameters.yml from one project

2017-05-10_17-47-17

Do the params displayed in the screenshot change from one machine to another? It looks like only the Google and Yandex secrets would change from your local machine to production. So, you can define those static params in app/config/config.yml (etc/container.yaml in Flex) and define the dynamic params (the secrets) in the .env file.

this is multi-site project with per-site configuration. Also some configuration are nested.

Does parameters.yml would totally replaced with env? Or we can use both?

@Koc the only question that you must ask yourself is: do I have to change this option if I execute this app in the computer of my workmate or in production?

For example, you have a param called hostnames_configuration.metaltop.dev.category_slug_field: null That's a "static param" because it's probably going to be the same wherever you execute the app. (If you reuse this code in another project, that config value may change ... but again, it doesn't depend on the machine where the app is running). Static params don't go to .env, only dynamic params.

@Koc you can use both. parameters.yml has nothing special in Symfony. It is just a YAML file imported by the main config file (just like security.yml is).
What makes parameters.yml special in SE is just the fact that it appears in .gitignore.

@javiereguiluz this project deployed with 3 different configurations. Like paas. One portal for metallurgical engineering, second for building materials, third for food. Food portal even hasn't hostnames_configuration.metaltop.dev.category_slug_field: null, it has other structure.

In the new situation, I would have only 1 front-controller (app.php) to edit my files, which is a better situation than before. However, I'm not willing to change my env variables each time I want to visit prod. Also, a second hostname is kind of an issue. How should I solve this?

For the first; you can still create that file if necessary.

:)

or get creative; app.php?magic-token=prod

@ro0NL But that's not really a sane default for the app.php and app_dev.php for flex then. Either:

  • I will have to extract the app_dev.php part from this file or
  • Have a lot of extra development effort changing values in files

Imo. having 1 front controller (based on env) is a sane default, i rarely visit app_prod.php today really.

But that also heavily relies on the fact i assume SF doesnt mess up; in my perspective if dev is all good, and CI passes, im ready to deploy.

Given https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/3.3/web/index.php index_prod.php would be as simply

putenv('APP_ENV', 'prod');
require 'index.php';

no?

I always use app_dev.php to develop, but there are often cases where I need to verify behavior in prod mode.

I believe your putenv() example is a viable alternative

I always use app_dev.php to develop

Same here, and i always keep patching vhosts to allow for domain.dev/ :)

The biggest personal project I'm working on is a monolithic app deployed on Heroku, and having something like 2 different domain names and lots of subdomains. I'm using 2 env vars to specify main hosts, it works like a charm.

And all my parameters.yml does is defining default env vars, like the .env file would do with Flex, because database, mailer and even secret configuration is handled via env vars and "defaulted" in parameters.yml.

I know @Koc example is very different because it's way much bigger than a simple multi-domain app, but it means there is a way to migrate to environment vars for at least some parts of the app itself, or change this system to a kernel-environment-based configuration (and kernel env would be set by... env vars? 馃槈) which is much more maintainable.

For @Koc's example, for instance, I certainly would keep using a parameters.yml file, or a similar system as said above, even with Flex, simply because per-app application is way more complex than simply handing a few environment vars.

.env file creates only for first installation. When another developer clone my repo and doing composer install - no interactive asking of parameters as before was when using Incenteev Param Handler

You can all take a look at symfony/symfony#23823 and support the idea of having JSON strings as env vars so they can be deserialized at runtime 馃槈

@Pierstoval, had already voted. But in any case inlined json is worse than yaml. Yaml multiline and readable.

@koc Yaml doesn't exist in a .env file, as said before, if you need yaml, use yaml 馃槃 However, inlined JSON is possible, that's why I proposed the above issue

Closing this issue as it diverged from the original report. The only question that is not answered about the original question is how to define env vars for test. The answer is that you can define them in phpunit.xml.

See symfony/recipes#170

I have just looked for an answer of this question and solved it the following way:

add to the doctrine-test-config file: config/packages/test/doctrine.yaml

doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%_test'

Now you can use all doctrine commands with the test environment.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

soullivaneuh picture soullivaneuh  路  6Comments

tsantos84 picture tsantos84  路  7Comments

Deltachaos picture Deltachaos  路  5Comments

fabpot picture fabpot  路  7Comments

c33s picture c33s  路  7Comments