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

Дата обновления перевода 2023-06-30

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

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

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

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

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

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

class NewsletterManager implements EmailFormatterAwareInterface
{
    private $enabledFormatters;

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

    // ...
}

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

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

class GreetingCardManager implements EmailFormatterAwareInterface
{
    private $enabledFormatters;

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

    // ...
}

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

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

class EmailFormatterManager
{
    // ...

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

        // ...

        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/Mail/EmailConfigurator.php
namespace App\Mail;

class EmailConfigurator
{
    private $formatterManager;

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

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

    // ...
}

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

Tip

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# config/services.yaml
services:
    # ...

    # Регистрирует все 4 класса как сервисы, включая App\Mail\EmailConfigurator
    App\:
        resource: '../src/*'
        # ...

    # переопределить сервисы, чтобы установить конфигуратор
    App\Mail\NewsletterManager:
        configurator: ['@App\Mail\EmailConfigurator', 'configure']

    App\Mail\GreetingCardManager:
        configurator: ['@App\Mail\EmailConfigurator', 'configure']

Сервисы можно конфигурировать с помощью вызываемых конфигураторов (заменяя метод configure() на __invoke()), опустив имя метода:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# config/services.yaml
services:
    # ...

    # регистрирует все классы как сервисы, включая App\Mail\EmailConfigurator
    App\:
        resource: '../src/*'
        # ...

    # переопределить сервисы, чтобы установить конфигуратор
    App\Mail\NewsletterManager:
        configurator: '@App\Mail\EmailConfigurator'

    App\Mail\GreetingCardManager:
        configurator: '@App\Mail\EmailConfigurator'

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