我实现了一个系统,让管理员从表单中配置一些其他行为(实际上是Symfony Services)。目前我使用的是EntityType,以便让 admin 从数据库中的表中选择一个或多个服务。
$builder->add('services', EntityType::class, array(
'class' => 'AppBundle:Services',
'multiple' => true,
));
但是由于我在 Symfony 本身注册服务,我只是觉得应该有办法从容器(或类似的)获取服务并创建一个新的 ServiceTagType < / em>所以我不必在data base
和services.yml
中添加它们,我可以这样做:
$builder->add('services', ServiceTagType::class, array(
'tag' => 'some.service.tag',
'multiple' => true,
));
在这里和那里读到我发现你可以标记服务,但是在编译容器时你只能获得标记服务列表 ...我是努力寻找解决方法但是没有用。
答案 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());
}
}