如何避免将attr应用于我选择字段的所有选项?

Chr*_*ris 5 php forms symfony symfony-2.7

在Symfony 2.7之前,字段的attrchoice仅应用于字段本身,即<select>呈现的元素.我用它来为这个元素应用类来设置它的样式.

在Symfony 2.7中,此行为已更改.现在,元素的所有<option><select>元素也获得相同的属性(提交更改),因此也获得类.


有些澄清,请将其作为代码:

<?php echo $view['form']->widget($form['myField'], ['attr' => ['class' => "text ui-widget-content ui-corner-all"]]); ?>
Run Code Online (Sandbox Code Playgroud)

然后这是Symfony <= 2.6的输出:

<select class="text ui-widget-content ui-corner-all" name="myField">
    <option value="1">Option 1</option>
    <option value="2">Option 2</option>
</select>
Run Code Online (Sandbox Code Playgroud)

这是Symfony> = 2.7的输出:

<select class="text ui-widget-content ui-corner-all" name="myField">
    <option value="1" class="text ui-widget-content ui-corner-all">Option 1</option>
    <option value="2" class="text ui-widget-content ui-corner-all">Option 2</option>
</select>
Run Code Online (Sandbox Code Playgroud)

我申请的类不适合<option>元素,因为它们定义了实际字段的边框等.请注意,这些是由jQuery UI定义的类,因此我无法轻松更改其定义.

避免将这些类应用于字段的所有<option>元素choice同时仍将其应用于元素的最简单方法是什么<select>

Chr*_*ris 5

感谢choice_attr@user2268997的评论,我找到了相关的博客文章Symfony 2.7 中新功能:选择表单类型重构,其中详细介绍了(截至目前未记录的)choice_attr选项的使用。

Symfony 似乎choice_attrattr渲染字段时将属性与 in 中的属性合并。这意味着我们需要覆盖class的属性choice_attr

我尝试在我定义的位置旁边的代码中执行此操作,attr但没有运气。看来您需要在表单类型定义中执行此操作。这是添加choice_attr选项后我的表单的摘录:

namespace MyBundle\Form;

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder
        ->add('roles',
            'entity',
            [
                'class' => 'MyBundle:Role',
                'choice_label' => 'name',
                'multiple' => true,
                'choice_attr' => function () { return ["class" => ""]; }
            ]);
}
Run Code Online (Sandbox Code Playgroud)

结果如我所愿。我可能还会将此重构为我自己的自定义表单类型,因此我不需要在我的包中重复它。


我现在决定创建一个choice具有上述所需行为的自定义类型,并在我的整个应用程序中使用该类型。

这是我选择的类型:

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

class ChoiceNoOptAttrType extends ChoiceType {
    public function configureOptions(OptionsResolver $resolver) {
        parent::configureOptions($resolver);

        $resolver->setDefault("choice_attr", function () { return ["class" => ""]; });
    }
}
Run Code Online (Sandbox Code Playgroud)

我不想重构我现有的所有表单以使用这种新类型,所以我选择用我的替换 Symfony 提供的选择类型。这可以通过修改choice表单类型的服务配置来实现。为此,我为我的包创建了一个编译器传递。

进一步阅读:创建编译器通行证

namespace MyBundle\DependencyInjection\Compiler;

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

class MyCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $definition = $container->getDefinition("form.type.choice");
        $definition->setClass('MyBundle\Form\ChoiceNoOptAttrType');
    }
}
Run Code Online (Sandbox Code Playgroud)

现在剩下要做的就是在包中注册编译器传递。

进一步阅读:如何使用捆绑中的编译器传递

namespace MyBundle;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use MyBundle\DependencyInjection\Compiler\MyCompilerPass;

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

        $container->addCompilerPass(new MyCompilerPass());
    }
}
Run Code Online (Sandbox Code Playgroud)

就是这样。现在我的所有choice字段都使用我的自定义类,以确保设置的 CSS 类attr不会传播到我的<option>元素。