Files
archived-symfony-docs/service_container/compiler_passes.rst

127 lines
4.4 KiB
ReStructuredText

How to Work with Compiler Passes
================================
Compiler passes give you an opportunity to manipulate other
:doc:`service definitions </service_container/definitions>` that have been
registered with the service container.
.. _kernel-as-compiler-pass:
If your compiler pass is relatively small, you can define it inside the
application's ``Kernel`` class instead of creating a
:ref:`separate compiler pass class <components-di-separate-compiler-passes>`.
To do so, make your kernel implement :class:`Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface`
and add the compiler pass code inside the ``process()`` method::
// 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
{
// in this method you can manipulate the service container:
// for example, changing some container service:
$container->getDefinition('app.some_private_service')->setPublic(true);
// or processing tagged services:
foreach ($container->findTaggedServiceIds('some_tag') as $id => $tags) {
// ...
}
}
}
If you create separate compiler pass classes, enable them in the ``build()``
method of the application kernel::
// 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());
}
}
Working with Compiler Passes in Bundles
---------------------------------------
:doc:`Bundles </bundles>` can define compiler passes in the ``build()`` method of
the main bundle class (this is not needed when implementing the ``process()``
method in the extension)::
// 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
{
$container->addCompilerPass(new CustomPass());
}
}
If your compiler pass is relatively small, you can make the main bundle class implements
:class:`Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface` so that
it can add itself::
// src/MyBundle/MyBundle.php
namespace App\MyBundle;
use App\DependencyInjection\Compiler\CustomPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
class MyBundle extends AbstractBundle implements CompilerPassInterface
{
public function build(ContainerBuilder $container): void
{
$container->addCompilerPass($this);
}
public function process(ContainerBuilder $container): void
{
// in this method you can manipulate the service container:
// for example, changing some container service:
$container->getDefinition('app.some_private_service')->setPublic(true);
// or processing tagged services:
foreach ($container->findTaggedServiceIds('some_tag') as $id => $tags) {
// ...
}
}
}
If you are using custom :doc:`service tags </service_container/tags>` in a
bundle, the convention is to format tag names by starting with the bundle's name
in lowercase (using underscores as separators), followed by a dot, and finally
the specific tag name. For example, to introduce a "transport" tag in your
AcmeMailerBundle, you would name it ``acme_mailer.transport``.