Получение списка помеченных сервисов в моем контроллере - PullRequest
0 голосов
/ 22 мая 2018

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

Итак, я создал две сервисы с моим пользовательским тегом 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 в моем контроллере.

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

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

Спасибо, что прочитали это: -)

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

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');

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

0 голосов
/ 22 мая 2018

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

расширить класс 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

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

0 голосов
/ 22 мая 2018

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

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

...