Version 1
[yaffs-website] / vendor / symfony / validator / Constraints / CollectionValidator.php
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
12 namespace Symfony\Component\Validator\Constraints;
13
14 use Symfony\Component\Validator\Constraint;
15 use Symfony\Component\Validator\ConstraintValidator;
16 use Symfony\Component\Validator\Context\ExecutionContextInterface;
17 use Symfony\Component\Validator\Exception\UnexpectedTypeException;
18
19 /**
20  * @author Bernhard Schussek <bschussek@gmail.com>
21  */
22 class CollectionValidator extends ConstraintValidator
23 {
24     /**
25      * {@inheritdoc}
26      */
27     public function validate($value, Constraint $constraint)
28     {
29         if (!$constraint instanceof Collection) {
30             throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Collection');
31         }
32
33         if (null === $value) {
34             return;
35         }
36
37         if (!is_array($value) && !($value instanceof \Traversable && $value instanceof \ArrayAccess)) {
38             throw new UnexpectedTypeException($value, 'array or Traversable and ArrayAccess');
39         }
40
41         // We need to keep the initialized context when CollectionValidator
42         // calls itself recursively (Collection constraints can be nested).
43         // Since the context of the validator is overwritten when initialize()
44         // is called for the nested constraint, the outer validator is
45         // acting on the wrong context when the nested validation terminates.
46         //
47         // A better solution - which should be approached in Symfony 3.0 - is to
48         // remove the initialize() method and pass the context as last argument
49         // to validate() instead.
50         $context = $this->context;
51
52         foreach ($constraint->fields as $field => $fieldConstraint) {
53             // bug fix issue #2779
54             $existsInArray = is_array($value) && array_key_exists($field, $value);
55             $existsInArrayAccess = $value instanceof \ArrayAccess && $value->offsetExists($field);
56
57             if ($existsInArray || $existsInArrayAccess) {
58                 if (count($fieldConstraint->constraints) > 0) {
59                     if ($context instanceof ExecutionContextInterface) {
60                         $context->getValidator()
61                             ->inContext($context)
62                             ->atPath('['.$field.']')
63                             ->validate($value[$field], $fieldConstraint->constraints);
64                     } else {
65                         // 2.4 API
66                         $context->validateValue($value[$field], $fieldConstraint->constraints, '['.$field.']');
67                     }
68                 }
69             } elseif (!$fieldConstraint instanceof Optional && !$constraint->allowMissingFields) {
70                 if ($context instanceof ExecutionContextInterface) {
71                     $context->buildViolation($constraint->missingFieldsMessage)
72                         ->atPath('['.$field.']')
73                         ->setParameter('{{ field }}', $this->formatValue($field))
74                         ->setInvalidValue(null)
75                         ->setCode(Collection::MISSING_FIELD_ERROR)
76                         ->addViolation();
77                 } else {
78                     $this->buildViolationInContext($context, $constraint->missingFieldsMessage)
79                         ->atPath('['.$field.']')
80                         ->setParameter('{{ field }}', $this->formatValue($field))
81                         ->setInvalidValue(null)
82                         ->setCode(Collection::MISSING_FIELD_ERROR)
83                         ->addViolation();
84                 }
85             }
86         }
87
88         if (!$constraint->allowExtraFields) {
89             foreach ($value as $field => $fieldValue) {
90                 if (!isset($constraint->fields[$field])) {
91                     if ($context instanceof ExecutionContextInterface) {
92                         $context->buildViolation($constraint->extraFieldsMessage)
93                             ->atPath('['.$field.']')
94                             ->setParameter('{{ field }}', $this->formatValue($field))
95                             ->setInvalidValue($fieldValue)
96                             ->setCode(Collection::NO_SUCH_FIELD_ERROR)
97                             ->addViolation();
98                     } else {
99                         $this->buildViolationInContext($context, $constraint->extraFieldsMessage)
100                             ->atPath('['.$field.']')
101                             ->setParameter('{{ field }}', $this->formatValue($field))
102                             ->setInvalidValue($fieldValue)
103                             ->setCode(Collection::NO_SUCH_FIELD_ERROR)
104                             ->addViolation();
105                     }
106                 }
107             }
108         }
109     }
110 }