I've got some issues with Symfony's form validation handling. I'd like to validate a form bound to an entity based on its data. There are quite a bunch of information how to dynamically modify the form fields using FormEvents. What I'm missing on this topic is how to control/modify the validation.
My simplified use case is:
- A user can add an event to a calendar.
- The validation checks if there's already an event.
- If there's a collision, the validation will throw an error.
- The user should now be able to ignore this error/warning.
The validation is implemented as a Validator
with Constraint::CLASS_CONSTRAINT
as the target (as it's taking some more stuff into account).
I tried to:
- Hack around the validation groups, but couldn't find access to the entity wide validators.
- Hack around the
FormEvents
and add an extra field like "Ignore date warning". - Hack around the submit button to change it to something like "Force submit".
... but never found a working solution. Even simpler hacks with a single property based validator didn't work out. :(
Is there a Symfony way to dynamically control the validation?
Edit: My code looks like this:
use Doctrine\ORM\Mapping as ORM;
use Acme\Bundle\Validator\Constraints as AcmeAssert;
/**
* Appointment
*
* @ORM\Entity
* @AcmeAssert\DateIsValid
*/
class Appointment
{
/**
* @ORM\Column(name="title", type="string", length=255)
*
* @var string
*/
protected $title;
/**
* @ORM\Column(name="date", type="date")
*
* @var \DateTime
*/
protected $date;
}
The validator used as a service:
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the date of an appointment.
*/
class DateIsValidValidator extends ConstraintValidator
{
/**
* {@inheritdoc}
*/
public function validate($appointment, Constraint $constraint)
{
if (null === $date = $appointment->getDate()) {
return;
}
/* Do some magic to validate date */
if (!$valid) {
$this->context->addViolationAt('date', $constraint->message);
}
}
}
The corresponding Constraint
class is set to target the entity class.
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class DateIsValid extends Constraint
{
public $message = 'The date is not valid!';
/**
* {@inheritdoc}
*/
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
/**
* {@inheritdoc}
*/
public function validatedBy()
{
return 'acme.validator.appointment.date';
}
}
Edit 2: Try with FormEvents
... I also tried all the different events.
$form = $formFactory->createBuilder()
->add('title', 'text')
->add('date', 'date')
->addEventListener(FormEvents::WHICHONE?, function(FormEvent $event) {
$form = $event->getForm();
// WHAT TO DO HERE?
$form->getErrors(); // Is always empty as all events run before validation?
// I need something like
if (!$dateIsValid) {
$form->setValidationGroup('ignoreWarning');
}
});
Edit 3: Constraint are correctly declared. That's not the issue:
services:
validator.acme.date:
class: AcmeBundle\Validator\Constraints\DateValidator
arguments: ["@acme.other_service"]
tags:
- { name: validator.constraint_validator, alias: acme.validator.appointment.date }
validation_groups
from inside your FormEvent? – RuzichFormEvents
in combination with thevalidation_groups
. I was stuck at fetching the current validation error to somehow disable it. – Russia