Как устанавливать внешние параметры в сервис-контейнере

В Configuring Symfony (and Environments) вы узнали, как управлять конфигурацией вашего приложения. В некоторых случаях вашему приложению может пойти на пользу хранение некоторых сертификатов вне кода вашего проекта. Конфигурация БД является одним из таких примеров. Гибкость сервис-контейнера Symfony позволяет вам с лёгкостью делать это.

Переменные окружения

Вы можете ссылаться на переменные окружения, используя специальные параметры, названные в честь тех переменных, которые вы хотите использовать, окружённые env(). Их настоящие значения будут разрешены во время прогона (единожды на запрос), чтобы сброшенные контейнеры могли быть вновь динамически сконфигурированы даже после компиляции.

Например, при установке рецепта doctrine, конфигурация БД помещается в переменную окружения DATABASE_URL:

1
2
# .env
DATABASE_URL="mysql://db_user:[email protected]:3306/db_name"

На эту переменную ссылаются в конфигурации сервис-контейнера, используя %env(DATABASE_URL)%:

  • YAML
    1
    2
    3
    4
    5
    # config/packages/doctrine.yaml
    doctrine:
        dbal:
            url: '%env(DATABASE_URL)%'
        # ...
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- config/packages/doctrine.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/doctrine
            http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
    
        <doctrine:config>
            <doctrine:dbal
                url="%env(DATABASE_URL)%"
            />
        </doctrine:config>
    
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // config/packages/doctrine.php
    $container->loadFromExtension('doctrine', array(
        'dbal' => array(
            'url' => '%env(DATABASE_URL)%',
        )
    ));
    

Вы также можете давать параметрам env() значение по умолчанию: значение по умолчанию будет использовано каждый раз, когда не найдена соответствующая переменная окружения:

  • YAML
    1
    2
    3
    # config/services.yaml
    parameters:
        env(DATABASE_HOST): localhost
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <!-- config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <parameters>
            <parameter key="env(DATABASE_HOST)">localhost</parameter>
        </parameters>
     </container>
    
  • PHP
    1
    2
    // config/services.php
    $container->setParameter('env(DATABASE_HOST)', 'localhost');
    

Конфигурация переменных окружения в производстве

Во время разработки, вы будете использовать файл .env, чтобы сконфигурировать ваши переменные окружения. На вашем сервере производства рекомендуется конфигурировать переменные на уровне веб-сервера. Если вы используете Apache или Nginx, то вы можете использовать, к примеру, следующее:

  • Apache
    1
    2
    3
    4
    5
    <VirtualHost *:80>
        # ...
    
        SetEnv DATABASE_URL "mysql://db_user:[email protected]:3306/db_name"
    </VirtualHost>
    
  • Nginx
    1
    fastcgi_param DATABASE_URL "mysql://db_user:[email protected]:3306/db_name";
    

Caution

Имейте в виду, что сброс содержания переменных $_SERVER и $_ENV или вывод содержания phpinfo() отобразит значения переменных окружения, обнажая чувствительную информацию вроде сертификатов БД.

Значения переменных окружения также отображаются в веб-интерфейсе Symfony профайлера. На практике это не должно быть проблемой, потому что веб-профайлер никогда не должен быть включён в production.

Процессоры переменных окружения

New in version 3.4: Процессоры переменных окружения появились в Symfony 3.4.

Значения переменных окружения по умолчанию считаются строками. Однако ваш код может ожидать другие типы данных, например, целые числа или булевые значения. Symfony решает эту проблему процессорами, которые преобразуют содержимое указанных переменных окружения. Следующий пример использует целочисленный процессор для преобразования значения переменной окружения HTTP_PORT в целое число:

  • YAML
    1
    2
    3
    4
    # config/packages/framework.yaml
    framework:
        router:
            http_port: env(int:HTTP_PORT)
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- config/packages/framework.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <framework:config>
            <framework:router http-port="%env(int:HTTP_PORT)%" />
        </framework:config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // config/packages/framework.php
    $container->loadFromExtension('framework', array(
        'router' => array(
            'http_port' => '%env(int:HTTP_PORT)%',
        ),
    ));
    

Symfony предоставляет следующие процессоры переменных окружения:

env(string:FOO)

Преобразует FOO в строку:

  • YAML
    1
    2
    3
    4
    5
    # config/packages/framework.yaml
    parameters:
        env(SECRET): 'some_secret'
    framework:
       secret: '%env(string:SECRET)%'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/packages/framework.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <parameters>
            <parameter key="env(SECRET)">some_secret</parameter>
        </parameters>
    
        <framework:config secret="%env(string:SECRET)%" />
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/packages/framework.php
    $container->setParameter('env(SECRET)', 'some_secret');
    $container->loadFromExtension('framework', array(
        'secret' => '%env(string:SECRET)%',
    ));
    
env(bool:FOO)

Преобразует FOO в булево значение:

  • YAML
    1
    2
    3
    4
    5
    # config/packages/framework.yaml
    parameters:
        env(HTTP_METHOD_OVERRIDE): 'true'
    framework:
       http_method_override: '%env(bool:HTTP_METHOD_OVERRIDE)%'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/packages/framework.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <parameters>
            <parameter key="env(HTTP_METHOD_OVERRIDE)">true</parameter>
        </parameters>
    
        <framework:config http-methode-override="%env(bool:HTTP_METHOD_OVERRIDE)%" />
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/packages/framework.php
    $container->setParameter('env(HTTP_METHOD_OVERRIDE)', 'true');
    $container->loadFromExtension('framework', array(
        'http_method_override' => '%env(bool:HTTP_METHOD_OVERRIDE)%',
    ));
    
env(int:FOO)
Преобразует FOO в целочисленное значение.
env(float:FOO)
Преобразует FOO в дробное число.
env(const:FOO)

Находит значение константы определённой в FOO:

  • YAML
    1
    2
    3
    4
    5
    6
    # config/packages/security.yaml
    parameters:
        env(HEALTH_CHECK_METHOD): 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD'
    security:
       access_control:
         - { path: '^/health-check$', methods: '%env(const:HEALTH_CHECK_METHOD)%' }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/packages/security.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:security="http://symfony.com/schema/dic/security"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <parameters>
            <parameter key="env(HEALTH_CHECK_METHOD)">Symfony\Component\HttpFoundation\Request::METHOD_HEAD</parameter>
        </parameters>
    
        <security:config>
            <rule path="^/health-check$" methods="%env(const:HEALTH_CHECK_METHOD)%" />
        </security:config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    // config/packages/security.php
    $container->setParameter('env(HEALTH_CHECK_METHOD)', 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD');
    $container->loadFromExtension('security', array(
        'access_control' => array(
            array(
                'path' => '^/health-check$',
                'methods' => '%env(const:HEALTH_CHECK_METHOD)%',
            ),
        ),
    ));
    
env(base64:FOO)
Декодирует содержимое FOO, которое является base64-закодированной строкой.
env(json:FOO)

Декодирует содержимое FOO, которое является JSON-закодированной строкой. Возвращает массив или null:

  • YAML
    1
    2
    3
    4
    5
    # config/packages/framework.yaml
    parameters:
        env(TRUSTED_HOSTS): '["10.0.0.1", "10.0.0.2"]'
    framework:
       trusted_hosts: '%env(json:TRUSTED_HOSTS)%'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/packages/framework.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <parameters>
            <parameter key="env(TRUSTED_HOSTS)">["10.0.0.1", "10.0.0.2"]</parameter>
        </parameters>
    
        <framework:config trusted-hosts="%env(json:TRUSTED_HOSTS)%" />
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/packages/framework.php
    $container->setParameter('env(TRUSTED_HOSTS)', '["10.0.0.1", "10.0.0.2"]');
    $container->loadFromExtension('framework', array(
        'trusted_hosts' => '%env(json:TRUSTED_HOSTS)%',
    ));
    
env(resolve:FOO)

Заменяет строку FOO значением конфигурационного параметра с этим значением:

  • YAML
    1
    2
    3
    4
    5
    6
    # config/packages/sentry.yaml
    parameters:
        env(HOST): '10.0.0.1'
        env(SENTRY_DSN): 'http://%env(HOST)%/project'
    sentry:
        dsn: '%env(resolve:SENTRY_DSN)%'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- config/packages/sentry.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <parameters>
            <parameter key="env(HOST)">10.0.0.1</parameter>
            <parameter key="env(SENTRY_DSN)">http://%env(HOST)%/project</parameter>
        </parameters>
    
        <sentry:config dsn="%env(resolve:SENTRY_DSN)%" />
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    // config/packages/sentry.php
    $container->setParameter('env(HOST)', '10.0.0.1');
    $container->setParameter('env(SENTRY_DSN)', 'http://%env(HOST)%/project');
    $container->loadFromExtension('sentry', array(
        'dsn' => '%env(resolve:SENTRY_DSN)%',
    ));
    
env(csv:FOO)

Декодирует содержимое FOO, которое является CSV-закодированной строкой:

1
2
3
4
parameters:
    env(TRUSTED_HOSTS): "10.0.0.1, 10.0.0.2"
framework:
   trusted_hosts: '%env(csv:TRUSTED_HOSTS)%'

New in version 4.1: Процессор csv появился в Symfony 4.1.

env(file:FOO)

Возвращает содержимое файла путь к которому указан в переменной окружения FOO:

  • YAML
    1
    2
    3
    4
    5
    # config/packages/framework.yaml
    parameters:
        env(AUTH_FILE): '../config/auth.json'
    google:
        auth: '%env(file:AUTH_FILE)%'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/packages/framework.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <parameters>
            <parameter key="env(AUTH_FILE)">../config/auth.json</parameter>
        </parameters>
    
        <google auth="%env(file:AUTH_FILE)%" />
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/packages/framework.php
    $container->setParameter('env(AUTH_FILE)', '../config/auth.json');
    $container->loadFromExtension('google', array(
        'auth' => '%env(file:AUTH_FILE)%',
    ));
    

Можно также комбинировать любое количество процессоров:

1
2
3
4
5
6
7
8
parameters:
    env(AUTH_FILE): "%kernel.project_dir%/config/auth.json"
google:
    # 1. получает значение переменной окружения AUTH_FILE
    # 2. заменяет значение конфигурационным параметром для получения пути к конфигурации
    # 3. получает содержимое файла сохранённого по этому пути
    # 4. JSON-декодирует содержимое файла и возвращает его
    auth: '%env(json:file:resolve:AUTH_FILE)%'

Пользовательские процессоры переменных окружения

Также возможно добавлять свои процессоры для пользовательских переменных. Сначала создайте класс, который реализует EnvVarProcessorInterface и потом определите сервис для этого класса:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class LowercasingEnvVarProcessor implements EnvVarProcessorInterface
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function getEnv($prefix, $name, \Closure $getEnv)
    {
        $env = $getEnv($name);

        return strtolower($env);
    }

    public static function getProvidedTypes()
    {
        return [
            'lowercase' => 'string',
        ];
    }
}

Константы

Контейнер также имеет поддержку для установки PHP-констант в качестве параметров. См. Constants as Parameters, чтобы узнать больше деталей.

Смешанная конфигурация

Вы можете смешивать любые форматы конфигурации на свой вкус (YAML, XML и PHP) в config/packages/. Импорт PHP-файла даёт вам возможность добавлять всё, что нужно, в контейнер. Например, вы можете создать файл drupal.php, в котором вы установите URL базы данных, основанный на конфигурации БД Drupal:

1
2
3
4
5
6
7
// config/packages/drupal.php

// импортировать конфигурацию Drupal
include_once('/path/to/drupal/sites/default/settings.php');

// установить параметр app.database_url
$container->setParameter('app.database_url', $db_url);

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.