Как сконфигурировать сервис с помощью конфигуратора

Как сконфигурировать сервис с помощью конфигуратора

Конфигуратор сервиса - это функция сервис-контейнера, которая позволяет вам использовать вызываемое, чтобы сконфигурировать сервис после его инстанциирования.

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

Ещё один пример использования - когда у вас есть множество объектов, которые совместно используют общую конфигурацию, или которые должны быть похожим образом сконфигурированы во время прогона.

Например, представьте, что у вас есть приложение, где вы оправляtnt разные виды электронных писем пользователям. Письма пропускаются через различные программы форматирования, которые могут быть включены или нет, в зависимости от некоторых динамических установок приложения. Вы начинаете определять класс NewsletterManager таким образом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/AppBundle/Mail/NewsletterManager.php
namespace AppBundle\Mail;

class NewsletterManager implements EmailFormatterAwareInterface
{
    private $enabledFormatters;

    public function setEnabledFormatters(array $enabledFormatters)
    {
        $this->enabledFormatters = $enabledFormatters;
    }

    // ...
}

а также класс GreetingCardManager:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/AppBundle/Mail/GreetingCardManager.php
namespace AppBundle\Mail;

class GreetingCardManager implements EmailFormatterAwareInterface
{
    private $enabledFormatters;

    public function setEnabledFormatters(array $enabledFormatters)
    {
        $this->enabledFormatters = $enabledFormatters;
    }

    // ...
}

Как упоминалось ранее, целью являетя установить программы форматирования во время прогона, в зависимости от настроек приложения. Чтобы сделать это, у вас также есть класс EmailFormatterManager, который отвечает за загрузку и валидацию программ форматирования, включённых в приложении:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// src/AppBundle/Mail/EmailFormatterManager.php
namespace AppBundle\Mail;

class EmailFormatterManager
{
    // ...

    public function getEnabledFormatters()
    {
        // код для конфигурации того, какие программы форматирования использовать
        $enabledFormatters = array(...);

        // ...

        return $enabledFormatters;
    }
}

Если вашей целью является избежать объединения NewsletterManager и GreetingCardManager с EmailFormatterManager, то вы можете захотеть создать класс конфигуратора для конфигурирования этих экземпляров:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// src/AppBundle/Mail/EmailConfigurator.php
namespace AppBundle\Mail;

class EmailConfigurator
{
    private $formatterManager;

    public function __construct(EmailFormatterManager $formatterManager)
    {
        $this->formatterManager = $formatterManager;
    }

    public function configure(EmailFormatterAwareInterface $emailManager)
    {
        $emailManager->setEnabledFormatters(
            $this->formatterManager->getEnabledFormatters()
        );
    }

    // ...
}

Работа EmailConfigurator - внедрять включённые программы форматирования в NewsletterManager и GreetingCardManager, потому что они не знают, откуда появились включённые программы форматирования. С другой стороны, EmailFormatterManager содержит данные о включенных программах форматирования и о том, как их загружать, поддерживая единый принцип ответственности.

Tip

В то время, как этот пример использует метод PHP-класса, конфигураторы могут быть любым PHP-вызываемым, включая функции, статические методы и методы сервисов.

Исползование конфигуратора

Вы можете сконфигурировать конфигуратор сервиса, используя опцию configurator. Если вы используете конфигурацию services.yml по умолчанию, то все классы уже загружены как сервисы. Всё, что вам нужно сделать, это точно определить configurator:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    # app/config/services.yml
    services:
        # ...
    
        # Регистрирует все 4 класса как сервисы, включая AppBundle\Mail\EmailConfigurator
        AppBundle\:
            resource: '../../src/AppBundle/*'
            # ...
    
        # переопределить сервисы, чтобы установить конфигуратор
        AppBundle\Mail\NewsletterManager:
            configurator: 'AppBundle\Mail\EmailConfigurator:configure'
    
        AppBundle\Mail\GreetingCardManager:
            configurator: 'AppBundle\Mail\EmailConfigurator:configure'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- app/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">
    
        <services>
            <prototype namespace="AppBundle\" resource="../../src/AppBundle/*" ... />
    
            <service id="AppBundle\Mail\NewsletterManager">
                <configurator service="AppBundle\Mail\EmailConfigurator" method="configure" />
            </service>
    
            <service id="AppBundle\Mail\GreetingCardManager">
                <configurator service="AppBundle\Mail\EmailConfigurator" method="configure" />
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // app/config/services.php
    use AppBundle\Mail\EmailConfigurator;
    use AppBundle\Mail\EmailFormatterManager;
    use AppBundle\Mail\GreetingCardManager;
    use AppBundle\Mail\NewsletterManager;
    use Symfony\Component\DependencyInjection\Reference;
    
    // ...
    $container->autowire(EmailFormatterManager::class);
    $container->autowire(EmailConfigurator::class);
    
    $container->autowire(NewsletterManager::class)
        ->setConfigurator(array(new Reference(EmailConfigurator::class), 'configure'));
    
    $container->autowire(GreetingCardManager::class)
        ->setConfigurator(array(new Reference(EmailConfigurator::class), 'configure'));
    

New in version 3.2: Синтаксис service_id:method_name для конфигурации формата YAML был представлен в Symfony 3.2.

Традиционный синтаксис конфигуратора в YAML-файлах использовал массив, чтобы определить id сервиса и имя метода:

1
2
3
4
5
app.newsletter_manager:
    # новый синтаксис
    configurator: 'AppBundle\Mail\EmailConfigurator:configure'
    # старый синтаксис
    configurator: ['@AppBundle\Mail\EmailConfigurator', configure]

Вот и всё! При запрашивании сервиса AppBundle\Mail\NewsletterManager или AppBundle\Mail\GreetingCardManager, созданный экземпляр вначале будет передан в метод EmailConfigurator::configure().

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