在Symfony ChoiceType中显示标记的服务

时间:2016-07-27 12:48:49

标签: php symfony symfony-forms

我实现了一个系统,让管理员从表单中配置一些其他行为(实际上是Symfony Services)。目前我使用的是EntityType,以便让 admin 从数据库中的表中选择一个或多个服务。

$builder->add('services', EntityType::class, array(
'class' => 'AppBundle:Services',
'multiple' => true,
));

但是由于我在 Symfony 本身注册服务,我只是觉得应该有办法从容器(或类似的)获取服务并创建一个新的 ServiceTagType < / em>所以我不必在data baseservices.yml中添加它们,我可以这样做:

$builder->add('services', ServiceTagType::class, array(
'tag' => 'some.service.tag',
'multiple' => true,
));

在这里和那里读到我发现你可以标记服务,但是在编译容器时你只能获得标记服务列表 ...我是努力寻找解决方法但是没有用。

1 个答案:

答案 0 :(得分:2)

首先,您必须创建 ServiceTagType (我假设它会扩展ChoiceType而不是EntityType):

如何创建自定义类型({3}}。

// src/AppBundle/Form/Type/ServiceTagType.php
namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

class ServiceTagType extends AbstractType
{
    private $tags;

    public function setTags($tags)
    {
        $this->tags = $tags;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'choices' => $this->tags
        ));
    }

    public function getParent()
    {
        return ChoiceType::class;
    }
}

ServiceTagType 注册为服务(因为您需要提供带有here的代码)

# services.yml
app.form_type.service_tag:
    class: AppBundle\Form\Type\ServiceTagType
    tags:
        - { name: form.type }

然后,正如Bourvill建议的那样,您可以在setter injection中收集代码。

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

class TagsCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->has('app.form_type.service_tag')) {
            return;
        }

        $definition = $container->findDefinition(
            'app.form_type.service_tag'
        );

        $taggedServicesIds = array_keys($container->findTaggedServiceIds(
            'app.tagged_for_service_tag_type'
        ));

        $taggedServices = array_fill_keys($taggedServicesIds ,$taggedServicesIds);

        $definition->addMethodCall('setTags',$taggedServices );
    }
}

不要忘记Compiler pass

在FullStack框架中注册CompilerPass:

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

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