Description
Description
Since switching Symfony to env vars, there is a systematic issue with bundle configurations. Env vars are replaced by string placeholders when compiling the container and those placeholders will be passed to bundle configurations. Any configuration value that expects anything else but a string will fail with an error like:
Invalid type for path "web_profiler.toolbar". Expected boolean, but got string.
A quick research shows up several bug reports of this kind:
- [DotEnv] Cannot pass .env parameters in bundles config #39625
- env processing and DI problem in monolog mailer config with multiple addresses #39499 for Monolog
- DoctrineBundle config parameter "doctrine.dbal.logging" didn't work with value passed via env #38915 for Doctrine
- [DI] Environment Variable Processors not working #37426 for Web Profiler and Framework
- Environment variable in configuration set to * nelmio/NelmioCorsBundle#99 for Nelmio CORS
- Using an env var for the disable_delivery option doesn't work as expected swiftmailer-bundle#290 for Swiftmailer
Benefits of env vars
Env vars as used in Symfony provide two benefits:
- Configure the application with static values provided in
.env
,.env.local
etc. Those are known during container compilation. - Configure the application with dynamic values provided by the runtime (Apache, Nginx). Those are not known during container compilation.
It is officially recommended to dump the environment variables to a PHP file in production. Hence my assumption would be that the majority of Symfony users is using mostly static variables.
Since static variables are known during container compilation, those could be passed to bundle configurations without ever changing a bundle to "support env vars".
Proposal: Static vs. runtime env vars
I propose to distinguish between static and runtime env vars. Static env vars (Group 1) are resolved at compile time and statically compiled into the container. Runtime env vars (Group 2) are replaced by placeholders and resolved at runtime.
For BC, all env vars are regarded as resolved at runtime. With a switch (e.g. framework.static_env_vars
), all env vars can be switched to static.
When individual variables are required to be resolved at runtime, those could be marked with a runtime:
processor. Such variables are resolved at runtime even if static_env_vars
is set to true
.
In a later major release, I propose to flip static_env_vars
to true
by default to improve DX.
Example
framework:
static_env_vars: true
some_bundle_config:
setting1: "%env(SETTING_1)%" # resolved at compile time - compiled into the container
setting2: "%env(runtime:SETTING_2)%" # resolved at runtime - placeholders are passed to bundle configuration
Benefits
- Only one configuration format (
.env
) rather than two (.env
andparameters.yaml
) for deployment specific configuration - Flat learning curve: Start with static env vars, introduce runtime env vars gradually when needed
- Supports secrets for all settings (secrets are not supported for DI parameters)
- Supports locally overriding settings in
.env.local
(not easily achievable withparameters.yaml
)