4

Is it normal to use parameters in your own code from .env file through $_ENV variable? Of course in context of project using Symfony 4.

I have such code:

//WebhookUrlBuilder.php
class WebhookUrlBuilder
{

    private RouterInterface $router;

    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
        if (PHP_SAPI === 'cli') {
            $this->router->getContext()->setHost($_ENV['HOST_URL'])->setScheme($_ENV['URL_SCHEME']);
        }
    }

    public function build(string $hash): string
    {
        return $this->router->generate(BotsController::WEBHOOK_URL_NAME, [
            'hash' => $hash
        ], UrlGeneratorInterface::ABSOLUTE_URL);
    }
}

There is an opinion that using an $_ENV variable is bad taste, and I have to deliver these parameters through ParameterBag, like this:

#services.yml
parameters:
    host: '%env(HOST_URL)'
    scheme: '%env(URL_SCHEME)'
//WebhookUrlBuilder.php
class WebhookUrlBuilder
{

    private RouterInterface $router;

    public function __construct(RouterInterface $router, ParameterBag $parameterBag)
    {
        $this->router = $router;
        if (PHP_SAPI === 'cli') {
            $this->router
                 ->getContext()
                 ->setHost($parameterBag->get('host'))
                 ->setScheme($parameterBag->get('scheme'));
        }
    }

    public function build(string $hash): string
    {
        return $this->router->generate(BotsController::WEBHOOK_URL_NAME, [
            'hash' => $hash
        ], UrlGeneratorInterface::ABSOLUTE_URL);
    }
}

But I consider that is useless extra action(copy values from .env variables to paramteres in services.yml) which doesn't bring any profit. What do u think?

GutsOut
  • 131
  • 1
  • 9

1 Answers1

1

It's better to decouple code from environmental variables, this make your code more portable and testable. You should rewrite contstructor of WebhookUrlBuilder like this:

//WebhookUrlBuilder.php
class WebhookUrlBuilder
{

    private RouterInterface $router;

    public function __construct(RouterInterface $router, $host, $scheme)
    {
        $this->router = $router;
        if (PHP_SAPI === 'cli') {
            $this->router
                 ->getContext()
                 ->setHost($host)
                 ->setScheme($scheme);
        }
    }

    public function build(string $hash): string
    {
        return $this->router->generate(BotsController::WEBHOOK_URL_NAME, [
            'hash' => $hash
        ], UrlGeneratorInterface::ABSOLUTE_URL);
    }
}

and inject $host and $scheme via services.yaml like this:

#services.yml
parameters:
    host: '%env(HOST_URL)'
    scheme: '%env(URL_SCHEME)'
services:
    WebhookUrlBuilder:
        autowire: true
        arguments: ['%host%', '%scheme%']

Now, thanks to autowire, your builder is correctly instantiated and you can create new instances passing directly $host and $scheme per example in a phpunit test

Manuel
  • 836
  • 13
  • 30
  • Yeah yeah, absolutely agree with that approach, we also came to this conclusion. But the main question is there any point to packing .env params to parameterBag, and don't use them directly through $_ENV. For example, suppose a symfony container wouldn’t be able to inject these parameters into the constructor. – GutsOut Oct 10 '19 at 09:43
  • It depends on how much secure and trusted is your $_ENV. ParameterBag comes with useful filter methods (getAlnum(), getInt(), getBoolean(), etc) that come free with the framework, IMO is a must to filter not trusted env vars. – Manuel Oct 10 '19 at 23:37