Symfony Advent Calendar 2021 4日目の記事です。
昨日は @ttskch さんの UniqueEntity制約はpersistしただけの既存エンティティとの重複は検出してくれないので工夫が必要 でした。
Symfony6は "php": ">=8.0.2"
という攻めた必須要件で、PHP8.1を使っているとEnumの恩恵を受けることもできるようになりました!
というわけで、早速PHP8.1.0とSymfony6の環境でEnumフォームタイプで遊んでみようと思います。(EnumFormType自体はSymfony5.4から利用可能です)
※ 以下、コードの詳細は遊んだプルリク https://github.com/77web/php8.1-Symfony6-playground/pull/1 のコミットログでも確認できます。
EnumType
EnumTypeはChoiceTypeを継承しているのでmultiple, expanded等ChoiceTypeでおなじみのオプションも使えます。 https://github.com/77web/php8.1-Symfony6-playground/blob/c125e99ac14ff4143e2446c6a48ad3d9b136f13b/src/Form/ContactType.php
<?php
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('age', EnumType::class, [
'class' => Age::class,
])
->add('interests', EnumType::class, [
'class' => Interest::class,
'multiple' => true,
'expanded' => true,
])
->add('opinion')
;
}
// ...
}
EnumTypeを含むフォームへのsubmit
BackedでないEnumに対してはEnumに定義されたcase上の順番(0index)の番号、BackedEnumに対してはBackedな値(Enumのインスタンスのvalueに当たるもの)をsubmitします。
<?php
$form->submit([
'name' => '77web',
'age' => 3, // Age::AGE_40_TO_49はAgeの4番目のcase
'interests' => ['php', 'angular', 'aws'], // BackedEnumなのでvalue
'opinion' => 'I love Symfony',
]);
$form->getData()
で実際にセットされた値を確認すると、ちゃんと各Enumのインスタンスがセットされていることがわかります。
<?php
$this->assertEquals(Age::AGE_40_TO_49, $data->getAge());
$this->assertEquals([Interest::PHP, Interest::FRONTEND, Interest::INFRA], $data->getInterests());
EnumTypeを使ったフォームのレンダリング
HTMLになると通常のChoiceTypeと同じです。
multiple => true, expanded => falseにしたときはselect multiple | multiple => true, expanded => trueにしたときはcheckbox |
---|---|
先ほど見たようにselect,radio,inputの値はsubmitしたい値なので、BackedでないEnumでは連番、BackedEnumではvalueとなります。
BackedでないEnumのselectのHTML出力
BackedEnumのcheckboxのHTML出力
まとめ
PHP8.1のEnum+Symfony6のEnumType、 いままで自作の EnumTrait
で色々むちゃしていたところがスッキリできそうです。遊びでコードを書いているだけでも、とても良い開発者体験を味わうことができました。 ☺️
早くプロダクションコードをPHP8.1にして、自作のEnumTraitを駆逐したいです
明日も @ttskch さんの記事です!お楽しみに!