如何在 Twig 中将实体(选择 <select>)字段呈现为 <ul> 字段?

How can I render an entity (choice <select>) field as a <ul> field in Twig?

Symfony renders an entity field type like a choice dropdown - a select, basically. However, the CSS framework that I'm using defines a sort of 'select' as a ul and li as the options. The Custom Field Type documentation gives no help on this scenario.

我正在将我的代码从手动 HTML 呈现表单下拉列表转换为使用 twig 和 form_widget() 的 symfony 表单版本。但是,我想要 ulli 而不是 select.

创建下拉菜单的手动方法是:

<ul class='dropdown-menu'>
    {% for locator in locators %}
        <li>
            <a href="#" data-id="{{locator.getId() }}">
                {{ locator.getName() }}
            </a>
        </li>
    {% endfor %}
</ul>

这就是我在使用 symfony 表单之前手动呈现下拉列表的方式。它看起来像这样:

我喜欢。我觉得它看起来棒极了。现在,如果我使用的是 Symfony 表单,我可以只使用它:

{{ form_start(form) }}
    {{ form_widget(form.locator) }} {# This is my locator dropdown #}
    {{ form_widget(form.target) }} {# Ignore this #}
{{ form_end(form) }}

问题是这会呈现这个:

我无法在此处添加我的自定义 CSS,因为它呈现为 select 而不是无序列表和 lis.

如果有帮助,这是我正在构建的表单类型:

/**
 * {@inheritDoc}
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('target')
            ->add('locator', 'entity', [
                'class'         => 'Application\Model\Entity\Locator',
                'query_builder' => function(EntityRepository $repo) {
                    return $repo->createQueryBuilder('e');
                },
                'empty_value'   => 'Locator'
            ])
            ->add('save', 'submit', ['label' => 'Save']);

    $builder->setAction($this->urlGenerator->generate('page_create_element', [
        'suiteId' => $options['suiteId'], 'pageId' => $options['pageId']
    ]))->setMethod('POST');
}

问题:有什么方法可以让上面的表单命令自动生成我的 ul / li 要求而不是选择,或者我是否必须手动呈现它并为此忽略 symfony 表单组件?

Thanks to some of the posters above, there was some information from Form Theming, but it wasn't exactly enough to go along with so I had to do a little bit of digging on github.

根据 documentation,Symfony 使用 twig 模板呈现表单的相关位及其包含的元素。这些只是树枝中的 {% block %}s。所以第一步是找到在 symfony 代码库中呈现 select 按钮的位置。

表单主题

首先,您在自己的 twig 文件中创建自己的主题块,然后使用以下代码将此主题应用于您的表单:

{% form_theme my_form_name 'form/file_to_overridewith.html.twig %}

因此,如果我在上面的文件中覆盖了 {% block form_row %},那么当我调用 {{ form_row(form) }} 时,它将使用我的块而不是 Symfony 的默认块。

重要提示:您不必覆盖所有内容。只需覆盖您想要更改的内容,如果在您的主题中找不到任何内容,Symfony 将回退到它自己的块。

源代码

在 github 上,我找到了 Symfony 的 "choice widget" 的 source code。它有点复杂,但如果您按照它进行操作并进行一些实验,您就会明白它的走向。

choice_widget_collapsed 块中,我将 select 更改为 ul,并将选项更改为 li。这是我创建的主题文件,请注意上面描述的细微差别:

{# Symfony renders a 'choice' or 'entity' field as a select dropdown - this changes it to ul/li's for our own CSS #}

{%- block choice_widget_collapsed -%}
    {%- if required and empty_value is none and not empty_value_in_choices and not multiple -%}
        {% set required = false %}
    {%- endif -%}
    <ul {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
        {%- if preferred_choices|length > 0 -%}
            {% set options = preferred_choices %}
            {{- block('choice_widget_options') -}}
            {%- if choices|length > 0 and separator is not none -%}
                <li disabled="disabled">{{ separator }}</li>
            {%- endif -%}
        {%- endif -%}
        {%- set options = choices -%}
        {{- block('choice_widget_options') -}}
    </ul>
{%- endblock choice_widget_collapsed -%}

{%- block choice_widget_options -%}
    {% for group_label, choice in options %}
        {%- if choice is iterable -%}
            <optgroup label="{{ group_label|trans({}, translation_domain) }}">
                {% set options = choice %}
                {{- block('choice_widget_options') -}}
            </optgroup>
        {%- else -%}
            <li value="{{ choice.value }}"{% if choice is selectedchoice(value) %} selected="selected"{% endif %}><a href="#">{{ choice.label|trans({}, translation_domain) }}</a></li>
        {%- endif -%}
    {% endfor %}
{%- endblock choice_widget_options -%}

渲染

现在我可以使用以下内容呈现我的表单:

{{ form_widget(form.locator, {'attr': {'class': 'dropdown-menu'}}) }}

这将我的主题用于选择下拉菜单,其中包含 ulli 标签而不是 selectoption 标签。一旦您知道在哪里寻找原始代码,就非常简单!呈现的 HTML:

<ul id="elementtype_locator" name="elementtype[locator]" required="required" class="dropdown-menu">
    <li value="1"><a href="#">id</a></li>
    <li value="2"><a href="#">name</a></li>
    <li value="3"><a href="#">xpath</a></li>
</ul>

我还必须删除将 'Locator' 放在下拉列表顶部的行之一,因为有四个下拉选项(包括 empty_data 一个)而不是三个。