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

Как работать с тегами сервисов

Теги сервисов - это способ сообщить Symfony или другим сторонним пакетам, что ваш сервис должен быть зарегистрирован каким-то особым образом. Возьмите следующий пример:

  • YAML
    1
    2
    3
    4
    # config/services.yaml
    services:
        App\Twig\AppExtension:
            tags: ['twig.extension']
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Twig\AppExtension">
                <tag name="twig.extension"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Twig\AppExtension;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(AppExtension::class)
            ->tag('twig.extension');
    };
    

Сервисы, с тегом twig.extension собираются во время инициализации TwigBundle и добавляются в Twig как расширения.

Другие теги используются для интеграции ваших сервисов в другие системы. Чтобы увидеть все доступные теги в базовом фреймворке Symfony, посмотрите Built-in Symfony Service Tags. Каждый из них имеет разные эффект на ваш сервис, и многие теги требуют дополнительных аргументов (кроме параметра name).

Для большинства пользователей - это всё, что вам нужно знать. Если вы хотите углубиться в изучение того, как создать ваши собственные пользовательские теги, продолжайте читать.

Автоконфигурация тегов

Если вы включили автоконфигурацию, тогда некоторые теги применяются для вас автоматически. Это так для тега twig.extension: контейнер видит, что ваш клас расширяет AbstractExtension (точнее, реализует ExtensionInterface), и добавляет тег для вас.

Если вы хотите применять теги автоматически для ваших собственных сервисов, используйте опцию _instanceof:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # config/services.yaml
    services:
        # эта конфигурация применяется только к сервисам, созданным этим файлом
        _instanceof:
            # сервисы, классы которых являются экземплярами CustomInterface будут тегированы автоматически
            App\Security\CustomInterface:
                tags: ['app.custom_tag']
        # ...
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    <!-- 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 https://symfony.com/schema/dic/services/services-1.0.xsd">
        <services>
            <!-- эта конфигурация применяется только к сервисам, созданным этим файлом -->
            <instanceof id="App\Security\CustomInterface" autowire="true">
                <!-- сервисы, классы которых являются экземплярами CustomInterface будут тегированы автоматически -->
                <tag name="app.custom_tag"/>
            </instanceof>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Security\CustomInterface;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        // эта конфигурация применяется только к сервисам, созданным этим файлом
        $services
            ->instanceof(CustomInterface::class)
                // сервисы, классы которых являются экземплярами CustomInterface будут тегированы автоматически
                ->tag('app.custom_tag');
    };
    

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

В приложении Symfony, вызовите этот метод в вашем классе ядра:

// src/Kernel.php
class Kernel extends BaseKernel
{
    // ...

    protected function build(ContainerBuilder $container): void
    {
        $container->registerForAutoconfiguration(CustomInterface::class)
            ->addTag('app.custom_tag')
        ;
    }
}

В пакете Symfony, вызовите этот метод в методе load() класса расширения пакета:

// src/DependencyInjection/MyBundleExtension.php
class MyBundleExtension extends Extension
{
    // ...

    public function load(array $configs, ContainerBuilder $container): void
    {
        $container->registerForAutoconfiguration(CustomInterface::class)
            ->addTag('app.custom_tag')
        ;
    }
}

Создание пользовательских тегов

Теги сами по себе не изменяют функциональность ваших сервисов каким-либо образом. Но если вы захотите, вы можете попросить у строителя контейнера список всех сервисов, которые были тегированы каким-то конкретным тегом. Это полезно в пропусках компилятора, где вы можете найти эти сервисы и использовать либо изменять их каким-либо образом.

Например, если вы используете Swift Mailer, то вы можете представить, что вы хотите реализовать “транспортную цепочку”, которая является коллекцией классов, реализующих \Swift_Transport. Используя цепочку, вы захотите, чтобы Swift Mailer попробовал несколько способов передачи сообщения, пока один из них не сработает.

Для начала, определите класс TransportChain:

// src/Mail/TransportChain.php
namespace App\Mail;

class TransportChain
{
    private $transports;

    public function __construct()
    {
        $this->transports = [];
    }

    public function addTransport(\Swift_Transport $transport): void
    {
        $this->transports[] = $transport;
    }
}

Затем, определите цепочку как сервис:

  • YAML
    1
    2
    3
    # config/services.yaml
    services:
        App\Mail\TransportChain: ~
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Mail\TransportChain"/>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Mail\TransportChain;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(TransportChain::class);
    };
    

Определеите сервисы с пользовательским тегом

Теперь вы можете захотеть, чтобы несколько из классов \Swift_Transport были инстанциированы и добавлены в цепочку автоматически, используя метод addTransport(). Например, вы можете добавить следующие транспорты как сервисы:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # config/services.yaml
    services:
        Swift_SmtpTransport:
            arguments: ['%mailer_host%']
            tags: ['app.mail_transport']
    
        Swift_SendmailTransport:
            tags: ['app.mail_transport']
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="Swift_SmtpTransport">
                <argument>%mailer_host%</argument>
    
                <tag name="app.mail_transport"/>
            </service>
    
            <service id="Swift_SendmailTransport">
                <tag name="app.mail_transport"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(\Swift_SmtpTransport::class)
            // the param() method was introduced in Symfony 5.2.
            ->args([param('mailer_host')])
            ->tag('app.mail_transport')
        ;
    
        $services->set(\Swift_SendmailTransport::class)
            ->tag('app.mail_transport')
        ;
    };
    

Заметьте, что каждому сервису был предоставлен тег под названием app.mail_transport. Это пользовательский тег, который вы будете использовать в вашем пропуске компилятора. Пропуск компилятора - это то, что придаёт этому тегу какой-то “смысл”.

Создайте пропуск компилятора

Теперь вы можете использовать пропуск компилятора, чтобы запросить у контейнера любые сервисы с тегом app.mail_transport:

// src/DependencyInjection/Compiler/MailTransportPass.php
namespace App\DependencyInjection\Compiler;

use App\Mail\TransportChain;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class MailTransportPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        // всегда вначале проверяйте, определён ли первичный сервис
        if (!$container->has(TransportChain::class)) {
            return;
        }

        $definition = $container->findDefinition(TransportChain::class);

        // найти все ID сервисов с тегом app.mail_transport tag
        $taggedServices = $container->findTaggedServiceIds('app.mail_transport');

        foreach ($taggedServices as $id => $tags) {
            // добавьте транспортный сервис в сервис ChainTransport
            $definition->addMethodCall('addTransport', [new Reference($id)]);
        }
    }
}

Зарегистрируйте пропуск в контейнере

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

// src/Kernel.php
namespace App;

use App\DependencyInjection\Compiler\MailTransportPass;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
// ...

class Kernel extends BaseKernel
{
    // ...

    protected function build(ContainerBuilder $container): void
    {
        $container->addCompilerPass(new MailTransportPass());
    }
}

Tip

При реализации CompilerPassInterface в расширении сервиса, вам не нужно регистрировать его. Смотрите документацию компонентов, чтобы узнать больше информации.

Добавление дополнительных атрибутов в тег

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

Для начала, измените класс TransportChain:

class TransportChain
{
    private $transports;

    public function __construct()
    {
        $this->transports = [];
    }

    public function addTransport(\Swift_Transport $transport, $alias): void
    {
        $this->transports[$alias] = $transport;
    }

    public function getTransport($alias): ?\Swift_Transport
    {
        if (array_key_exists($alias, $this->transports)) {
            return $this->transports[$alias];
        }

        return null;
    }
}

Как вы видите, когда вызывается addTransport(), требуется не только объект Swift_Transport, но также дополнительное имя строки для этого транспорта. Тогда как вы можете разрешить каждому тегированному транспортному сервису также снабжать дополнительное имя?

Чтобы ответить на этот вопрос, измените объявление сервиса:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    # config/services.yaml
    services:
        Swift_SmtpTransport:
            arguments: ['%mailer_host%']
            tags:
                - { name: 'app.mail_transport', alias: 'smtp' }
    
        Swift_SendmailTransport:
            tags:
                - { name: 'app.mail_transport', alias: 'sendmail' }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="Swift_SmtpTransport">
                <argument>%mailer_host%</argument>
    
                <tag name="app.mail_transport" alias="smtp"/>
            </service>
    
            <service id="Swift_SendmailTransport">
                <tag name="app.mail_transport" alias="sendmail"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(\Swift_SmtpTransport::class)
            // the param() method was introduced in Symfony 5.2.
            ->args([param('mailer_host')])
            ->tag('app.mail_transport', ['alias' => 'smtp'])
        ;
    
        $services->set(\Swift_SendmailTransport::class)
            ->tag('app.mail_transport', ['alias' => 'sendmail'])
        ;
    };
    

Tip

В формате YAML, вы можете представить тег в качестве простой строки, если вам не нужно указывать дополнительные атрибуты. Следующие определения являются эквивалентными.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# config/services.yaml
services:
    # Compact syntax
    Swift_SendmailTransport:
        class: \Swift_SendmailTransport
        tags: ['app.mail_transport']

    # Verbose syntax
    Swift_SendmailTransport:
        class: \Swift_SendmailTransport
        tags:
            - { name: 'app.mail_transport' }

Заметьте, что вы добавили общий ключ alias к тегу. Чтобы действительно использовать его, обновите компилятор:

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class TransportCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        // ...

        foreach ($taggedServices as $id => $tags) {

            // сервис может иметь один и тот же тег дважды
            foreach ($tags as $attributes) {
                $definition->addMethodCall('addTransport', [
                    new Reference($id),
                    $attributes['alias']
                ]);
            }
        }
    }
}

Двойной цикл может быть запутанным. Это потому, что сервис может иметь больше одного тега. Вы тегируете сервис дважды или более с помощью тега app.mail_transport. Второй цикл foreach повторяет набор тегов app.mail_transport для текущего сервиса и даёт вам атрибуты.

Ссылайтесь на тегированные сервисы

Symfony предоставляет сокращение для внедрения всех сервисов, тегированных конкретным тегом, что частно нужно в некоторых приложениях, чтобы вам не нужно было подключать пропуск компилятора только для этого.

В следующем примере все сервисы, тегированные app.handler передаются как первый аргумент конструктора сервису App\HandlerCollection:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    # config/services.yaml
    services:
        App\Handler\One:
            tags: ['app.handler']
    
        App\Handler\Two:
            tags: ['app.handler']
    
        App\HandlerCollection:
            # внедрить все сервисы, тегированные app.handler в качестве первого аргумента
            arguments:
                - !tagged_iterator app.handler
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Handler\One">
                <tag name="app.handler"/>
            </service>
    
            <service id="App\Handler\Two">
                <tag name="app.handler"/>
            </service>
    
            <service id="App\HandlerCollection">
                <!-- внедрить все сервисы, тегированные app.handler в качестве первого аргумента -->
                <argument type="tagged_iterator" tag="app.handler"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(App\Handler\One::class)
            ->tag('app.handler')
        ;
    
        $services->set(App\Handler\Two::class)
            ->tag('app.handler')
        ;
    
        $services->set(App\HandlerCollection::class)
            // внедрить все сервисы, тегированные app.handler в качестве первого аргумента
            ->args([tagged_iterator('app.handler')])
        ;
    };
    

После компиляции, сервис HandlerCollection имеет возможность итерировать поверх ваших обработчиков приложения:

// src/HandlerCollection.php
namespace App;

class HandlerCollection
{
    public function __construct(iterable $handlers)
    {
    }
}

See also

Смотрите также тегированные сервисы локатора

Тегированные сервисы с приоритетностью

Тегированные сервисы могуть быть приоритизированы с использованием атрибута priority. Приоритетность - это положительное или отрицательное целое число. Чем выше число, тем раньше будет найден тегированный сервис в коллекции:

  • YAML
    1
    2
    3
    4
    5
    # config/services.yaml
    services:
        App\Handler\One:
            tags:
                - { name: 'app.handler', priority: 20 }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Handler\One">
                <tag name="app.handler" priority="20"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Handler\One;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(One::class)
            ->tag('app.handler', ['priority' => 20])
        ;
    };
    

Другой опцией. которая особенно полезна при использовании автоконфигурации тегов, является реализация статического метода getDefaultPriority() в самом сервисе:

// src/Handler/One.php
namespace App\Handler;

class One
{
    public static function getDefaultPriority(): int
    {
        return 3;
    }
}

Если вы хотите иметь другой метод, определяющие приоритетность (например, getPriority() вместо getDefaultPriority()), вы можете определить его в конфигурации сервиса сбора:

  • YAML
    1
    2
    3
    4
    5
    6
    # config/services.yaml
    services:
        App\HandlerCollection:
            # внедрить все сервисы с тегом app.handler в качестве первого аргумента
            arguments:
                - !tagged_iterator { tag: app.handler, default_priority_method: getPriority }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
        <services>
            <service id="App\HandlerCollection">
                <argument type="tagged_iterator" tag="app.handler" default-priority-method="getPriority"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
    
    return function (ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        // ...
    
        $services->set(App\HandlerCollection::class)
            ->args([
                tagged_iterator('app.handler', null, null, 'getPriority'),
            ])
        ;
    };
    

Тегированные сервисы с индексом

Если вы хотите извлечь конкретный сервис из внедренной коллекции, вы можете использовать опции index_by и default_index_method аргумента, в сочетании с !tagged_iterator.

Используя предыдущий пример, эта конфигурация сервиса создает коллекцию, проиндексированную по атрибуту key:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    # config/services.yaml
    services:
        App\Handler\One:
            tags:
                - { name: 'app.handler', key: 'handler_one' }
    
        App\Handler\Two:
            tags:
                - { name: 'app.handler', key: 'handler_two' }
    
        App\HandlerCollection:
            arguments: [!tagged_iterator { tag: 'app.handler', index_by: 'key' }]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Handler\One">
                <tag name="app.handler" key="handler_one"/>
            </service>
    
            <service id="App\Handler\Two">
                <tag name="app.handler" key="handler_two"/>
            </service>
    
            <service id="App\HandlerCollection">
                <argument type="tagged_iterator" tag="app.handler" index-by="key"/>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Handler\One;
    use App\Handler\Two;
    use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
    
    return function (ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(One::class)
            ->tag('app.handler', ['key' => 'handler_one']);
    
        $services->set(Two::class)
            ->tag('app.handler', ['key' => 'handler_two']);
    
        $services->set(App\HandlerCollection::class)
            ->args([
                // 2nd argument is the index attribute name
                tagged_iterator('app.handler', 'key'),
            ])
        ;
    };
    

После компиляции, HandlerCollection может итерировать поверх ваших обработчиков приложения. Чтобы извлечь конкретный сервис из итератора, вызовите функцию iterator_to_array(), а затем используйте атрибут key, чтобы получить элемент массива. Например, чтобы извлечь обработчик handler_two:

// src/Handler/HandlerCollection.php
namespace App\Handler;

class HandlerCollection
{
    public function __construct(iterable $handlers)
    {
        $handlers = $handlers instanceof \Traversable ? iterator_to_array($handlers) : $handlers;

        $handlerTwo = $handlers['handler_two'];
    }
}

Tip

Как и с приоритетностью, вы можете также реализовать статический метод getDefaultIndexName() в обработчиках и опустить атрибут индекса (key):

// src/Handler/One.php
namespace App\Handler;

class One
{
    // ...
    public static function getDefaultIndexName(): string
    {
        return 'handler_one';
    }
}

Вы также можете определить имя статического метода, реализуемого в каждом сервисе, с помощью атрибута default_index_method в тегированном аргументе:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    # config/services.yaml
    services:
        # ...
    
        App\HandlerCollection:
            # используйте getIndex() вместо getDefaultIndexName()
            arguments: [!tagged_iterator { tag: 'app.handler', default_index_method: 'getIndex' }]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- 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
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <!-- ... -->
    
            <service id="App\HandlerCollection">
                <!-- используйте getIndex() вместо getDefaultIndexName() -->
                <argument type="tagged_iterator"
                    tag="app.handler"
                    default-index-method="someFunctionName"
                />
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\HandlerCollection;
    use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
    
    return function (ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        // ...
    
        // используйте getIndex() вместо getDefaultIndexName()
        $services->set(HandlerCollection::class)
            ->args([
                tagged_iterator('app.handler', null, 'getIndex'),
            ])
        ;
    };
    

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