/** * Validates the form and its domain object. * * @param FormInterface $form A FormInterface instance */ public function validate(FormInterface $form) { if ($form->isRoot()) { $mapping = array(); $forms = array(); $this->buildFormPathMapping($form, $mapping); $this->buildDataPathMapping($form, $mapping); $this->buildNamePathMapping($form, $forms); $this->resolveMappingPlaceholders($mapping, $forms); // Validate the form in group "Default" // Validation of the data in the custom group is done by validateData(), // which is constrained by the Execute constraint if ($form->hasAttribute('validation_constraint')) { $violations = $this->validator->validateValue($form->getData(), $form->getAttribute('validation_constraint'), self::getFormValidationGroups($form)); if ($violations) { foreach ($violations as $violation) { $propertyPath = new PropertyPath($violation->getPropertyPath()); $template = $violation->getMessageTemplate(); $parameters = $violation->getMessageParameters(); $error = new FormError($template, $parameters); $child = $form; foreach ($propertyPath->getElements() as $element) { $children = $child->getChildren(); if (!isset($children[$element])) { if ($form->isSynchronized()) { $form->addError($error); } break; } $child = $children[$element]; } if ($child->isSynchronized()) { $child->addError($error); } } } } elseif (count($violations = $this->validator->validate($form))) { foreach ($violations as $violation) { $propertyPath = $violation->getPropertyPath(); $template = $violation->getMessageTemplate(); $parameters = $violation->getMessageParameters(); $error = new FormError($template, $parameters); foreach ($mapping as $mappedPath => $child) { if (preg_match($mappedPath, $propertyPath)) { if ($child->isSynchronized()) { $child->addError($error); } continue 2; } } if ($form->isSynchronized()) { $form->addError($error); } } } } }
/** * Creates a new violation path from a string. * * @param string $violationPath The property path of a {@link ConstraintViolation} * object. */ public function __construct($violationPath) { $path = new PropertyPath($violationPath); $elements = $path->getElements(); $positions = $path->getPositions(); $data = false; for ($i = 0, $l = count($elements); $i < $l; ++$i) { if (!$data) { // The element "data" has not yet been passed if ('children' === $elements[$i] && $path->isProperty($i)) { // Skip element "children" ++$i; // Next element must exist and must be an index // Otherwise consider this the end of the path if ($i >= $l || !$path->isIndex($i)) { break; } $this->elements[] = $elements[$i]; $this->positions[] = $positions[$i]; $this->isIndex[] = true; $this->mapsForm[] = true; } elseif ('data' === $elements[$i] && $path->isProperty($i)) { // Skip element "data" ++$i; // End of path if ($i >= $l) { break; } $this->elements[] = $elements[$i]; $this->positions[] = $positions[$i]; $this->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; $data = true; } else { // Neither "children" nor "data" property found // Consider this the end of the path break; } } else { // Already after the "data" element // Pick everything as is $this->elements[] = $elements[$i]; $this->positions[] = $positions[$i]; $this->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; } } $this->length = count($this->elements); $this->pathAsString = $violationPath; $this->resizeString(); }