🎻
[Symfony] エンティティのプロパティがオブジェクトの場合は @Assert\Valid が必要なので注意
どういうこと
例えば、以下のようなエンティティがあるとします。
class Foo
{
/**
* @var Bar
*/
private $bar;
/**
* @Assert\NotBlank()
*/
private $baz;
// ...
}
class Bar
{
/**
* @Assert\NotBlank()
*/
private $qux;
/**
* @Assert\Regex("/^\d+$/")
*/
private $quux;
// ...
}
これらのクラスに対応するFormTypeも以下のように用意してみます。
class FooType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('bar', BarType::class)
->add('baz', TextType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Foo::class,
]);
}
}
class BarType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('qux', TextType::class)
->add('quux', NumberType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Bar::class,
]);
}
}
これで、 FooType
のフォームを使えば自動的に以下のプロパティがすべてバリデーションしてもらえそうな気がしますね。
Foo::baz
Bar::qux
Bar::quux
しかし、実はこのままだと
Foo::baz
しかバリデーションされません🙄
Bar::qux
が空でも、 Bar::quux
に数字以外が入っていても、特にエラーにならずにsubmitできてしまいます。
どうすればいいの
プロパティにオブジェクトを持ち、そのオブジェクトのプロパティにもバリデーションが設定されている場合、 親のプロパティに Valid
制約をつける必要があります。
こちらの公式ドキュメントにすべて書いてあります👍
https://symfony.com/doc/current/reference/constraints/Valid.html
先ほどの例で言うと、 Foo
クラスを以下のように修正することで解決します。
class Foo
{
/**
* @var Bar
+ *
+ * @Assert\Valid()
*/
private $bar;
/**
* @Assert\NotBlank()
*/
private $baz;
// ...
}
深くネストしている場合はすべての階層で Valid
アノテートする必要があるので、付け忘れに注意ですね。
オブジェクトのプロパティに Valid
アノテートする代わりに、FormTypeで直接
->add('bar', BarType::class, [
'constraints' => new Valid(),
])
としてもよいです👌
この方法なら階層が深くても最下層に1回書くだけでいいので少し楽かもしれません✋
まとめ
- Symfonyでエンティティのプロパティがオブジェクトの場合はプロパティに
@Assert\Valid
しておかないとオブジェクト内部のバリデーションが適用されないので要注意 - アノテーションの代わりにFormTypeの当該フィールドに
'constraints' => new Valid()
を書くでもOK
Discussion