[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);
|
$context->setNode($node->value, $node->metadata, $node->propertyPath);
|
||||||
|
|
||||||
if ($node instanceof ClassNode) {
|
if ($node instanceof ClassNode) {
|
||||||
$this->replaceDefaultGroup($node);
|
|
||||||
|
|
||||||
$objectHash = spl_object_hash($node->value);
|
$objectHash = spl_object_hash($node->value);
|
||||||
} elseif ($node instanceof PropertyNode) {
|
} elseif ($node instanceof PropertyNode) {
|
||||||
$objectHash = spl_object_hash($node->object);
|
$objectHash = spl_object_hash($node->object);
|
||||||
@ -88,6 +86,8 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||||||
// simply continue traversal (if possible)
|
// simply continue traversal (if possible)
|
||||||
|
|
||||||
foreach ($node->groups as $key => $group) {
|
foreach ($node->groups as $key => $group) {
|
||||||
|
$cascadedGroup = null;
|
||||||
|
|
||||||
// Even if we remove the following clause, the constraints on an
|
// Even if we remove the following clause, the constraints on an
|
||||||
// object won't be validated again due to the measures taken in
|
// object won't be validated again due to the measures taken in
|
||||||
// validateNodeForGroup().
|
// validateNodeForGroup().
|
||||||
@ -106,11 +106,36 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
$context->markObjectAsValidatedForGroup($objectHash, $groupHash);
|
$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) {
|
if ($group instanceof GroupSequence) {
|
||||||
// Traverse group sequence until a violation is generated
|
// 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
|
// Skip the group sequence when validating successor nodes
|
||||||
unset($node->groups[$key]);
|
unset($node->groups[$key]);
|
||||||
@ -135,17 +160,15 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||||||
* @param GroupSequence $groupSequence The group sequence
|
* @param GroupSequence $groupSequence The group sequence
|
||||||
* @param ExecutionContextInterface $context The execution context
|
* @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());
|
$violationCount = count($context->getViolations());
|
||||||
|
$cascadedGroups = $cascadedGroup ? array($cascadedGroup) : null;
|
||||||
|
|
||||||
foreach ($groupSequence->groups as $groupInSequence) {
|
foreach ($groupSequence->groups as $groupInSequence) {
|
||||||
$node = clone $node;
|
$node = clone $node;
|
||||||
$node->groups = array($groupInSequence);
|
$node->groups = array($groupInSequence);
|
||||||
|
$node->cascadedGroups = $cascadedGroups;
|
||||||
if (null !== $groupSequence->cascadedGroup) {
|
|
||||||
$node->cascadedGroups = array($groupSequence->cascadedGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->nodeTraverser->traverse(array($node), $context);
|
$this->nodeTraverser->traverse(array($node), $context);
|
||||||
|
|
||||||
@ -199,44 +222,4 @@ class NodeValidationVisitor extends AbstractVisitor
|
|||||||
$validator->validate($node->value, $constraint);
|
$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)
|
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);
|
$groups = $this->validateNode($value, $valueHash, null, null, $metadata, $propertyPath, $groups, $traversalStrategy, $context);
|
||||||
|
|
||||||
if (0 === count($groups)) {
|
if (0 === count($groups)) {
|
||||||
@ -444,14 +441,13 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "cascadedGroups" property is set by the NodeValidationVisitor when
|
|
||||||
// traversing group sequences
|
|
||||||
$cascadedGroups = count($cascadedGroups) > 0
|
|
||||||
? $cascadedGroups
|
|
||||||
: $groups;
|
|
||||||
|
|
||||||
$cascadingStrategy = $metadata->getCascadingStrategy();
|
$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
|
// If no specific traversal strategy was requested when this method
|
||||||
// was called, use the traversal strategy of the node's metadata
|
// was called, use the traversal strategy of the node's metadata
|
||||||
if ($traversalStrategy & TraversalStrategy::IMPLICIT) {
|
if ($traversalStrategy & TraversalStrategy::IMPLICIT) {
|
||||||
@ -460,6 +456,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
| ($traversalStrategy & TraversalStrategy::STOP_RECURSION);
|
| ($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)) {
|
if (is_array($value)) {
|
||||||
// Arrays are always traversed, independent of the specified
|
// Arrays are always traversed, independent of the specified
|
||||||
// traversal strategy
|
// traversal strategy
|
||||||
@ -475,21 +477,17 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cascadingStrategy & CascadingStrategy::CASCADE) {
|
// If the value is a scalar, pass it anyway, because we want
|
||||||
// If the value is a scalar, pass it anyway, because we want
|
// a NoSuchMetadataException to be thrown in that case
|
||||||
// a NoSuchMetadataException to be thrown in that case
|
// (BC with Symfony < 2.5)
|
||||||
// (BC with Symfony < 2.5)
|
$this->cascadeObject(
|
||||||
$this->cascadeObject(
|
$value,
|
||||||
$value,
|
$valueHash,
|
||||||
$valueHash,
|
$propertyPath,
|
||||||
$propertyPath,
|
$cascadedGroups,
|
||||||
$cascadedGroups,
|
$traversalStrategy,
|
||||||
$traversalStrategy,
|
$context
|
||||||
$context
|
);
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currently, the traversal strategy can only be TRAVERSE for a
|
// Currently, the traversal strategy can only be TRAVERSE for a
|
||||||
// generic node if the cascading strategy is CASCADE. Thus, traversable
|
// generic node if the cascading strategy is CASCADE. Thus, traversable
|
||||||
@ -590,6 +588,8 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
// simply continue traversal (if possible)
|
// simply continue traversal (if possible)
|
||||||
|
|
||||||
foreach ($groups as $key => $group) {
|
foreach ($groups as $key => $group) {
|
||||||
|
$cascadedGroup = null;
|
||||||
|
|
||||||
// Even if we remove the following clause, the constraints on an
|
// Even if we remove the following clause, the constraints on an
|
||||||
// object won't be validated again due to the measures taken in
|
// object won't be validated again due to the measures taken in
|
||||||
// validateNodeForGroup().
|
// validateNodeForGroup().
|
||||||
@ -608,11 +608,36 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
$context->markObjectAsValidatedForGroup($valueHash, $groupHash);
|
$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) {
|
if ($group instanceof GroupSequence) {
|
||||||
// Traverse group sequence until a violation is generated
|
// 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
|
// Skip the group sequence when validating successor nodes
|
||||||
unset($groups[$key]);
|
unset($groups[$key]);
|
||||||
@ -637,17 +662,13 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
* @param GroupSequence $groupSequence The group sequence
|
* @param GroupSequence $groupSequence The group sequence
|
||||||
* @param ExecutionContextInterface $context The execution context
|
* @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());
|
$violationCount = count($context->getViolations());
|
||||||
|
$cascadedGroups = $cascadedGroup ? array($cascadedGroup) : null;
|
||||||
|
|
||||||
foreach ($groupSequence->groups as $groupInSequence) {
|
foreach ($groupSequence->groups as $groupInSequence) {
|
||||||
$groups = array($groupInSequence);
|
$groups = array($groupInSequence);
|
||||||
$cascadedGroups = null;
|
|
||||||
|
|
||||||
if (null !== $groupSequence->cascadedGroup) {
|
|
||||||
$cascadedGroups = array($groupSequence->cascadedGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($metadata instanceof ClassMetadataInterface) {
|
if ($metadata instanceof ClassMetadataInterface) {
|
||||||
$this->traverseClassNode(
|
$this->traverseClassNode(
|
||||||
@ -727,44 +748,4 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
$validator->validate($value, $constraint);
|
$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
Block a user