68publishers / application

🌎 Easily setup different languages, currencies and countries
MIT License
3 stars 2 forks source link

Replace PHP configurations file with neon variant #30

Open jelen07 opened 5 years ago

jelen07 commented 5 years ago

ATM we have configuration files in project like

<?php

declare(strict_types=1);

if ($secure = (bool) getenv('COOKIE_SECURE')) {
    return [
        'session' => [
            'cookieSecure' => $secure,
        ],
    ];
}

return [];

It would be nice if we could write some syntax in neon to load this setting. This example is just a boolean, so it would be easy

session:
    cookieSecure: ::getenv(COOKIE_SECURE)

But there are more complicated structures, even the whole block could not be used.

So something like: ::parseEnv(DATABASE_URL, Kdyby\Doctrine\EnvConfig)

Or any other hints? Will it be profit?

tg666 commented 5 years ago

Implementing ENV variables into neon is generally a problem...

There are two packages by community, that tries it:

1) https://www.componette.com/wodcz/nette-dotenv/ 2) https://www.componette.com/rixxi/env/

Usage of the first one package in similar to your example

session:
    cookieSecure: ::getenv(COOKIE_SECURE)
    cookieSecure: @env::get(COOKIE_SECURE, no)

But the problem is a method in generated container looks like this:

public function createServiceSession__session(): Nette\Http\Session
    {
        $service = new Nette\Http\Session(....));
        $service->setOptions(['cookieSecure' => $this->getService('env.env')->get('COOKIE_SECURE', FALSE)]);
        return $service;
    }

So the .env file is loaded/parsed everytime. This can be fixed by loading ENV veriables only once in compile-time and pass it as an array into ServiceDefinition - ENV variables will be an static array in a Container's file.

But there is a another problem - if some CompilerExtension validates type of an configuration option like this:

Nette\Utils\Validator::assertField($config, 'name', 'string');

it will fails bcs @env::get('NAME') will be translated as instance of Nette\DI\Statement(['@env', 'get'], ['NAME']) so validation fails. Another example is in SessionExtension:

public function loadConfiguration()
{
    # ...

    if (isset($config['cookieSecure']) && $config['cookieSecure'] === 'auto') {
        $config['cookieSecure'] = $builder::literal('$this->getByType(Nette\Http\IRequest::class)->isSecured()');
    }

    # ...
}

If you set an cookieSecure option to auto in the .env file and you pass a value into configuration as cookieSecure: @env::get('COOKIE_SECURE') the vlaue of $config['cookieSeecure'] is instance of Nette\DI\Statement, not string auto. So another unpredictable behavior...

The second package by rixxi is based on native DI parameters => extension loads ENV variables into DI parameters. This solution had a lot of limitations and its not compatible with a nette 2.4 because parameters are now processed before any CompilerExtension.


The only solution I came up with is to extend Nette\Configurator (used in bootstrap.php), override method Configurator::createLoader() and pass custom NeonAdapter into Loader, that will return parsed neon with ENV variables.

But i think the solution is ugly :confused: ...

mabar commented 5 years ago

Just load environment parameters to container parameters through configurator. Nothing more is needed