如何在Symfony2中进行捆绑通信

时间:2013-03-27 10:33:59

标签: symfony structure bundle

我正在制作一个管理菜单包。我希望其他捆绑包能够将菜单项添加到捆绑包中,但我还希望在删除捆绑包时删除菜单项。最好的方法是什么?

我可以创建一个“重新生成管理菜单”操作,扫描所有包以查找某个YML,然后将其存储在缓存或数据库中。

有更好的方法吗?

1 个答案:

答案 0 :(得分:3)

您可以使用tags从其他捆绑包(甚至相同的捆绑包)中查找服务,并使用它们在compiler pass中从中构建菜单。

在此示例中,我假设您将菜单定义为服务(我将使用服务ID acme_menu.menu)。

// src/Acme/MenuBundle/DependencyInjection/Compiler/BuildMenuCompilerPass.php
namespace Acme\MenuBundle\DependencyInjection\Compiler;

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

class BuildMenuCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('acme_menu.menu')) {
            return;
        }

        $definition = $container->getDefinition('acme_menu.menu');

        $taggedServices = $container->findTaggedServiceIds('acme_menu.item');
        foreach ($taggedServices as $id => $attributes) {
            $definition->addMethodCall(
                'addMenuItem',
                array(new Reference($id))
            );
        }
    }
}

将其注册到菜单包中:

// src/Acme/MenuBundle/AcmeMenuBundle.php
namespace Acme\MenuBundle;

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

use Acme\MenuBundle\DependencyInjection\Compiler\BuildMenuCompilerPass;

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

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

标记为acme_menu.item的每个服务都将添加到菜单中 - 方法addMenuItem将在其创建的菜单上调用,标记服务作为参数。所以简单地定义:

# services.yml
services:
    acme_demo.menu.item1:
        # ...
        tags:
            - { name: acme_menu.item }
    acme_demo.menu.item2:
        # ...
        tags:
            - { name: acme_menu.item }