web-dev-qa-db-ja.com

symfony twigフォーム行にクラスを追加する方法

Twigを使用してSymfony 2.3でプロジェクトを構築しています。クラスをフォーム行ブロックに追加したいのですが。以下を含むフォームテーマファイルを使用しています。

{% block form_row %}
    <div class="form-row">
        {{ form_label(form) }}
        {{ form_widget(form) }}
        {{ form_errors(form) }}
    </div>
{% endblock %}

ここで、フォーム行の一部にクラスを追加したいform-row-split。これを正しく行う方法がわかりません。私がそれをほぼ機能させる方法は次のとおりです:

{% block form_row %}
    {% set attr = attr|merge({'class': 'form-row' ~ (attr.class is defined ? ' ' ~ attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
    <div {{ block('widget_container_attributes') }}>
        {{ form_label(form) }}
        {{ form_widget(form) }}
        {{ form_errors(form) }}
    </div>
{% endblock %}

(注:errorクラスロジックもそのままにしておく必要があります)。次にフォームビルダーで:

$builder
        ->add('first_name', 'text', array(
            'attr' => array(
                'class' => 'form-row-split'
            )
        ));

これはほとんど機能しますが、このクラスがどこにでも追加され、ウィジェットIDが行に追加されます!

<div id="myform_first_name" class="form-row form-row-split">
    <label for="myform_first_name">First name</label>
    <input id="myform_first_name" class="form-row-split" type="text" name="myform[first_name]">
</div>

私はいくつかの潜在的な解決策を考えることができますが、それらのどれもかなりまたは簡単です。確かにこれを行う簡単な方法があるはずですか?

16
lopsided

この問題には実際にはかなり単純な解決策があります。ベースフォームタイプを拡張して追加の利用可能なオプションを許可するために、フォームタイプ拡張が必要でした: http://symfony.com/doc/2.3/cookbook/form/create_form_type_extension.html

ドキュメントの例に従って、新しいフォームタイプ拡張を作成しました。

// src/Acme/FrontendBundle/Form/Extension/FormTypeExtension.php

namespace Acme\FrontendBundle\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

/**
 * Class FormTypeExtension
 * @package Acme\FrontendBundle\Form\Extension
 */
class FormTypeExtension extends AbstractTypeExtension
{
    /**
     * Extends the form type which all other types extend
     *
     * @return string The name of the type being extended
     */
    public function getExtendedType()
    {
        return 'form';
    }

    /**
     * Add the extra row_attr option
     *
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'row_attr' => array()
        ));
    }

    /**
     * Pass the set row_attr options to the view
     *
     * @param FormView $view
     * @param FormInterface $form
     * @param array $options
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['row_attr'] = $options['row_attr'];
    }
}

次に、サービスをバンドルに登録しました...

<!-- Form row attributes form extension -->
<service id="acme.form_type_extension" class="Acme\FrontendBundle\Form\Extension\FormTypeExtension">
    <tag name="form.type_extension" alias="form" />
</service>

すべてのウィジェットが基本フォームタイプを拡張するため、これにより、この新しいrow_attrオプションを任意のフィールドで渡すことができます。例:

$builder
    ->add('first_name', 'text', array(
        'row_attr' => array(
            'class' => 'form-row-split'
        )
    ));

次に、twigオーバーライドして、新しいrow_attrオプションを使用します。

{% block form_row %}
    <div {{ block('form_row_attributes') }}>
        {{ form_label(form) }}
        {{ form_widget(form) }}
        {{ form_errors(form) }}
    </div>
{% endblock form_row %}

{% block form_row_attributes %}
    {% spaceless %}
        {% for attrname, attrvalue in row_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
    {% endspaceless %}
{% endblock form_row_attributes %}

これで完了です。

(完全を期すために、私の完全なtwigオーバーライドは、以下のようにform-rowおよびerrorクラスにマージされます:

{% set row_attr = row_attr|merge({'class': 'form-row' ~ (row_attr.class is defined ? ' ' ~ row_attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}

..しかし、私自身の質問に答えるのにそれは本当に必要ではありません:P)

23
lopsided

Docs 言う:常にレンダリングされた要素にattrを渡すことができます:

{{ form_start(form, {'attr': {'class': 'your-class'}} ) }}
    {{ form_label(form, {'attr': {'class': 'your-class'}}) }}
    {{ form_widget(form, {'attr': {'class': 'your-class'}}) }}
    {{ form_errors(form, {'attr': {'class': 'your-class'}}) }}
{{ form_end(form) }}
16
pomaxa

以下は@lopsidedによる回答のクローンですが、Symfonyの最新の構造変更(v。2.7以降)を反映した変更が加えられています。


この問題には実際にはかなり単純な解決策があります。ベースフォームタイプを拡張して追加の利用可能なオプションを許可するためにフォームタイプ拡張が必要でした: http://symfony.com/doc/master/form/create_form_type_extension.html

ドキュメントの例に従って、新しいフォームタイプ拡張を作成しました。

// src/Acme/FrontendBundle/Form/Extension/FormTypeExtension.php

namespace Acme\FrontendBundle\Form\Extension;

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

/**
 * Class FormTypeExtension
 * @package Acme\FrontendBundle\Form\Extension
 */
class FormTypeExtension extends AbstractTypeExtension
{
    /**
     * Extends the form type which all other types extend
     *
     * @return string The name of the type being extended
     */
    public function getExtendedType()
    {
        return FormType::class;
    }

    /**
     * Add the extra row_attr option
     *
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'row_attr' => []
        ));
    }

    /**
     * Pass the set row_attr options to the view
     *
     * @param FormView $view
     * @param FormInterface $form
     * @param array $options
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['row_attr'] = $options['row_attr'];
    }
}

次に、サービスをバンドルに登録しました...

<!-- Form row attributes form extension -->
<service id="acme.form_type_extension" class="Acme\FrontendBundle\Form\Extension\FormTypeExtension">
    <tag name="form.type_extension" alias="form" extended_type="Symfony\Component\Form\Extension\Core\Type\FormType" />
</service>

すべてのウィジェットが基本フォームタイプを拡張するため、これにより、この新しいrow_attrオプションを任意のフィールドで渡すことができます。例:

$builder
    ->add('first_name', TextType:class, [
        'row_attr' => [
            'class' => 'form-row-split'
        ]
    ]);

次に、twigオーバーライドして、新しいrow_attrオプションを使用します。

{% block form_row %}
    <div {{ block('form_row_attributes') }}>
        {{ form_label(form) }}
        {{ form_widget(form) }}
        {{ form_errors(form) }}
    </div>
{% endblock form_row %}

{% block form_row_attributes %}
    {% spaceless %}
        {% for attrname, attrvalue in row_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
    {% endspaceless %}
{% endblock form_row_attributes %}

これで完了です。

(完全を期すために、私の完全なtwigオーバーライドは、以下のようにform-rowおよびerrorクラスにマージされます:

{% set row_attr = row_attr|merge({'class': 'form-row' ~ (row_attr.class is defined ? ' ' ~ row_attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}

..しかし、私自身の質問に答えるのにそれは本当に必要ではありません:P)

6
Pavel Dubinin

私がやったことはより単純でした(多分少しクリーンではありませんか?)。

フィールドの「data」属性を介してフォーム行のクラスを渡します。

// template.html.twig

{{ form_start(form) }}
    {{ form_row(form.field, {'attr': {'data-row-class': 'my-row-class'} }) }}
{{ form_end(form) }}

次に、フォームのテーマテンプレートで次のように処理します。

// form-theme.html.twig

{% block form_row -%}
    {% set row_class = attr['data-row-class'] | default('') %}
    <div class="{{ row_class }}">
        {{- form_label(form) -}}
        {{- form_widget(form) -}}
        {{- form_errors(form) -}}
    </div>
{%- endblock form_row %}

これはこれを与えます:

<form name="formName" method="post">
    <div class="my-row-class">
        <label for="formName_field">Field label</label>
        <input type="text" id="formName_field" name="formName[field]" data-row-class="my-row-class">
    </div>
</form>
1
Philippe-B-