AbstractComposite.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <?php
  2. /*
  3. * Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. declare(strict_types=1);
  7. namespace Respect\Validation\Rules;
  8. use Respect\Validation\Exceptions\NestedValidationException;
  9. use Respect\Validation\Exceptions\ValidationException;
  10. use Respect\Validation\Validatable;
  11. use function array_filter;
  12. use function array_map;
  13. /**
  14. * Abstract class for rules that are composed by other rules.
  15. *
  16. * @author Alexandre Gomes Gaigalas <alganet@gmail.com>
  17. * @author Henrique Moody <henriquemoody@gmail.com>
  18. * @author Wojciech Frącz <fraczwojciech@gmail.com>
  19. */
  20. abstract class AbstractComposite extends AbstractRule
  21. {
  22. /**
  23. * @var Validatable[]
  24. */
  25. private $rules = [];
  26. /**
  27. * Initializes the rule adding other rules to the stack.
  28. */
  29. public function __construct(Validatable ...$rules)
  30. {
  31. $this->rules = $rules;
  32. }
  33. /**
  34. * {@inheritDoc}
  35. */
  36. public function setName(string $name): Validatable
  37. {
  38. $parentName = $this->getName();
  39. foreach ($this->rules as $rule) {
  40. $ruleName = $rule->getName();
  41. if ($ruleName && $parentName !== $ruleName) {
  42. continue;
  43. }
  44. $rule->setName($name);
  45. }
  46. return parent::setName($name);
  47. }
  48. public function setDefault(string $default, bool $defaultType=false): Validatable
  49. {
  50. $parentDefault = $this->getDefault();
  51. foreach ($this->rules as $rule) {
  52. $ruleDefault = $rule->getDefault();
  53. if ($ruleDefault && $parentDefault !== $ruleDefault) {
  54. continue;
  55. }
  56. $rule->setDefault($default, $defaultType);
  57. }
  58. return parent::setDefault($default, $defaultType);
  59. }
  60. /**
  61. * Append a rule into the stack of rules.
  62. *
  63. * @return AbstractComposite
  64. */
  65. public function addRule(Validatable $rule): self
  66. {
  67. if ($this->shouldHaveNameOverwritten($rule) && $this->getName() !== null) {
  68. $rule->setName($this->getName());
  69. }
  70. $this->rules[] = $rule;
  71. return $this;
  72. }
  73. /**
  74. * Returns all the rules in the stack.
  75. *
  76. * @return Validatable[]
  77. */
  78. public function getRules(): array
  79. {
  80. return $this->rules;
  81. }
  82. /**
  83. * Returns all the exceptions throw when asserting all rules.
  84. *
  85. * @param mixed $input
  86. *
  87. * @return ValidationException[]
  88. */
  89. protected function getAllThrownExceptions($input): array
  90. {
  91. return array_filter(
  92. array_map(
  93. function (Validatable $rule) use ($input): ?ValidationException {
  94. try {
  95. $rule->assert($input);
  96. } catch (ValidationException $exception) {
  97. $this->updateExceptionTemplate($exception);
  98. return $exception;
  99. }
  100. return null;
  101. },
  102. $this->getRules()
  103. )
  104. );
  105. }
  106. private function shouldHaveNameOverwritten(Validatable $rule): bool
  107. {
  108. return $this->hasName($this) && !$this->hasName($rule);
  109. }
  110. private function hasName(Validatable $rule): bool
  111. {
  112. return $rule->getName() !== null;
  113. }
  114. private function updateExceptionTemplate(ValidationException $exception): void
  115. {
  116. if ($this->template === null || $exception->hasCustomTemplate()) {
  117. return;
  118. }
  119. $exception->updateTemplate($this->template);
  120. if (!$exception instanceof NestedValidationException) {
  121. return;
  122. }
  123. foreach ($exception->getChildren() as $childException) {
  124. $this->updateExceptionTemplate($childException);
  125. }
  126. }
  127. }