Как работать с передачами компилятора

Дата обновления перевода 2025-02-15

Как работать с передачами компилятора

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

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

Для этого заставьте ваше ядро реализовывать CompilerPassInterface и добавьте код передачи компилятора внутри метода process():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// src/Kernel.php
namespace App;

use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel implements CompilerPassInterface
{
    use MicroKernelTrait;

    // ...

    public function process(ContainerBuilder $container): void
    {
        // в этом методе вы можете манипулировать сервис-контейнером:
        // например, изменение какого-то сервис-контейнера:
        $container->getDefinition('app.some_private_service')->setPublic(true);

        // или обработка тегированного сервиса:
        foreach ($container->findTaggedServiceIds('some_tag') as $id => $tags) {
            // ...
        }
    }
}

Если вы создаете отдельные классы передачи компилятора, включите их в методе ядра приложения build():

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

use App\DependencyInjection\Compiler\CustomPass;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    // ...

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

Работа с передачами компилятора в пакетах

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

CompilerPassInterface и поместите код передачи компилятора внутри метода основного класса пакета process():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/MyBundle/MyBundle.php
namespace App\MyBundle;

use App\DependencyInjection\Compiler\CustomPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class MyBundle extends AbstractBundle
{
    public function process(ContainerBuilder $container): void
    {
        // в этом методе вы можете манипулировать сервис-контейнером:
        // например, изменение какого-то сервис-контейнера:
        $container->getDefinition('app.some_private_service')->setPublic(true);

        // или обработка тегированного сервиса:
        foreach ($container->findTaggedServiceIds('some_tag') as $id => $tags) {
            // ...
        }
    }
}

Альтернативно, при использовании отдельных классов передачи компилятора , пакеты могут включить их в методе build() своего главного класса пакета:

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

use App\DependencyInjection\Compiler\CustomPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class MyBundle extends AbstractBundle
{
    public function build(ContainerBuilder $container): void
    {
        parent::build($container);

        $container->addCompilerPass(new CustomPass());
    }
}

Если вы используете пользовательские теги сервиса в пакете, тогда, по соглашению, имена тегов состоят из имени пакета (нижний регистр, нижние подчеркивания в качестве разделителей), за которым следует точка, и, наконец, "настоящее" имя. Например, если вы хотите представить какой-то вид тега "транспорту" в вашем AcmeMailerBundle, вам следует назвать его acme_mailer.transport.