symfony 4 中的表单生成器和主题变量

Form builder and theming variables in symfony 4

有些情况下我的表单输入会有图标,有些则没有。最初,我以为我可以像这样将 class 放在表单生成器中:

$builder
        ->add('email', EmailType::class, [
            'label' => 'Email address',
            'attr' => [
                'placeholder' => 'john.smith@foo.com',
                'class' => 'has_icon icon_email'
            ],
            'constraints' => [
                new NotBlank([
                    'message' => 'Enter an email address.'
                ])
            ]
        ])

然后表单模板中的输出可能会采用 class 并重新配置外观。显然这行不通,但这是我前进的方向:

{% block form_row %}
    <div class="form_row">
        {{ form_label(form) }}
        {% if form.vars.attr.class == 'has_icon' %}
            test
        {% endif %}
        {{ form_errors(form) }}
    </div>
{% endblock form_row %}

这是正确的方法还是有其他更可靠的方法?


编辑 2019 年 9 月 22 日

我想做一个测试,这很有趣,因为如果我要尝试访问表单的块前缀,我可以像这样在表单主题中指定:

block_prefixes.2 == "password" 这将访问块前缀内的数组并检查它。但是,如果我要访问 attr,那么 class 选项如下所示:

attr.class 它会 return 一个错误 Key "class" does not exist as the array is empty. 这是为什么?如何轻松访问 attr 中的数组?

我认为您想为每个输入创建一个自定义 FormType,然后在您的主题中为每个输入使用一个自定义 fom_widget,就像在内置 Symfony\Component\Form\Extension\Core\Type\PercentType 和 [=13= 中所做的一样]

表格类型:

// src:"/vendor/symfony/form/Extension/Core/Type/PercentType.php"

namespace Symfony\Component\Form\Extension\Core\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

class PercentType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['scale'], $options['type']));
    }

    /**
     * {@inheritdoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['symbol'] = $options['symbol'];
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'scale' => 0,
            'symbol' => '%',
            'type' => 'fractional',
            'compound' => false,
        ]);

        $resolver->setAllowedValues('type', [
            'fractional',
            'integer',
        ]);

        $resolver->setAllowedTypes('scale', 'int');
        $resolver->setAllowedTypes('symbol', ['bool', 'string']);
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'percent';
    }
}

form_theme:

// src:"/vendor/symfony/twig-bridge/Resources/views/Form/bootstrap_4_layout.html.twig"
...

{% block percent_widget -%}
    {%- if symbol -%}
        <div class="input-group">
            {{- block('form_widget_simple') -}}
            <div class="input-group-append">
                <span class="input-group-text">{{ symbol|default('%') }}</span>
            </div>
        </div>
    {%- else -%}
        {{- block('form_widget_simple') -}}
    {%- endif -%}
{%- endblock percent_widget %}

...

您当前的方法可行。您只需要获取表单的正确子项的变量,而不是整个表单。这应该有效(在本例中为 电子邮件):

{% if form.email.vars.attr.class == 'has_icon icon_email' %}
    do or show something here
{% endif %}

或者简单地测试你的单身 class has_icon:

{% if 'has_icon' in form.email.vars.attr.class %}
    do or show something here
{% endif %} 

对于您在评论中描述的 any field 字段,我想您需要遍历所有表单子项并查看它们是否包含您正在测试的 class为了。像这样:

{% for input in form.children  %}
    {% if 'has_icon' in input.vars.attr.class | default %}
        do or show something here
    {% endif %}
{% endfor %}

| default 适用于没有 class 属性的字段。另外,我想你想在同一次迭代中渲染输入字段,这样你就可以在正确的地方渲染你的图标。我希望这能让你开始。

我明白了。因为图标将从全局角度用于我的应用程序。

方法是首先扩展 FormType,在我的例子中被称为 FormTypeExtension,它被放置在这个层次结构中:src/Form/Extensions/FormTypeExtension.php

概述该文件:

<?php

namespace App\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccess;

class FormTypeExtension extends AbstractTypeExtension
{
    public static function getExtendedTypes() : iterable
    {
        return [FormType::class];
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'icon' => null
        ]);
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {

        $view->vars['icon'] = $options['icon'];
    }
}

?>

现在在生成器中我可以应用图标选项(由于我的扩展,它默认为空,所以在表单生成器不使用它的情况下):

$builder
    ->add('email', EmailType::class, [
        'label' => 'Email address',
        'attr' => [
            'placeholder' => 'john.smith@foo.com'
        ],
        'constraints' => [
            new NotBlank([
               'message' => 'Enter an email address.'
            ])
        ],
        "icon" => "icon_email"
   ])

现在我可以在我的表单主题中访问该信息,例如 {% if icon != null %} 现在我可以根据自己的喜好对其进行自定义。

还要声明我更喜欢 Symfony 4 因为它的强大!干杯,希望这对其他人有帮助。