[在上一个问题(Symfony Check if at least one of two fields isn't empty on form validation)中,我曾向帮助寻求使用回调的表单验证的帮助。 @hous给出的答案是正确的,但不适用于CollectionType中的元素,这是我要打开一个新问题的原因。
基于上一个答案,我已经做了以下工作:
这是我的“母亲”表格:
class BookingVisitorType extends AbstractType
{
private $router;
private $translator;
public function __construct()
{
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('visitors', CollectionType::class, [
'entry_type' => VisitorType::class,
'label' => 'entity.booking.visitors',
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false,
'entry_options' => [
'label' => false,
'delete-url' => $options['visitor-delete-url']
],
'constraints' =>[
new Count([
'min' => 1,
'minMessage' => 'validator.visitor.at-least-one-visitor',
'max' => $options['numberOfPlaces'],
'maxMessage' => 'validator.visitor.cannot-have-more-visitor-than-spaces',
'exactMessage' => 'validator.visitor.exact-message'
])
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Booking::class,
'numberOfPlaces' => 1,
'visitor-delete-url' => ''
]);
}
}
这是我的“儿子”表格:
class VisitorType extends AbstractType
{
private $phone;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName', TextType::class, [
'label' => 'entity.visitor.first-name',
'constraints' => [
new NotBlank(),
new Length([
'min' => 2,
'max' => 255
]),
new Regex([
'pattern' => "/[\pL\s\-]*/",
'message' => 'validator.visitor.not-valide-first-name'
])
]
])
->add('phone', TextType::class, [
'label' => 'entity.visitor.phone-number',
'required' => false,
'constraints' => [
new Regex([
'pattern' => "/[0-9\s\.\+]*/",
'message' => 'validator.visitor.not-valide-phone-number'
]),
new Callback(function($phone, ExecutionContextInterface $context){
$this->phone = $phone;
}),
]
])
->add('email', TextType::class, [
'label' => 'entity.visitor.email',
'required' => false,
'constraints' => [
new Email(),
new Callback(function($email, ExecutionContextInterface $context){
if ($this->phone == null && $email == null) {
$context->buildViolation('validator.visitor.email-or-phone-required')->addViolation();
}
}),
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Visitor::class,
'error_bubbling' => false,
'delete-url' => '',
]);
}
}
我的“预订”(缩短的)课程:
/**
* @ORM\Entity(repositoryClass="App\Repository\BookingRepository")
*/
class Booking
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Visitor", mappedBy="booking", orphanRemoval=true, cascade={"persist"})
* @Assert\Valid
*/
private $visitors;
}
最后是我的“访客”(缩短的)课程:
/**
* @ORM\Entity(repositoryClass="App\Repository\VisitorRepository")
*/
class Visitor
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=45, nullable=true)
*/
private $phone;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $email;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Booking", inversedBy="visitors")
* @ORM\JoinColumn(nullable=false)
*/
private $booking;
/**
* @Assert\Callback
*/
public function validateAtLeastEmailOrPhone(ExecutionContextInterface $context, $payload)
{
if ($this->getPhone() === null && $this->getEmail() === null) {
$context->buildViolation('validator.visitor.email-or-phone-required-for-all')->addViolation();
}
}
}
我已经能够解决此问题,方法是在我的VisitorType表单中添加一个属性,该属性由电话值上的Callback约束定义,然后通过email字段上的Callback约束进行检查,但是看起来并不十分“好的做法”。
如果仅尝试调用回调约束,则会收到以下错误消息:“警告:get_class()期望参数1为对象,给定字符串”
非常感谢您的帮助!
代替回调函数,您可以创建自己的Constraint。然后,该支票将可重复使用。
我一直使用它来根据自定义规则检查注册密码。