bangpound/callable-compiler-pass

Create compiler passes in Symfony without defining another class

1.0.0 2016-03-11 01:49 UTC

This package is auto-updated.

Last update: 2024-04-12 02:48:40 UTC


README

Use this implementation of CompilerPassInterface to create compiler passes in Symfony without defining another class.

Usage

You should use this class wherever you instantiate a container compiler pass to modify the Symfony dependency injection container. For typical Symfony applications, this happens in a bundle.

Without CallableCompilerPass, your bundle class would add the compiler pass this way:

<?php
namespace My\Bundle\CoolBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use My\Bundle\CoolBundle\DependencyInjection\Compiler\AddMyStuffPass;

class MyCoolBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

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

With CallableCompilerPass, you can skip creating the AddMyTaggedServicesPass and define the compiler pass in the bundle's build method:

<?php
namespace My\Bundle\CoolBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Bangpound\Symfony\DependencyInjection\CallableCompilerPass;

class MyCoolBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->addCompilerPass(new CallableCompilerPass(
            function (ContainerBuilder $container) {
                if (!$container->has('my_cool.service')) {
                    return;
                }

                $definition = $container->findDefinition('my_cool.service');

                $taggedServices = $container->findTaggedServiceIds(
                    'my_cool.service_addition'
                );

                foreach ($taggedServices as $id => $tags) {
                    $definition->addMethodCall(
                        'addThing', array(new Reference($id))
                    );
                }
            }
        ));
    }
}

The utility of the CallableCompilerPass is most apparent when developing a Symfony application with the new MicroKernelTrait in Symfony 2.8 and 3.0.

<?php

use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;

class AppKernel extends Kernel
{
    use MicroKernelTrait;

    public function registerBundles()
    {
        $bundles = array(
            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
        );

        return $bundles;
    }

    protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
    {
        $c->addCompilerPass(new CallableCompilerPass(function (ContainerBuilder $container) {
            if (!$container->has('my_cool.service')) {
                return;
            }

            $definition = $container->findDefinition('my_cool.service');

            $taggedServices = $container->findTaggedServiceIds(
                'my_cool.service_addition'
            );

            foreach ($taggedServices as $id => $tags) {
                $definition->addMethodCall(
                    'addThing', array(new Reference($id))
                );
            }
        });
    }
}

In the microkernel, you might also use CallableCompilerPass to remove services you do not need but which are added by the Symfony FrameworkBundle by default, for example.