1<?php
2
3namespace Drupal\Core\TypedData\Validation;
4
5use Drupal\Core\Validation\TranslatorInterface;
6use Symfony\Component\Validator\Constraint;
7use Symfony\Component\Validator\ConstraintViolation;
8use Symfony\Component\Validator\ConstraintViolationList;
9use Symfony\Component\Validator\Context\ExecutionContextInterface;
10use Symfony\Component\Validator\Mapping\MetadataInterface;
11use Symfony\Component\Validator\Util\PropertyPath;
12use Symfony\Component\Validator\Validator\ValidatorInterface;
13
14/**
15 * Defines an execution context class.
16 *
17 * We do not use the context provided by Symfony as it is marked internal, so
18 * this class is pretty much the same, but has some code style changes as well
19 * as exceptions for methods we don't support.
20 */
21class ExecutionContext implements ExecutionContextInterface {
22
23  /**
24   * @var \Symfony\Component\Validator\Validator\ValidatorInterface
25   */
26  protected $validator;
27
28  /**
29   * The root value of the validated object graph.
30   *
31   * @var mixed
32   */
33  protected $root;
34
35  /**
36   * @var \Drupal\Core\Validation\TranslatorInterface
37   */
38  protected $translator;
39
40  /**
41   * @var string
42   */
43  protected $translationDomain;
44
45  /**
46   * The violations generated in the current context.
47   *
48   * @var \Symfony\Component\Validator\ConstraintViolationList
49   */
50  protected $violations;
51
52  /**
53   * The currently validated value.
54   *
55   * @var mixed
56   */
57  protected $value;
58
59  /**
60   * The currently validated typed data object.
61   *
62   * @var \Drupal\Core\TypedData\TypedDataInterface
63   */
64  protected $data;
65
66  /**
67   * The property path leading to the current value.
68   *
69   * @var string
70   */
71  protected $propertyPath = '';
72
73  /**
74   * The current validation metadata.
75   *
76   * @var \Symfony\Component\Validator\Mapping\MetadataInterface|null
77   */
78  protected $metadata;
79
80  /**
81   * The currently validated group.
82   *
83   * @var string|null
84   */
85  protected $group;
86
87  /**
88   * The currently validated constraint.
89   *
90   * @var \Symfony\Component\Validator\Constraint|null
91   */
92  protected $constraint;
93
94  /**
95   * Stores which objects have been validated in which group.
96   *
97   * @var array
98   */
99  protected $validatedObjects = [];
100
101  /**
102   * Stores which class constraint has been validated for which object.
103   *
104   * @var array
105   */
106  protected $validatedConstraints = [];
107
108  /**
109   * Creates a new ExecutionContext.
110   *
111   * @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
112   *   The validator.
113   * @param mixed $root
114   *   The root.
115   * @param \Drupal\Core\Validation\TranslatorInterface $translator
116   *   The translator.
117   * @param string $translationDomain
118   *   (optional) The translation domain.
119   *
120   * @internal Called by \Drupal\Core\TypedData\Validation\ExecutionContextFactory.
121   *    Should not be used in user code.
122   */
123  public function __construct(ValidatorInterface $validator, $root, TranslatorInterface $translator, $translationDomain = NULL) {
124    $this->validator = $validator;
125    $this->root = $root;
126    $this->translator = $translator;
127    $this->translationDomain = $translationDomain;
128    $this->violations = new ConstraintViolationList();
129  }
130
131  /**
132   * {@inheritdoc}
133   */
134  public function setNode($value, $object, MetadataInterface $metadata = NULL, $propertyPath) {
135    $this->value = $value;
136    $this->data = $object;
137    $this->metadata = $metadata;
138    $this->propertyPath = (string) $propertyPath;
139  }
140
141  /**
142   * {@inheritdoc}
143   */
144  public function setGroup($group) {
145    $this->group = $group;
146  }
147
148  /**
149   * {@inheritdoc}
150   */
151  public function setConstraint(Constraint $constraint) {
152    $this->constraint = $constraint;
153  }
154
155  /**
156   * {@inheritdoc}
157   */
158  public function addViolation($message, array $parameters = [], $invalidValue = NULL, $plural = NULL, $code = NULL) {
159    // The parameters $invalidValue and following are ignored by the new
160    // API, as they are not present in the new interface anymore.
161    // You should use buildViolation() instead.
162    if (func_num_args() > 2) {
163      throw new \LogicException('Legacy validator API is unsupported.');
164    }
165
166    $this->violations->add(new ConstraintViolation($this->translator->trans($message, $parameters, $this->translationDomain), $message, $parameters, $this->root, $this->propertyPath, $this->value, NULL, NULL, $this->constraint));
167  }
168
169  /**
170   * {@inheritdoc}
171   */
172  public function buildViolation($message, array $parameters = []) {
173    return new ConstraintViolationBuilder($this->violations, $this->constraint, $message, $parameters, $this->root, $this->propertyPath, $this->value, $this->translator, $this->translationDomain);
174  }
175
176  /**
177   * {@inheritdoc}
178   */
179  public function getViolations() {
180    return $this->violations;
181  }
182
183  /**
184   * {@inheritdoc}
185   */
186  public function getValidator() {
187    return $this->validator;
188  }
189
190  /**
191   * {@inheritdoc}
192   */
193  public function getRoot() {
194    return $this->root;
195  }
196
197  /**
198   * {@inheritdoc}
199   */
200  public function getValue() {
201    return $this->value;
202  }
203
204  /**
205   * {@inheritdoc}
206   */
207  public function getObject() {
208    return $this->data;
209  }
210
211  /**
212   * {@inheritdoc}
213   */
214  public function getMetadata() {
215    return $this->metadata;
216  }
217
218  /**
219   * {@inheritdoc}
220   */
221  public function getGroup() {
222    return Constraint::DEFAULT_GROUP;
223  }
224
225  /**
226   * {@inheritdoc}
227   */
228  public function getClassName() {
229    return get_class($this->data);
230  }
231
232  /**
233   * {@inheritdoc}
234   */
235  public function getPropertyName() {
236    return $this->data->getName();
237  }
238
239  /**
240   * {@inheritdoc}
241   */
242  public function getPropertyPath($sub_path = '') {
243    return PropertyPath::append($this->propertyPath, $sub_path);
244  }
245
246  /**
247   * {@inheritdoc}
248   */
249  public function addViolationAt($subPath, $message, array $parameters = [], $invalidValue = NULL, $plural = NULL, $code = NULL) {
250    throw new \LogicException('Legacy validator API is unsupported.');
251  }
252
253  /**
254   * {@inheritdoc}
255   */
256  public function validate($value, $subPath = '', $groups = NULL, $traverse = FALSE, $deep = FALSE) {
257    throw new \LogicException('Legacy validator API is unsupported.');
258  }
259
260  /**
261   * {@inheritdoc}
262   */
263  public function markConstraintAsValidated($cache_key, $constraint_hash) {
264    $this->validatedConstraints[$cache_key . ':' . $constraint_hash] = TRUE;
265  }
266
267  /**
268   * {@inheritdoc}
269   */
270  public function isConstraintValidated($cache_key, $constraint_hash) {
271    return isset($this->validatedConstraints[$cache_key . ':' . $constraint_hash]);
272  }
273
274  /**
275   * {@inheritdoc}
276   */
277  public function validateValue($value, $constraints, $subPath = '', $groups = NULL) {
278    throw new \LogicException('Legacy validator API is unsupported.');
279  }
280
281  /**
282   * {@inheritdoc}
283   */
284  public function markGroupAsValidated($cache_key, $group_hash) {
285    $this->validatedObjects[$cache_key][$group_hash] = TRUE;
286  }
287
288  /**
289   * {@inheritdoc}
290   */
291  public function isGroupValidated($cache_key, $group_hash) {
292    return isset($this->validatedObjects[$cache_key][$group_hash]);
293  }
294
295  /**
296   * {@inheritdoc}
297   */
298  public function markObjectAsInitialized($cache_key) {
299    // Not supported, so nothing todo.
300  }
301
302  /**
303   * {@inheritdoc}
304   */
305  public function isObjectInitialized($cache_key) {
306    // Not supported, so nothing todo.
307  }
308
309  /**
310   * {@inheritdoc}
311   */
312  public function getMetadataFactory() {
313    throw new \LogicException('Legacy validator API is unsupported.');
314  }
315
316}
317