Justin Dearing
Justin Dearing

Reputation: 14978

symfony/yaml backed symfony/config not parsing environment variables

I have recreated a simple example in this tiny github repo. I am attempting to use symfony/dependency-injection to configure monolog/monolog to write logs to php://stderr. I am using a yaml file called services.yml to configure dependency injection.

This all works fine if my yml file looks like this:

parameters:
    log.file: 'php://stderr'
    log.level: 'DEBUG'

services:
    stream_handler:
    class:     \Monolog\Handler\StreamHandler
    arguments:
     - '%log.file%'
     - '%log.level%'
    log:
    class:     \Monolog\Logger
    arguments: [ 'default',  ['@stream_handler']  ]

However, my goal is to read the path of the log files and the log level from environment variables, $APP_LOG and LOG_LEVEL respectively. According to The symphony documentations on external paramaters the correct way to do that in the services.yml file is like this:

parameters:
    log.file: '%env(APP_LOG)%'
    log.level: '%env(LOGGING_LEVEL)%'

In my sample app I verified PHP can read these environment variables with the following:

echo "Hello World!\n\n";

echo 'APP_LOG=' . (getenv('APP_LOG') ?? '__NULL__') . "\n";
echo 'LOG_LEVEL=' . (getenv('LOG_LEVEL') ?? '__NULL__') . "\n";

Which writes the following to the browser when I use my original services.yml with hard coded values.:

Hello World!

APP_LOG=php://stderr
LOG_LEVEL=debug

However, if I use the %env(VAR_NAME)% syntax in services.yml, I get the following error:

Fatal error: Uncaught UnexpectedValueException: The stream or file "env_PATH_a61e1e48db268605210ee2286597d6fb" could not be opened: failed to open stream: Permission denied in /var/www/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:107 Stack trace: #0 /var/www/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php(37): Monolog\Handler\StreamHandler->write(Array) #1 /var/www/vendor/monolog/monolog/src/Monolog/Logger.php(337): Monolog\Handler\AbstractProcessingHandler->handle(Array) #2 /var/www/vendor/monolog/monolog/src/Monolog/Logger.php(532): Monolog\Logger->addRecord(100, 'Initialized dep...', Array) #3 /var/www/html/index.php(17): Monolog\Logger->debug('Initialized dep...') #4 {main} thrown in /var/www/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php on line 107

What am I doing wrong?

Upvotes: 2

Views: 2138

Answers (2)

Frantisek Hallo
Frantisek Hallo

Reputation: 1711

Using this command after loading your services.yaml file should help.

$containerBuilder->compile(true); given your files gets also validated by the checks for proper configurations which this method also does. The parameter is $resolveEnvPlaceholders which makes environmental variables accessible to the yaml services configuration.

Upvotes: 0

Justin Dearing
Justin Dearing

Reputation: 14978

Ok you need a few things here. First of all you need version 3.3 of Symfony, which is still in beta. 3.2 was the released version when I encountered this. Second you need to "compile" the environment variables.

Edit your composer.json with the following values and run composer update. You might need to update other dependencies. You can substitute ^3.3 with dev-master.

    "symfony/config": "^3.3",
    "symfony/console": "^3.3",
    "symfony/dependency-injection": "^3.3",
    "symfony/yaml": "^3.3",

You will likely have to do this for symfony/__WHATEVER__ if you have other symfony components.

Now in you're code after you load your yaml configuration into your dependency container you compile it.

So after you're lines here (perhaps in bin/console):

$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . DIRECTORY_SEPARATOR . '..'));
$loader->load('services.yml');

Do this:

$container->compile(true);

Your IDE's intellisense might tell you compile takes no parameters. That's ok. That's because compile() grabs its args indirectly via func_get_arg().

public function compile(/*$resolveEnvPlaceholders = false*/)
{
    if (1 <= func_num_args()) {
        $resolveEnvPlaceholders = func_get_arg(0);
    } else {
    . . .
}

References

Upvotes: 2

Related Questions