Распакуйте Symfony с меткой Сервисы - PullRequest
0 голосов
/ 20 декабря 2018

Я получил класс, который принимает несколько реализаций Consumer в качестве аргументов конструктора.

Я хочу "заполнить" всех моих Потребителей через DI-контейнер Symfony.Я пробовал сервисы с тегами внедрения.

final class SynchronousMessageDispatcher implements MessageDispatcher
{
    /**
     * @var Consumer[]
     */
    private $consumers;

    public function __construct(Consumer ...$consumers)
    {
        $this->consumers = $consumers;
    }
}

Поэтому я попытался пометить сервисы в services.yml следующим образом:

services:
    _instanceof:
        EventSauce\EventSourcing\Consumer:
            tags: ['eventsauce.consumer']

А затем внедрить его так:

eventsauce.message_dispatcher:
    class: EventSauce\EventSourcing\SynchronousMessageDispatcher
    arguments: [!tagged eventsauce.consumer]

Теперь я получаю следующую ошибку:

Аргумент 1 передан в EventSauce \ EventSourcing \ SynchronousMessageDispatcher :: __ construct () должен реализовывать интерфейс EventSauce \ EventSourcing \ Consumer, экземпляр Symfony \Компонент \ DependencyInjection \ Argument \ RewindableGenerator предоставлен

Я полностью понимаю, почему.Есть ли способ распаковать сервисы

Другими словами: можно ли как-то изменить [!tagged eventsauce.consumer].Или синтаксис ...$consumers несовместим с сервисом Tagged Injection в Symfony.

Не поймите меня неправильно.Я знаю, что могу легко реализовать MessageDispatcher сам.Просто хотел знать; -)

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Мое оригинальное решение :

Как упоминал "Tomáš Votruba", вам придется переписать свою собственную !tagged функциональность.например, !tagged-variadic.

Это не стоит усилий для меня.Я предпочел бы реализовать класс, используя iteratable («nifr» объяснил преимущества, спасибо).

Для дальнейшего чтения есть закрытая проблема по symfony / symfony # 23608

Мое новое решение

Я использовал Распаковка аргумента и шаблон делегирования , чтобы использовать класс, предоставляемый библиотекой с моимпомеченные услуги.

Работа :-) Ура.

final class TaggedMessageDispatcher implements MessageDispatcher {
    public function __construct(iterable $consumers)
    {
        $this->dispatcher = new SynchronousMessageDispatcher(... $consumers);
    }

    public function dispatch(Message ...$messages): void
    {
        $this->dispatcher->dispatch(... $messages);
    }
}
0 голосов
/ 21 декабря 2018

Вы используете неправильную подсказку здесь.

С синтаксисом [!tagged <tag>] будет введен один iterable, а не неопределенное количество аргументов, как ожидается оператором splat.

Вы на самом деле набираете текст для нескольких Consumer объектов в качестве аргументов с помощью оператора splat (...$arguments).

Итак, ответ на ваш вопрос: оператор splat несовместим с синтаксисом [!tagged ..].Вам действительно нужно написать свой собственный тип внедрения, который разделяет тегированные сервисы при использовании новой нотации, такой как [!tagged-call_user_func ..].

Тем не менее, на самом деле не имеет смысла собирать список объектов, извлекать их как аргументы функций, просто чтобы PHP снова поместил их в список.Я понимаю вашу идею с точки зрения чистоты кода.

Еще одним ограничением является то, что вы не можете передавать множественные переменные аргументы в функцию.Итак ...

public function __construct(Alpha ...$alphas, Beta ...$betas)

... невозможно.

Возможное решение / обходной путь, позволяющий сохранить типографский шрифт для коллекции, будет следующим:

final class SynchronousMessageDispatcher implements MessageDispatcher
{
    /**
     * @var Consumer[]
     */
    private $consumers;

    public function __construct(iterable $consumers)
    {
        foreach($consumers as $consumer) {
          assert($consumer instanceof Consumer, \InvalidArgumentException('..'));
        }

        $this->consumers = $consumers;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...