ExecutionContext.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Validator;
  11. use Symfony\Component\Translation\TranslatorInterface;
  12. /**
  13. * Default implementation of {@link ExecutionContextInterface}.
  14. *
  15. * This class is immutable by design.
  16. *
  17. * @author Fabien Potencier <fabien@symfony.com>
  18. * @author Bernhard Schussek <bschussek@gmail.com>
  19. */
  20. class ExecutionContext implements ExecutionContextInterface
  21. {
  22. /**
  23. * @var GlobalExecutionContextInterface
  24. */
  25. private $globalContext;
  26. /**
  27. * @var TranslatorInterface
  28. */
  29. private $translator;
  30. /**
  31. * @var null|string
  32. */
  33. private $translationDomain;
  34. /**
  35. * @var MetadataInterface
  36. */
  37. private $metadata;
  38. /**
  39. * @var mixed
  40. */
  41. private $value;
  42. /**
  43. * @var string
  44. */
  45. private $group;
  46. /**
  47. * @var string
  48. */
  49. private $propertyPath;
  50. /**
  51. * Creates a new execution context.
  52. *
  53. * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state.
  54. * @param TranslatorInterface $translator The translator for translating violation messages.
  55. * @param null|string $translationDomain The domain of the validation messages.
  56. * @param MetadataInterface $metadata The metadata of the validated node.
  57. * @param mixed $value The value of the validated node.
  58. * @param string $group The current validation group.
  59. * @param string $propertyPath The property path to the current node.
  60. */
  61. public function __construct(GlobalExecutionContextInterface $globalContext, TranslatorInterface $translator, $translationDomain = null, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '')
  62. {
  63. if (null === $group) {
  64. $group = Constraint::DEFAULT_GROUP;
  65. }
  66. $this->globalContext = $globalContext;
  67. $this->translator = $translator;
  68. $this->translationDomain = $translationDomain;
  69. $this->metadata = $metadata;
  70. $this->value = $value;
  71. $this->propertyPath = $propertyPath;
  72. $this->group = $group;
  73. }
  74. /**
  75. * {@inheritdoc}
  76. */
  77. public function addViolation($message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null)
  78. {
  79. if (null === $pluralization) {
  80. $translatedMessage = $this->translator->trans($message, $params, $this->translationDomain);
  81. } else {
  82. try {
  83. $translatedMessage = $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain);
  84. } catch (\InvalidArgumentException $e) {
  85. $translatedMessage = $this->translator->trans($message, $params, $this->translationDomain);
  86. }
  87. }
  88. $this->globalContext->getViolations()->add(new ConstraintViolation(
  89. $translatedMessage,
  90. $message,
  91. $params,
  92. $this->globalContext->getRoot(),
  93. $this->propertyPath,
  94. // check using func_num_args() to allow passing null values
  95. func_num_args() >= 3 ? $invalidValue : $this->value,
  96. $pluralization,
  97. $code
  98. ));
  99. }
  100. /**
  101. * {@inheritdoc}
  102. */
  103. public function addViolationAt($subPath, $message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null)
  104. {
  105. $this->globalContext->getViolations()->add(new ConstraintViolation(
  106. null === $pluralization
  107. ? $this->translator->trans($message, $params, $this->translationDomain)
  108. : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain),
  109. $message,
  110. $params,
  111. $this->globalContext->getRoot(),
  112. $this->getPropertyPath($subPath),
  113. // check using func_num_args() to allow passing null values
  114. func_num_args() >= 4 ? $invalidValue : $this->value,
  115. $pluralization,
  116. $code
  117. ));
  118. }
  119. /**
  120. * {@inheritdoc}
  121. */
  122. public function getViolations()
  123. {
  124. return $this->globalContext->getViolations();
  125. }
  126. /**
  127. * {@inheritdoc}
  128. */
  129. public function getRoot()
  130. {
  131. return $this->globalContext->getRoot();
  132. }
  133. /**
  134. * {@inheritdoc}
  135. */
  136. public function getPropertyPath($subPath = '')
  137. {
  138. if ('' != $subPath && '' !== $this->propertyPath && '[' !== $subPath[0]) {
  139. return $this->propertyPath.'.'.$subPath;
  140. }
  141. return $this->propertyPath.$subPath;
  142. }
  143. /**
  144. * {@inheritdoc}
  145. */
  146. public function getClassName()
  147. {
  148. if ($this->metadata instanceof ClassBasedInterface) {
  149. return $this->metadata->getClassName();
  150. }
  151. return null;
  152. }
  153. /**
  154. * {@inheritdoc}
  155. */
  156. public function getPropertyName()
  157. {
  158. if ($this->metadata instanceof PropertyMetadataInterface) {
  159. return $this->metadata->getPropertyName();
  160. }
  161. return null;
  162. }
  163. /**
  164. * {@inheritdoc}
  165. */
  166. public function getValue()
  167. {
  168. return $this->value;
  169. }
  170. /**
  171. * {@inheritdoc}
  172. */
  173. public function getGroup()
  174. {
  175. return $this->group;
  176. }
  177. /**
  178. * {@inheritdoc}
  179. */
  180. public function getMetadata()
  181. {
  182. return $this->metadata;
  183. }
  184. /**
  185. * {@inheritdoc}
  186. */
  187. public function getMetadataFor($value)
  188. {
  189. return $this->globalContext->getMetadataFactory()->getMetadataFor($value);
  190. }
  191. /**
  192. * {@inheritdoc}
  193. */
  194. public function validate($value, $subPath = '', $groups = null, $traverse = false, $deep = false)
  195. {
  196. $propertyPath = $this->getPropertyPath($subPath);
  197. foreach ($this->resolveGroups($groups) as $group) {
  198. $this->globalContext->getVisitor()->validate($value, $group, $propertyPath, $traverse, $deep);
  199. }
  200. }
  201. /**
  202. * {@inheritdoc}
  203. */
  204. public function validateValue($value, $constraints, $subPath = '', $groups = null)
  205. {
  206. $constraints = is_array($constraints) ? $constraints : array($constraints);
  207. if (null === $groups && '' === $subPath) {
  208. $context = clone $this;
  209. $context->value = $value;
  210. $context->executeConstraintValidators($value, $constraints);
  211. return;
  212. }
  213. $propertyPath = $this->getPropertyPath($subPath);
  214. foreach ($this->resolveGroups($groups) as $group) {
  215. $context = clone $this;
  216. $context->value = $value;
  217. $context->group = $group;
  218. $context->propertyPath = $propertyPath;
  219. $context->executeConstraintValidators($value, $constraints);
  220. }
  221. }
  222. /**
  223. * {@inheritdoc}
  224. */
  225. public function getMetadataFactory()
  226. {
  227. return $this->globalContext->getMetadataFactory();
  228. }
  229. /**
  230. * Executes the validators of the given constraints for the given value.
  231. *
  232. * @param mixed $value The value to validate.
  233. * @param Constraint[] $constraints The constraints to match against.
  234. */
  235. private function executeConstraintValidators($value, array $constraints)
  236. {
  237. foreach ($constraints as $constraint) {
  238. $validator = $this->globalContext->getValidatorFactory()->getInstance($constraint);
  239. $validator->initialize($this);
  240. $validator->validate($value, $constraint);
  241. }
  242. }
  243. /**
  244. * Returns an array of group names.
  245. *
  246. * @param null|string|string[] $groups The groups to resolve. If a single string is
  247. * passed, it is converted to an array. If null
  248. * is passed, an array containing the current
  249. * group of the context is returned.
  250. *
  251. * @return array An array of validation groups.
  252. */
  253. private function resolveGroups($groups)
  254. {
  255. return $groups ? (array) $groups : (array) $this->group;
  256. }
  257. }