Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

190 lines (160 sloc) 7.132 kb
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Mapping\ClassMetadataFactoryInterface;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\MemberMetadata;
/**
* Responsible for walking over and initializing validation on different
* types of items.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
*/
class GraphWalker
{
protected $context;
protected $validatorFactory;
protected $metadataFactory;
protected $validatorInitializers = array();
protected $validatedObjects = array();
public function __construct($root, ClassMetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $factory, array $validatorInitializers = array())
{
$this->context = new ExecutionContext($root, $this, $metadataFactory);
$this->validatorFactory = $factory;
$this->metadataFactory = $metadataFactory;
$this->validatorInitializers = $validatorInitializers;
}
/**
* @return ConstraintViolationList
*/
public function getViolations()
{
return $this->context->getViolations();
}
/**
* Initialize validation on the given object using the given metadata
* instance and validation group.
*
* @param ClassMetadata $metadata
* @param object $object The object to validate
* @param string $group The validator group to use for validation
* @param string $propertyPath
*/
public function walkObject(ClassMetadata $metadata, $object, $group, $propertyPath)
{
foreach ($this->validatorInitializers as $initializer) {
if (!$initializer instanceof ObjectInitializerInterface) {
throw new \LogicException('Validator initializers must implement ObjectInitializerInterface.');
}
$initializer->initialize($object);
}
$this->context->setCurrentClass($metadata->getClassName());
if ($group === Constraint::DEFAULT_GROUP && $metadata->hasGroupSequence()) {
$groups = $metadata->getGroupSequence();
foreach ($groups as $group) {
$this->walkObjectForGroup($metadata, $object, $group, $propertyPath, Constraint::DEFAULT_GROUP);
if (count($this->getViolations()) > 0) {
break;
}
}
} else {
$this->walkObjectForGroup($metadata, $object, $group, $propertyPath);
}
}
protected function walkObjectForGroup(ClassMetadata $metadata, $object, $group, $propertyPath, $propagatedGroup = null)
{
$hash = spl_object_hash($object);
// Exit, if the object is already validated for the current group
if (isset($this->validatedObjects[$hash])) {
if (isset($this->validatedObjects[$hash][$group])) {
return;
}
} else {
$this->validatedObjects[$hash] = array();
}
// Remember validating this object before starting and possibly
// traversing the object graph
$this->validatedObjects[$hash][$group] = true;
foreach ($metadata->findConstraints($group) as $constraint) {
$this->walkConstraint($constraint, $object, $group, $propertyPath);
}
if (null !== $object) {
foreach ($metadata->getConstrainedProperties() as $property) {
$localPropertyPath = empty($propertyPath) ? $property : $propertyPath.'.'.$property;
$this->walkProperty($metadata, $property, $object, $group, $localPropertyPath, $propagatedGroup);
}
}
}
public function walkProperty(ClassMetadata $metadata, $property, $object, $group, $propertyPath, $propagatedGroup = null)
{
foreach ($metadata->getMemberMetadatas($property) as $member) {
$this->walkMember($member, $member->getValue($object), $group, $propertyPath, $propagatedGroup);
}
}
public function walkPropertyValue(ClassMetadata $metadata, $property, $value, $group, $propertyPath)
{
foreach ($metadata->getMemberMetadatas($property) as $member) {
$this->walkMember($member, $value, $group, $propertyPath);
}
}
protected function walkMember(MemberMetadata $metadata, $value, $group, $propertyPath, $propagatedGroup = null)
{
$this->context->setCurrentClass($metadata->getClassName());
$this->context->setCurrentProperty($metadata->getPropertyName());
foreach ($metadata->findConstraints($group) as $constraint) {
$this->walkConstraint($constraint, $value, $group, $propertyPath);
}
if ($metadata->isCascaded()) {
$this->walkReference($value, $propagatedGroup ?: $group, $propertyPath, $metadata->isCollectionCascaded());
}
}
public function walkReference($value, $group, $propertyPath, $traverse)
{
if (null !== $value) {
if (!is_object($value) && !is_array($value)) {
throw new UnexpectedTypeException($value, 'object or array');
}
if ($traverse && (is_array($value) || $value instanceof \Traversable)) {
foreach ($value as $key => $element) {
// Ignore any scalar values in the collection
if (is_object($element) || is_array($element)) {
$this->walkReference($element, $group, $propertyPath.'['.$key.']', $traverse);
}
}
}
if (is_object($value)) {
$metadata = $this->metadataFactory->getClassMetadata(get_class($value));
$this->walkObject($metadata, $value, $group, $propertyPath);
}
}
}
public function walkConstraint(Constraint $constraint, $value, $group, $propertyPath)
{
$validator = $this->validatorFactory->getInstance($constraint);
$this->context->setPropertyPath($propertyPath);
$this->context->setGroup($group);
$validator->initialize($this->context);
if (!$validator->isValid($value, $constraint)) {
// Resetting the property path. This is needed because some
// validators, like CollectionValidator, use the walker internally
// and so change the context.
$this->context->setPropertyPath($propertyPath);
$this->context->addViolation(
$validator->getMessageTemplate(),
$validator->getMessageParameters(),
$value
);
}
}
}
Jump to Line
Something went wrong with that request. Please try again.