🎻

[Symfony/Form] CheckboxTypeでもラベル列を出力したい

2020/08/05に公開

twig-bridgeにはBootstrap4フォームテーマが同梱されている

symfony/twig-bundle 経由で自動でインストールされる symfony/twig-bridge には、

という2つのフォームテーマが入っています。

config/packages/twig.yaml でフォームテーマとしてこれらのファイルを指定するだけで、簡単にSymfonyのフォームをBootstrap4の見た目で出力できるようになり、とても便利です。

// config/packages/twig.yaml
twig:
    # ...
    form_themes:
#        - 'bootstrap_4_layout.html.twig'
        - 'bootstrap_4_horizontal_layout.html.twig' # 配列の最後の要素がデフォルトのテーマになる

このフォームテーマでは、CheckboxTypeにはラベル列が出力されない

とても便利なのですが、個人的にはいくつか不満点もあり、普段は自分でtwigを拡張して多少手直しをした状態で使っています。

その不満点の一つが、 CheckboxTypeにはラベル列が出力されない というものです。

例えば、以下のようにCheckboxTypeのフォームフィールドを作ってみましょう。

class ContactType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // ...
            ->add('news_letters', CheckboxType::class, [
                'label' => 'News letters',
                'required' => false,
            ])
            // ...
        ;
    }
}

この場合、出力されるHTMLは下図のようになります。

必須項目に required というバッジを表示しているのは自分のCSSです🙏

bootstrap_4_horizontal_layout.html.twig で表示

bootstrap_4_layout.html.twig で表示

別にこれはこれでおかしくないのかもしれませんが、個人的には

  • 他の項目のようにラベル列を表示して、そこに News letters と表示
  • チェックボックス自体のラベルにはこの場合なら Subscribe などと表示

という見せ方がしたいです🤔

フォームテーマを拡張して対応してみる

というわけで、フォームテーマのtwigを拡張してこの要望に対応してみましょう。

細かい解説は省きますが、 bootstrap_4_layout.html.twigbootstrap_4_horizontal_layout.html.twig (およびその継承元のtwig)とにらめっこしながら格闘した結果、以下のようなコードで上手く対応できました。

// templates/form_theme/bootstrap_4_layout.html.twig

{% use 'bootstrap_4_layout.html.twig' %}

{# CheckboxTypeに対してラベル列を出力するために上書きして一部を修正 #}
{% block form_row -%}
  {%- if compound is defined and compound -%}
    {%- set element = 'fieldset' -%}
  {%- endif -%}
  {%- set widget_attr = {} -%}
  {%- if help is not empty -%}
    {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
  {%- endif -%}
  <{{ element|default('div') }}{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group')|trim})} %}{{ block('attributes') }}{% endwith %}>

  {# ここを修正 #}
  {% if label_attr.value is defined %}
    {{ block('form_label') }}
  {% else %}
    {{- form_label(form) -}}
  {% endif %}

  {# ここを修正 #}
  <div class="d-block">
    {{- form_widget(form, widget_attr) -}}
  </div>

  {{- form_help(form) -}}
  </{{ element|default('div') }}>
{%- endblock form_row %}

{# ラベルの文言を label_attr.value で制御するために上書き #}
{% block checkbox_radio_label -%}
  {% if label_attr.value is defined %}
    {% set label = label_attr.value %}
  {% endif %}
  {{ parent() }}
{%- endblock checkbox_radio_label %}
// templates/form_theme/bootstrap_4_horizontal_layout.html.twig

{% use 'bootstrap_4_horizontal_layout.html.twig' %}

{# CheckboxTypeに対してラベル列を出力するために上書きして一部を修正 #}
{% block checkbox_row -%}
  <div{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group row')|trim})} %}{{ block('attributes') }}{% endwith %}>{#--#}

    {# ここを修正 #}
    {% if label_attr.value is defined %}
      {{ block('form_label') }}
    {% else %}
      <div class="{{ block('form_label_class') }}"></div>{#--#}
    {% endif %}

    <div class="{{ block('form_group_class') }}">
      {{- form_widget(form) -}}
      {{- form_help(form) -}}
    </div>{#--#}
  </div>
{%- endblock checkbox_row %}

{# ラベルの文言を label_attr.value で制御するために上書き #}
{% block checkbox_radio_label -%}
  {% if label_attr.value is defined %}
    {% set label = label_attr.value %}
  {% endif %}
  {{ parent() }}
{%- endblock checkbox_radio_label %}

これらの内容で

  • templates/form_theme/bootstrap_4_layout.html.twig
  • templates/form_theme/bootstrap_4_horizontal_layout.html.twig

を作成して、

// config/packages/twig.yaml
twig:
    # ...
    form_themes:
#        - 'form_theme/bootstrap_4_layout.html.twig'
        - 'form_theme/bootstrap_4_horizontal_layout.html.twig' # 配列の最後の要素がデフォルトのテーマになる

のようにしてフォームテーマを差し替えて有効化します。

そして、FormTypeに以下のように label_attr.value を追加し、そこでチェックボックス自体に付加したいラベルの文字列を設定します。

  class ContactType extends AbstractType
  {
      public function buildForm(FormBuilderInterface $builder, array $options)
      {
          $builder
  
              // ...
  
              ->add('news_letters', CheckboxType::class, [
                  'label' => 'News letters',
                  'required' => false,
+                 'label_attr' => [
+                     'value' => 'Subscribe',
+                     'class' => 'checkbox-inline', // これはついでに見た目を整えるため
+                 ],
              ])
  
              // ...
          ;
      }
  }

これで、表示結果は以下のようになります。

bootstrap_4_horizontal_layout.html.twig で表示

bootstrap_4_layout.html.twig で表示

美しいですね😇

ちなみに、コードを見ていただければ分かると思いますが、 label_attr.value を設定しなければ今までどおりの表示になるので、必要に応じて使い分けることも可能です👌

まとめ

というわけで、symfony/twig-bridge にデフォルトで入っている bootstrap_4_layout.html.twigbootstrap_4_horizontal_layout.html.twig を拡張してCheckboxTypeでもラベル列を出力できるようにする方法を紹介しました。

僕がSymfonyで開発するときに毎回使っている至高のスケルトン ttskch/symfony-skeleton にもデフォルトでこの機能を入れてありますので、よろしければ使ってみてください😇

GitHubで編集を提案

Discussion