[Symfony/Form] CheckboxTypeでもラベル列を出力したい
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.twig
と bootstrap_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.twig
や bootstrap_4_horizontal_layout.html.twig
を拡張してCheckboxTypeでもラベル列を出力できるようにする方法を紹介しました。
僕がSymfonyで開発するときに毎回使っている至高のスケルトン ttskch/symfony-skeleton にもデフォルトでこの機能を入れてありますので、よろしければ使ってみてください😇
Discussion