6

I am using a package that is not especially made for symfony (TNTsearch), and have put all the functions I want to use in a service I called TNTsearchHelper.php. This service requires some variables, including some that could be found in the .env file. I currently define and construct these in my class:

class TntSearchHelper
{
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;

        $config = [
            'driver'    => 'mysql',
            'host'      => 'localhost',
            'database'  => 'databasename',
            'username'  => 'user',
            'password'  => 'pw',
            'storage'   => 'my/path/to/file',
            'charset'   => 'utf8',
            'collation' => 'utf8_general_ci',
        ];

        $this->config = $config;
    }

What I would really like is to simply use the variables for my database that are set in the .env file. Is there any way to do this? This service is not registered in services.yaml because this is not neccesary with the autowire: true option, so I don't have any config options/file for my service in the config and wonder if I can keep it that way.

Nikita Leshchev
  • 1,784
  • 2
  • 14
  • 26
Dirk J. Faber
  • 4,360
  • 5
  • 20
  • 58

2 Answers2

15

Yes. It's possible. If you want to use env variables for configuration, you have two options:

1.Use getenv:

$config = [
    'driver'    => 'mysql',
    'host'      => getenv('MYSQL_HOST'),
    'database'  => getenv('MYSQL_DB'),
    'username'  => getenv('MYSQL_LOGIN'),
    'password'  => getenv('MYSQL_PASSWORD'),
    'storage'   => 'my/path/to/file',
    'charset'   => 'utf8',
    'collation' => 'utf8_general_ci',
];

2.Configure your service in services.yaml:

services:
  App\TntSearchHelper:
    arguments:
      - '%env(MYSQL_HOST)%'
      - '%env(MYSQL_DB)%'
      - '%env(MYSQL_LOGIN)%'
      - '%env(MYSQL_PASSWORD)%'

And change your __construct function to this:

public function __construct(string $host, string $db, string $login, string $password, EntityManagerInterface $em) 
{
    $this->em = $em;
    $config = [
        'driver'    => 'mysql',
        'host'      => $host,
        'database'  => $db,
        'username'  => $login,
        'password'  => $password,
        'storage'   => 'my/path/to/file',
        'charset'   => 'utf8',
        'collation' => 'utf8_general_ci',
    ];
    $this->config = $config;
}

Also make sure that all this env variables are set because there's only DATABASE_URL variable in .env file by default

Nikita Leshchev
  • 1,784
  • 2
  • 14
  • 26
  • I must add a reminder, because the getenv returns on some servers always false, I looked further and getenv() is not ideal solution, because: https://stackoverflow.com/a/63814025/1376033 – Mirgen Oct 06 '21 at 14:14
3

I know three possibilities. Each case has 03 steps configuration :
1 - declare yours variables in env.
2 - config service file
3 - and call your parameter

_ In controllers extending from the AbstractController, and use the getParameter() helper :

YAML file config

# config/services.yaml
parameters:
    kernel.project_dir: "%env(variable_name)%"
    app.admin_email: "%env(variable_name)%"

In your service,

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class UserController extends AbstractController
{
    // ...

    public function index(): Response
    {
        $projectDir = $this->getParameter('kernel.project_dir');
        $adminEmail = $this->getParameter('app.admin_email');

        // ...
    }
}


_ In services and controllers not extending from AbstractController, inject the parameters as arguments of their constructors.

YAML file config

# config/services.yaml
parameters:
    app.contents_dir: "%env(variable_name)%"

services:
    App\Service\MessageGenerator:
        arguments:
            $contentsDir: '%app.contents_dir%'

In your service,

class MessageGenerator
{
    private $params;

    public function __construct(string $contentsDir)
    {
        $this->params = $contentsDir;
    }

    public function someMethod()
    {
        $parameterValue = $this->params;
        // ...
    }
}


_ Finally, if some service needs access to lots of parameters, instead of injecting each of them individually, you can inject all the application parameters at once by type-hinting any of its constructor arguments with the ContainerBagInterface:

YAML file config

# config/services.yaml
parameters:
    app.parameter_name: "%env(variable_name)%"

In your service,

use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;

class MessageGenerator
{
    private $params;

    public function __construct(ContainerBagInterface $params)
    {
        $this->params = $params;
    }

    public function someMethod()
    {
        $parameterValue = $this->params->get('app.parameter_name');
        // ...
    }
}


source Accessing Configuration Parameters

belem
  • 341
  • 4
  • 3