Получение списка помеченных сервисов в моем контроллере

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

Итак, я создал две службы со своим настраиваемым тегом fbeen.admin

Вот они:

services:
    app.test:
        class: AppBundle\Admin\TestAdmin
        tags:
            - { name: fbeen.admin }

    fbeen.admin.test:
        class: Fbeen\AdminBundle\Admin\TestAdmin
        tags:
            - { name: fbeen.admin }

Теперь я хочу использовать все службы с тегом fbeen.admin в моем контроллере, но не знаю как.

Я следовал руководству Как работать с сервисными тегами, но застрял на этом правиле:

$definition->addMethodCall('addTransport', array(new Reference($id)));

Каким-то образом следует вызвать метод addTransport класса TransportChain, но кажется, что он не был вызван.

И даже если бы он был вызван, у меня все еще нет списка служб с тегом fbeen.admin в моем контроллере.

Я уверен, что что-то упускаю, но кто может мне объяснить, что это такое?

p.s. Я знаю, что compilerPass запускается во время сборки, но, например, администратор sonata знает все классы администратора, а twig знает все расширения twig. Как они узнали?

Спасибо за чтение этого :-)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
0
798
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Здесь следует отметить следующее: CompilerPass не запускает addTransport (или как вы его называете) в самом проходе компилятора - просто говорит: «Когда настало время - запустите класс $definition->addTransport(...) с этими данными». . Место, где это происходит, следует искать в каталоге кэша (grep -R TransportChain var/cache/), где он устанавливает $transportChain->addTransport(...).

Когда вы впервые используете эту службу, данные заполняются только тогда, когда класс создается из контейнера.

Спасибо, Алистер, а как теперь читать необходимые данные из кеша?

Frank B 22.05.2018 01:30

Вызовы addTransport() (или как вы хотите его назвать) будут происходить при создании экземпляра службы - когда вы используете ее через container-> get (...) или автоматически подключаете в конструкторе или службе контроллера. и поэтому данные будут доступны из любого места, где они были сохранены.

Alister Bulman 22.05.2018 13:06
Ответ принят как подходящий

Symfony 3.3

Контейнер компилируется один раз (чаще при отладке, а в продакшене только один раз). С addMethodCall... вы управляете тем, что как только вы запрашиваете сервис из контейнера, который вы храните в $definition (в данном случае это контроллер). Затем контейнер вызовет метод addMethodCall('method'.. во время инициализации вашей службы.

Как это будет выглядеть в контейнере:

// This is pseudo content of compiled container
$service = new MyController();
// This is what compiler pass addMethodCall will add, now its your 
// responsibility to implement method addAdmin to store admins in for 
// example class variable. This is as well way which sonata is using
$service->addAdmin(new AppBundle\Admin\TestAdmin());
$service->addAdmin(new AppBundle\Admin\TestAdmin());

return $service; // So you get fully initialized service

Symfony 3.4+

Что вы можете сделать:

// Your services.yaml
services:
    App/MyController/WantToInjectSerivcesController:
        arguments:
            $admins: !tagged fbeen.admin

// Your controller
class WantToInjectSerivcesController {
    public function __construct(iterable $admins) {
        foreach ($admins as $admin) {
            // you hot your services here
        }
    }
}

Бонусная автоматическая пометка ваших услуг. Допустим, все ваши контроллеры реализуют интерфейс AdminInterface.

// In your extension where you building container or your kernel build method
$container->registerForAutoconfiguration(AdminInterface::class)->addTag('fbeen.admin');

Это автоматически пометит все сервисы, реализующие ваш интерфейс, тегом. Таким образом, вам не нужно явно устанавливать тег.

Тег! Доступен в Symfony 3.4+.

Alister Bulman 22.05.2018 13:03

Извините, пропустил вашу версию Symfony, добавлено объяснение для 3.3

M. Kebza 22.05.2018 13:25

Это сработало для меня:

расширите класс TransportChain с помощью метода getTransports:

public function getTransports()
{
    return $this->transports;
}

и используйте службу TransportChain в моем контроллере:

use AppBundle\Mail\TransportChain;

$transportChain = $this->get(TransportChain::class);
$transports = $transportChain->getTransports();
// $transports is now an array with all the tagged services

Спасибо Алистер Булман за то, что подтолкнули меня вперед :-)

Другие вопросы по теме