[Validator] Moved logic of replaceDefaultGroup() to validateNode()
This commit is contained in:
parent
2f23d9725b
commit
029a71638e
|
@ -72,8 +72,6 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||
$context->setNode($node->value, $node->metadata, $node->propertyPath);
|
||||
|
||||
if ($node instanceof ClassNode) {
|
||||
$this->replaceDefaultGroup($node);
|
||||
|
||||
$objectHash = spl_object_hash($node->value);
|
||||
} elseif ($node instanceof PropertyNode) {
|
||||
$objectHash = spl_object_hash($node->object);
|
||||
|
@ -88,6 +86,8 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||
// simply continue traversal (if possible)
|
||||
|
||||
foreach ($node->groups as $key => $group) {
|
||||
$cascadedGroup = null;
|
||||
|
||||
// Even if we remove the following clause, the constraints on an
|
||||
// object won't be validated again due to the measures taken in
|
||||
// validateNodeForGroup().
|
||||
|
@ -106,11 +106,36 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||
}
|
||||
|
||||
$context->markObjectAsValidatedForGroup($objectHash, $groupHash);
|
||||
|
||||
// Replace the "Default" group by the group sequence defined
|
||||
// for the class, if applicable
|
||||
// This is done after checking the cache, so that
|
||||
// spl_object_hash() isn't called for this sequence and
|
||||
// "Default" is used instead in the cache. This is useful
|
||||
// if the getters below return different group sequences in
|
||||
// every call.
|
||||
if (Constraint::DEFAULT_GROUP === $group) {
|
||||
if ($node->metadata->hasGroupSequence()) {
|
||||
// The group sequence is statically defined for the class
|
||||
$group = $node->metadata->getGroupSequence();
|
||||
$cascadedGroup = Constraint::DEFAULT_GROUP;
|
||||
} elseif ($node->metadata->isGroupSequenceProvider()) {
|
||||
// The group sequence is dynamically obtained from the validated
|
||||
// object
|
||||
/** @var \Symfony\Component\Validator\GroupSequenceProviderInterface $value */
|
||||
$group = $node->value->getGroupSequence();
|
||||
$cascadedGroup = Constraint::DEFAULT_GROUP;
|
||||
|
||||
if (!$group instanceof GroupSequence) {
|
||||
$group = new GroupSequence($group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($group instanceof GroupSequence) {
|
||||
// Traverse group sequence until a violation is generated
|
||||
$this->traverseGroupSequence($node, $group, $context);
|
||||
$this->traverseGroupSequence($node, $group, $cascadedGroup, $context);
|
||||
|
||||
// Skip the group sequence when validating successor nodes
|
||||
unset($node->groups[$key]);
|
||||
|
@ -135,17 +160,15 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||
* @param GroupSequence $groupSequence The group sequence
|
||||
* @param ExecutionContextInterface $context The execution context
|
||||
*/
|
||||
private function traverseGroupSequence(Node $node, GroupSequence $groupSequence, ExecutionContextInterface $context)
|
||||
private function traverseGroupSequence(Node $node, GroupSequence $groupSequence, $cascadedGroup, ExecutionContextInterface $context)
|
||||
{
|
||||
$violationCount = count($context->getViolations());
|
||||
$cascadedGroups = $cascadedGroup ? array($cascadedGroup) : null;
|
||||
|
||||
foreach ($groupSequence->groups as $groupInSequence) {
|
||||
$node = clone $node;
|
||||
$node->groups = array($groupInSequence);
|
||||
|
||||
if (null !== $groupSequence->cascadedGroup) {
|
||||
$node->cascadedGroups = array($groupSequence->cascadedGroup);
|
||||
}
|
||||
$node->cascadedGroups = $cascadedGroups;
|
||||
|
||||
$this->nodeTraverser->traverse(array($node), $context);
|
||||
|
||||
|
@ -199,44 +222,4 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||
$validator->validate($node->value, $constraint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks class nodes whether their "Default" group is replaced by a group
|
||||
* sequence and adjusts the validation groups accordingly.
|
||||
*
|
||||
* If the "Default" group is replaced for a class node, and if the validated
|
||||
* groups of the node contain the group "Default", that group is replaced by
|
||||
* the group sequence specified in the class' metadata.
|
||||
*
|
||||
* @param ClassNode $node The node
|
||||
*/
|
||||
private function replaceDefaultGroup(ClassNode $node)
|
||||
{
|
||||
if ($node->metadata->hasGroupSequence()) {
|
||||
// The group sequence is statically defined for the class
|
||||
$groupSequence = $node->metadata->getGroupSequence();
|
||||
} elseif ($node->metadata->isGroupSequenceProvider()) {
|
||||
// The group sequence is dynamically obtained from the validated
|
||||
// object
|
||||
/** @var \Symfony\Component\Validator\GroupSequenceProviderInterface $value */
|
||||
$groupSequence = $node->value->getGroupSequence();
|
||||
|
||||
if (!$groupSequence instanceof GroupSequence) {
|
||||
$groupSequence = new GroupSequence($groupSequence);
|
||||
}
|
||||
} else {
|
||||
// The "Default" group is not overridden. Quit.
|
||||
return;
|
||||
}
|
||||
|
||||
$key = array_search(Constraint::DEFAULT_GROUP, $node->groups);
|
||||
|
||||
if (false !== $key) {
|
||||
// Replace the "Default" group by the group sequence
|
||||
$node->groups[$key] = $groupSequence;
|
||||
|
||||
// Cascade the "Default" group when validating the sequence
|
||||
$groupSequence->cascadedGroup = Constraint::DEFAULT_GROUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,9 +277,6 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
*/
|
||||
private function traverseClassNode($value, $valueHash, ClassMetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context)
|
||||
{
|
||||
// Replace "Default" group by group sequence, if appropriate
|
||||
$groups = $this->replaceDefaultGroup($value, $metadata, $groups);
|
||||
|
||||
$groups = $this->validateNode($value, $valueHash, null, null, $metadata, $propertyPath, $groups, $traversalStrategy, $context);
|
||||
|
||||
if (0 === count($groups)) {
|
||||
|
@ -444,14 +441,13 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
return;
|
||||
}
|
||||
|
||||
// The "cascadedGroups" property is set by the NodeValidationVisitor when
|
||||
// traversing group sequences
|
||||
$cascadedGroups = count($cascadedGroups) > 0
|
||||
? $cascadedGroups
|
||||
: $groups;
|
||||
|
||||
$cascadingStrategy = $metadata->getCascadingStrategy();
|
||||
|
||||
// Quit unless we have an array or a cascaded object
|
||||
if (!is_array($value) && !($cascadingStrategy & CascadingStrategy::CASCADE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If no specific traversal strategy was requested when this method
|
||||
// was called, use the traversal strategy of the node's metadata
|
||||
if ($traversalStrategy & TraversalStrategy::IMPLICIT) {
|
||||
|
@ -460,6 +456,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
| ($traversalStrategy & TraversalStrategy::STOP_RECURSION);
|
||||
}
|
||||
|
||||
// The "cascadedGroups" property is set by the NodeValidationVisitor when
|
||||
// traversing group sequences
|
||||
$cascadedGroups = count($cascadedGroups) > 0
|
||||
? $cascadedGroups
|
||||
: $groups;
|
||||
|
||||
if (is_array($value)) {
|
||||
// Arrays are always traversed, independent of the specified
|
||||
// traversal strategy
|
||||
|
@ -475,21 +477,17 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
return;
|
||||
}
|
||||
|
||||
if ($cascadingStrategy & CascadingStrategy::CASCADE) {
|
||||
// If the value is a scalar, pass it anyway, because we want
|
||||
// a NoSuchMetadataException to be thrown in that case
|
||||
// (BC with Symfony < 2.5)
|
||||
$this->cascadeObject(
|
||||
$value,
|
||||
$valueHash,
|
||||
$propertyPath,
|
||||
$cascadedGroups,
|
||||
$traversalStrategy,
|
||||
$context
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
// If the value is a scalar, pass it anyway, because we want
|
||||
// a NoSuchMetadataException to be thrown in that case
|
||||
// (BC with Symfony < 2.5)
|
||||
$this->cascadeObject(
|
||||
$value,
|
||||
$valueHash,
|
||||
$propertyPath,
|
||||
$cascadedGroups,
|
||||
$traversalStrategy,
|
||||
$context
|
||||
);
|
||||
|
||||
// Currently, the traversal strategy can only be TRAVERSE for a
|
||||
// generic node if the cascading strategy is CASCADE. Thus, traversable
|
||||
|
@ -590,6 +588,8 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
// simply continue traversal (if possible)
|
||||
|
||||
foreach ($groups as $key => $group) {
|
||||
$cascadedGroup = null;
|
||||
|
||||
// Even if we remove the following clause, the constraints on an
|
||||
// object won't be validated again due to the measures taken in
|
||||
// validateNodeForGroup().
|
||||
|
@ -608,11 +608,36 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
}
|
||||
|
||||
$context->markObjectAsValidatedForGroup($valueHash, $groupHash);
|
||||
|
||||
// Replace the "Default" group by the group sequence defined
|
||||
// for the class, if applicable
|
||||
// This is done after checking the cache, so that
|
||||
// spl_object_hash() isn't called for this sequence and
|
||||
// "Default" is used instead in the cache. This is useful
|
||||
// if the getters below return different group sequences in
|
||||
// every call.
|
||||
if (Constraint::DEFAULT_GROUP === $group) {
|
||||
if ($metadata->hasGroupSequence()) {
|
||||
// The group sequence is statically defined for the class
|
||||
$group = $metadata->getGroupSequence();
|
||||
$cascadedGroup = Constraint::DEFAULT_GROUP;
|
||||
} elseif ($metadata->isGroupSequenceProvider()) {
|
||||
// The group sequence is dynamically obtained from the validated
|
||||
// object
|
||||
/** @var \Symfony\Component\Validator\GroupSequenceProviderInterface $value */
|
||||
$group = $value->getGroupSequence();
|
||||
$cascadedGroup = Constraint::DEFAULT_GROUP;
|
||||
|
||||
if (!$group instanceof GroupSequence) {
|
||||
$group = new GroupSequence($group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($group instanceof GroupSequence) {
|
||||
// Traverse group sequence until a violation is generated
|
||||
$this->stepThroughGroupSequence($value, $valueHash, $container, $containerHash, $metadata, $propertyPath, $traversalStrategy, $group, $context);
|
||||
$this->stepThroughGroupSequence($value, $valueHash, $container, $containerHash, $metadata, $propertyPath, $traversalStrategy, $group, $cascadedGroup, $context);
|
||||
|
||||
// Skip the group sequence when validating successor nodes
|
||||
unset($groups[$key]);
|
||||
|
@ -637,17 +662,13 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
* @param GroupSequence $groupSequence The group sequence
|
||||
* @param ExecutionContextInterface $context The execution context
|
||||
*/
|
||||
private function stepThroughGroupSequence($value, $valueHash, $container, $containerHash, MetadataInterface $metadata = null, $propertyPath, $traversalStrategy, GroupSequence $groupSequence, ExecutionContextInterface $context)
|
||||
private function stepThroughGroupSequence($value, $valueHash, $container, $containerHash, MetadataInterface $metadata = null, $propertyPath, $traversalStrategy, GroupSequence $groupSequence, $cascadedGroup, ExecutionContextInterface $context)
|
||||
{
|
||||
$violationCount = count($context->getViolations());
|
||||
$cascadedGroups = $cascadedGroup ? array($cascadedGroup) : null;
|
||||
|
||||
foreach ($groupSequence->groups as $groupInSequence) {
|
||||
$groups = array($groupInSequence);
|
||||
$cascadedGroups = null;
|
||||
|
||||
if (null !== $groupSequence->cascadedGroup) {
|
||||
$cascadedGroups = array($groupSequence->cascadedGroup);
|
||||
}
|
||||
|
||||
if ($metadata instanceof ClassMetadataInterface) {
|
||||
$this->traverseClassNode(
|
||||
|
@ -727,44 +748,4 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||
$validator->validate($value, $constraint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param ClassMetadataInterface $metadata
|
||||
* @param array $groups
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function replaceDefaultGroup($value, ClassMetadataInterface $metadata, array $groups)
|
||||
{
|
||||
$groupSequence = null;
|
||||
|
||||
if ($metadata->hasGroupSequence()) {
|
||||
// The group sequence is statically defined for the class
|
||||
$groupSequence = $metadata->getGroupSequence();
|
||||
} elseif ($metadata->isGroupSequenceProvider()) {
|
||||
// The group sequence is dynamically obtained from the validated
|
||||
// object
|
||||
/** @var \Symfony\Component\Validator\GroupSequenceProviderInterface $value */
|
||||
$groupSequence = $value->getGroupSequence();
|
||||
|
||||
if (!$groupSequence instanceof GroupSequence) {
|
||||
$groupSequence = new GroupSequence($groupSequence);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $groupSequence) {
|
||||
$key = array_search(Constraint::DEFAULT_GROUP, $groups);
|
||||
|
||||
if (false !== $key) {
|
||||
// Replace the "Default" group by the group sequence
|
||||
$groups[$key] = $groupSequence;
|
||||
|
||||
// Cascade the "Default" group when validating the sequence
|
||||
$groupSequence->cascadedGroup = Constraint::DEFAULT_GROUP;
|
||||
}
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue