TL; DR:
我的Person
实体表单上有一个未映射的字段,我需要对其进行验证。我已经关注this great article如何执行此操作,但我的用例略有不同,文章并未完全涵盖。
我正在创建自己的Unique Constraint,需要运行自定义查询来确定唯一性。要运行查询,我需要访问已提交的字段值以及原始Person
对象(如果它是更新操作,我可以获取它的ID )。如果没有Person
对象,我就无法在唯一性查询中将其排除在考虑之外。
如果我在PersonType
类上应用验证器,如下所示:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver
->setDefaults(array(
'data_class' => 'CS\AcmeBundle\Entity\Person',
'constraints' => array(
new MyUniqueValidator(),
)
))
;
}
然后验证器将传递整个Person
对象以执行验证。这对我没有帮助,因为提交的表单数据不会持久保存到Person
对象(它是在控制器中调用$form->isValid()
后我处理的未映射字段)。
如果我直接将验证器应用于未映射的字段:
$builder
->add('myUnmappedField', 'text', array(
'mapped' => false,
'constraints' => array(
new MyUniqueValidator(),
)
),
))
然后我传递给验证器的对象只是独立的表单文本,没有别的。我没有要通过唯一性查询执行ID Person
对象(如果它是更新操作)。
希望我已经正确地解释了这一点。我有任何选择可以优雅地进行这种验证吗?
答案 0 :(得分:6)
你说你有未映射的字段。如果你把它映射到Person实体会有帮助吗?只需使用getter和setter方法在Person类中创建一个新属性,但不要在ORM中创建一个新属性,因为您不希望它持久存在。
如果您不想对Person类进行轮询,您还可以创建另一个复合类,它将保存当前未映射的字段和Person对象(然后您将对其进行映射)。然后,您将设置data_class以匹配新对象的命名空间。
上述两种解决方案都应该与您拥有的上层代码一起使用。请让我知道它有帮助。
答案 1 :(得分:0)
您可以使用callback constraint with a closure来实现。
要访问您的Person
实体,您将需要通过事件监听器添加该字段。
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$person = $event->getData();
$form->add('myUnmappedField', TextType::class, [
'mapped' => false,
'constraints' => [
new Symfony\Component\Validator\Constraints\Callback([
'callback' => function ($value, ExecutionContextInterface $context) use ($person) {
// Here you can use $person->getId()
// $value is the value of the unmapped field
}
])
],
]);
});