private function RecursiveContextualValidator::validateClassNode in Plug 7
Validates a class node.
A class node is a combination of an object with a {@link ClassMetadataInterface} instance. Each class node (conceptionally) has zero or more succeeding property nodes:
(Article:class node) \ ($title:property node)
This method validates the passed objects against all constraints defined at class level. It furthermore triggers the validation of each of the class' properties against the constraints for that property.
If the selected traversal strategy allows traversal, the object is iterated and each nested object is validated against its own constraints. The object is not traversed if traversal is disabled in the class metadata.
If the passed groups contain the group "Default", the validator will check whether the "Default" group has been replaced by a group sequence in the class metadata. If this is the case, the group sequence is validated instead.
Parameters
object $object The validated object:
string $cacheKey The key for caching: the validated object
ClassMetadataInterface $metadata The class metadata of: the object
string $propertyPath The property path leading: to the object
string[] $groups The groups in which the: object should be validated
string[]|null $cascadedGroups The groups in which: cascaded objects should be validated
int $traversalStrategy The strategy used for: traversing the object
ExecutionContextInterface $context The current execution context:
Throws
UnsupportedMetadataException If a property metadata does not implement {@link PropertyMetadataInterface}
ConstraintDefinitionException If traversal was enabled but the object does not implement {@link \Traversable}
See also
2 calls to RecursiveContextualValidator::validateClassNode()
- RecursiveContextualValidator::stepThroughGroupSequence in lib/
Symfony/ validator/ Symfony/ Component/ Validator/ Validator/ RecursiveContextualValidator.php - Sequentially validates a node's value in each group of a group sequence.
- RecursiveContextualValidator::validateObject in lib/
Symfony/ validator/ Symfony/ Component/ Validator/ Validator/ RecursiveContextualValidator.php - Validates an object against the constraints defined for its class.
File
- lib/
Symfony/ validator/ Symfony/ Component/ Validator/ Validator/ RecursiveContextualValidator.php, line 484
Class
- RecursiveContextualValidator
- Recursive implementation of {@link ContextualValidatorInterface}.
Namespace
Symfony\Component\Validator\ValidatorCode
private function validateClassNode($object, $cacheKey, ClassMetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context) {
$context
->setNode($object, $object, $metadata, $propertyPath);
if (!$context
->isObjectInitialized($cacheKey)) {
foreach ($this->objectInitializers as $initializer) {
$initializer
->initialize($object);
}
$context
->markObjectAsInitialized($cacheKey);
}
foreach ($groups as $key => $group) {
// If the "Default" group is replaced by a group sequence, remember
// to cascade the "Default" group when traversing the group
// sequence
$defaultOverridden = false;
// Use the object hash for group sequences
$groupHash = is_object($group) ? spl_object_hash($group) : $group;
if ($context
->isGroupValidated($cacheKey, $groupHash)) {
// Skip this group when validating the properties and when
// traversing the object
unset($groups[$key]);
continue;
}
$context
->markGroupAsValidated($cacheKey, $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();
$defaultOverridden = true;
}
elseif ($metadata
->isGroupSequenceProvider()) {
// The group sequence is dynamically obtained from the validated
// object
/* @var \Symfony\Component\Validator\GroupSequenceProviderInterface $object */
$group = $object
->getGroupSequence();
$defaultOverridden = true;
if (!$group instanceof GroupSequence) {
$group = new GroupSequence($group);
}
}
}
// If the groups (=[<G1,G2>,G3,G4]) contain a group sequence
// (=<G1,G2>), then call validateClassNode() with each entry of the
// group sequence and abort if necessary (G1, G2)
if ($group instanceof GroupSequence) {
$this
->stepThroughGroupSequence($object, $object, $cacheKey, $metadata, $propertyPath, $traversalStrategy, $group, $defaultOverridden ? Constraint::DEFAULT_GROUP : null, $context);
// Skip the group sequence when validating properties, because
// stepThroughGroupSequence() already validates the properties
unset($groups[$key]);
continue;
}
$this
->validateInGroup($object, $cacheKey, $metadata, $group, $context);
}
// If no more groups should be validated for the property nodes,
// we can safely quit
if (0 === count($groups)) {
return;
}
// Validate all properties against their constraints
foreach ($metadata
->getConstrainedProperties() as $propertyName) {
// If constraints are defined both on the getter of a property as
// well as on the property itself, then getPropertyMetadata()
// returns two metadata objects, not just one
foreach ($metadata
->getPropertyMetadata($propertyName) as $propertyMetadata) {
if (!$propertyMetadata instanceof PropertyMetadataInterface) {
throw new UnsupportedMetadataException(sprintf('The property metadata instances should implement ' . '"Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface", ' . 'got: "%s".', is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)));
}
$propertyValue = $propertyMetadata
->getPropertyValue($object);
$this
->validateGenericNode($propertyValue, $object, $cacheKey . ':' . $propertyName, $propertyMetadata, PropertyPath::append($propertyPath, $propertyName), $groups, $cascadedGroups, TraversalStrategy::IMPLICIT, $context);
}
}
// If no specific traversal strategy was requested when this method
// was called, use the traversal strategy of the class' metadata
if ($traversalStrategy & TraversalStrategy::IMPLICIT) {
// Keep the STOP_RECURSION flag, if it was set
$traversalStrategy = $metadata
->getTraversalStrategy() | $traversalStrategy & TraversalStrategy::STOP_RECURSION;
}
// Traverse only if IMPLICIT or TRAVERSE
if (!($traversalStrategy & (TraversalStrategy::IMPLICIT | TraversalStrategy::TRAVERSE))) {
return;
}
// If IMPLICIT, stop unless we deal with a Traversable
if ($traversalStrategy & TraversalStrategy::IMPLICIT && !$object instanceof \Traversable) {
return;
}
// If TRAVERSE, fail if we have no Traversable
if (!$object instanceof \Traversable) {
// Must throw a ConstraintDefinitionException for backwards
// compatibility reasons with Symfony < 2.5
throw new ConstraintDefinitionException(sprintf('Traversal was enabled for "%s", but this class ' . 'does not implement "\\Traversable".', get_class($object)));
}
$this
->validateEachObjectIn($object, $propertyPath, $groups, $traversalStrategy & TraversalStrategy::STOP_RECURSION, $context);
}