public function validate($form, Constraint $constraint)
{
if (!$constraint instanceof Form) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Form');
}
if (!$form instanceof FormInterface) {
return;
}
/* @var FormInterface $form */
$config = $form->getConfig();
$validator = $this->context->getValidator()->inContext($this->context);
if ($form->isSynchronized()) {
// Validate the form data only if transformation succeeded
$groups = self::getValidationGroups($form);
$data = $form->getData();
// Validate the data against its own constraints
if ($form->isRoot() && (is_object($data) || is_array($data))) {
if (is_array($groups) && count($groups) > 0 || $groups instanceof GroupSequence && count($groups->groups) > 0) {
$validator->atPath('data')->validate($form->getData(), null, $groups);
}
}
// Validate the data against the constraints defined
// in the form
$constraints = $config->getOption('constraints', array());
foreach ($constraints as $constraint) {
// For the "Valid" constraint, validate the data in all groups
if ($constraint instanceof Valid) {
$validator->atPath('data')->validate($form->getData(), $constraint, $groups);
continue;
}
// Otherwise validate a constraint only once for the first
// matching group
foreach ($groups as $group) {
if (in_array($group, $constraint->groups)) {
$validator->atPath('data')->validate($form->getData(), $constraint, $group);
// Prevent duplicate validation
continue 2;
}
}
}
} else {
$childrenSynchronized = true;
foreach ($form as $child) {
if (!$child->isSynchronized()) {
$childrenSynchronized = false;
break;
}
}
// Mark the form with an error if it is not synchronized BUT all
// of its children are synchronized. If any child is not
// synchronized, an error is displayed there already and showing
// a second error in its parent form is pointless, or worse, may
// lead to duplicate errors if error bubbling is enabled on the
// child.
// See also https://github.com/symfony/symfony/issues/4359
if ($childrenSynchronized) {
$clientDataAsString = is_scalar($form->getViewData())
? (string) $form->getViewData()
: gettype($form->getViewData());
$this->context->buildViolation($config->getOption('invalid_message'))
->setParameters(array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')))
->setInvalidValue($form->getViewData())
->setCode(Form::NOT_SYNCHRONIZED_ERROR)
->setCause($form->getTransformationFailure())
->addViolation();
}
}
// Mark the form with an error if it contains extra fields
if (!$config->getOption('allow_extra_fields') && count($form->getExtraData()) > 0) {
$this->context->buildViolation($config->getOption('extra_fields_message'))
->setParameter('{{ extra_fields }}', implode('", "', array_keys($form->getExtraData())))
->setInvalidValue($form->getExtraData())
->setCode(Form::NO_SUCH_FIELD_ERROR)
->addViolation();
}
}