Как загружать конфигурацию сервиса внутри пакета

Сервисы, созданные пакетами, не определяются в основном файле config/services.yaml, используемом приложением, а определяются в самих пакетах. Эта статья объясняет, как создавать и загружать такие файлы сервисов пакета.

Создание класса расширения

Для того, чтобы загружать конфигурацию сервисов, вам нужно создать Расширение внедрения зависимости (ВЗ) для вашего пакета. По умолчанию, класс Расширения должен следовать таким соглашениям (но позже вы узнаете, как их пропускать, если это необходимо):

  • Оно должно жить в пространстве имён DependencyInjection пакета;
  • Оно должно реализовывать ExtensionInterface, что обычно достигается путём расширения класса Extension ;
  • Имя равняется имени пакета с суффиксом Bundle, заменённым на Extension (например класс расширения AcmeBundle будет называться AcmeExtension, а AcmeHelloBundle - AcmeHelloExtension).

Вот как должно выглядеть расширение AcmeHelloBundle:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;

use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class AcmeHelloExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        // ... позднее вы будете загружать здесь файлы
    }
}

Ручная регистрация класса расширения

Если не следовать соглашениям, вам нужно будет вручную регистрировать ваше расширение. Чтобы сделать это, вам нужно переопределить метод Bundle::getContainerExtension(), чтобы он возвращал экземпляр расширения:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// ...
use Acme\HelloBundle\DependencyInjection\UnconventionalExtensionClass;

class AcmeHelloBundle extends Bundle
{
    public function getContainerExtension()
    {
        return new UnconventionalExtensionClass();
    }
}

Кроме того, если новое имя класса Расширения не следует соглашениям об именовании, вам также нужно переопределить метод Extension::getAlias(), чтобы он возвращал правильное дополнительное имя ВЗ. Дополнительное имя ВЗ - это имя, используемое для ссылки на пакет в контейнере (например, в файлах config/packages/). По умолчанию, это делается путём удаления суффикса Extension и преобразованя имени класса на нижние подчёркивания (например, дополнительное имя ВЗ AcmeHelloExtension - это acme_hello).

Использование метода load()

В методе load(), все сервисы и параметры относятся к загружаемому расширению. Этот метод получает не настоящий экземпляр контейнера, а копию. Контейнер имеет только параметры из настоящего контейнера. После загрузки сервисов и параметром, копия будет соединена с настоящим контейнером, чтобы убедитьс, что все сервисы и параметры также добавлены в него.

В методе load(), вы можете использовать PHP-код для регистрации определений сервиса, но чаще вы будете помещать эти определения в файл конфигурации (используя форматы YAML, XML или PHP).

Например, предположите, что у вас есть файл по имени services.xml в каталоге Resources/config/ вашего пакета, ваш метод load() выглядит так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\Config\FileLocator;

// ...
public function load(array $configs, ContainerBuilder $container)
{
    $loader = new XmlFileLoader(
        $container,
        new FileLocator(__DIR__.'/../Resources/config')
    );
    $loader->load('services.xml');
}

Другие доступные загрузчики - YamlFileLoader и PhpFileLoader.

Использование конфигурации для изменения сервисов

Расширение также является классом, которое занимается конфигурацией для этого конкретного пакета (например, конфигурация в config/packages/<bundle_alias>.yaml). Чтобы прочитать больше об этом, см. статью "How to Create Friendly Configuration for a Bundle" article.

Добавление классов для компиляции

Пакеты могут намекать Symfony о том, какие из их классов содержат аннотации, чтобы они были скомпилированы при генерировании кеша приложения для улучшения общей производительности. Определите список классов с аннотациями для компиляции в методе addAnnotatedClassesToCompile():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
use App\Manager\UserManager;
use App\Utils\Slugger;

// ...
public function load(array $configs, ContainerBuilder $container)
{
    // ...

    $this->addAnnotatedClassesToCompile(array(
        // you can define the fully qualified class names...
        'App\\Controller\\DefaultController',
        // ... but glob patterns are also supported:
        '**Bundle\\Controller\\',

        // ...
    ));
}

Note

Если какой-то класс расширяется из других классов, все его родители автоматически включаются в список классов для компиляции.

Схемы трансформируются в настоящие пространства имён классов, используя карту классов, сегенерированную Composer. Следовательно, до использования этих схем, вы должны сгенерировать полную карту классов, выполняющую команду Composer dump-autoload.

Caution

Эта техника не может быть использована, когда классы для компиляции используют константы __DIR__ или __FILE__, так как их значения будут изменяться при загрузке этих классов из файла classes.php.

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