1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Validator\Validator;
13
14use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
15use Symfony\Component\Validator\Context\ExecutionContextFactoryInterface;
16use Symfony\Component\Validator\Context\ExecutionContextInterface;
17use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
18use Symfony\Component\Validator\ObjectInitializerInterface;
19
20/**
21 * Recursive implementation of {@link ValidatorInterface}.
22 *
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 */
25class RecursiveValidator implements ValidatorInterface
26{
27    protected $contextFactory;
28    protected $metadataFactory;
29    protected $validatorFactory;
30    protected $objectInitializers;
31
32    /**
33     * Creates a new validator.
34     *
35     * @param ExecutionContextFactoryInterface    $contextFactory     The factory for
36     *                                                                creating new contexts
37     * @param MetadataFactoryInterface            $metadataFactory    The factory for
38     *                                                                fetching the metadata
39     *                                                                of validated objects
40     * @param ConstraintValidatorFactoryInterface $validatorFactory   The factory for creating
41     *                                                                constraint validators
42     * @param ObjectInitializerInterface[]        $objectInitializers The object initializers
43     */
44    public function __construct(ExecutionContextFactoryInterface $contextFactory, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, array $objectInitializers = [])
45    {
46        $this->contextFactory = $contextFactory;
47        $this->metadataFactory = $metadataFactory;
48        $this->validatorFactory = $validatorFactory;
49        $this->objectInitializers = $objectInitializers;
50    }
51
52    /**
53     * {@inheritdoc}
54     */
55    public function startContext($root = null)
56    {
57        return new RecursiveContextualValidator(
58            $this->contextFactory->createContext($this, $root),
59            $this->metadataFactory,
60            $this->validatorFactory,
61            $this->objectInitializers
62        );
63    }
64
65    /**
66     * {@inheritdoc}
67     */
68    public function inContext(ExecutionContextInterface $context)
69    {
70        return new RecursiveContextualValidator(
71            $context,
72            $this->metadataFactory,
73            $this->validatorFactory,
74            $this->objectInitializers
75        );
76    }
77
78    /**
79     * {@inheritdoc}
80     */
81    public function getMetadataFor($object)
82    {
83        return $this->metadataFactory->getMetadataFor($object);
84    }
85
86    /**
87     * {@inheritdoc}
88     */
89    public function hasMetadataFor($object)
90    {
91        return $this->metadataFactory->hasMetadataFor($object);
92    }
93
94    /**
95     * {@inheritdoc}
96     */
97    public function validate($value, $constraints = null, $groups = null)
98    {
99        return $this->startContext($value)
100            ->validate($value, $constraints, $groups)
101            ->getViolations();
102    }
103
104    /**
105     * {@inheritdoc}
106     */
107    public function validateProperty($object, $propertyName, $groups = null)
108    {
109        return $this->startContext($object)
110            ->validateProperty($object, $propertyName, $groups)
111            ->getViolations();
112    }
113
114    /**
115     * {@inheritdoc}
116     */
117    public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null)
118    {
119        // If a class name is passed, take $value as root
120        return $this->startContext(\is_object($objectOrClass) ? $objectOrClass : $value)
121            ->validatePropertyValue($objectOrClass, $propertyName, $value, $groups)
122            ->getViolations();
123    }
124}
125