Not.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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\ComponentException;
  9. use Respect\Validation\Exceptions\ValidationException;
  10. use Respect\Validation\NonNegatable;
  11. use Respect\Validation\Validatable;
  12. use function array_shift;
  13. use function count;
  14. use function current;
  15. use function get_class;
  16. use function sprintf;
  17. /**
  18. * @author Alexandre Gomes Gaigalas <alganet@gmail.com>
  19. * @author Caio César Tavares <caiotava@gmail.com>
  20. * @author Henrique Moody <henriquemoody@gmail.com>
  21. */
  22. final class Not extends AbstractRule
  23. {
  24. /**
  25. * @var Validatable
  26. */
  27. private $rule;
  28. public function __construct(Validatable $rule)
  29. {
  30. $this->rule = $this->extractNegatedRule($rule);
  31. }
  32. public function getNegatedRule(): Validatable
  33. {
  34. return $this->rule;
  35. }
  36. public function setName(string $name): Validatable
  37. {
  38. $this->rule->setName($name);
  39. return parent::setName($name);
  40. }
  41. /**
  42. * {@inheritDoc}
  43. */
  44. public function validate($input): bool
  45. {
  46. return $this->rule->validate($input) === false;
  47. }
  48. /**
  49. * {@inheritDoc}
  50. */
  51. public function assert($input): void
  52. {
  53. if ($this->validate($input)) {
  54. return;
  55. }
  56. $rule = $this->rule;
  57. if ($rule instanceof AllOf) {
  58. $rule = $this->absorbAllOf($rule, $input);
  59. }
  60. $exception = $rule->reportError($input);
  61. $exception->updateMode(ValidationException::MODE_NEGATIVE);
  62. throw $exception;
  63. }
  64. /**
  65. * @param mixed $input
  66. */
  67. private function absorbAllOf(AllOf $rule, $input): Validatable
  68. {
  69. $rules = $rule->getRules();
  70. while (($current = array_shift($rules))) {
  71. $rule = $current;
  72. if (!$rule instanceof AllOf) {
  73. continue;
  74. }
  75. if (!$rule->validate($input)) {
  76. continue;
  77. }
  78. $rules = $rule->getRules();
  79. }
  80. return $rule;
  81. }
  82. private function extractNegatedRule(Validatable $rule): Validatable
  83. {
  84. if ($rule instanceof NonNegatable) {
  85. throw new ComponentException(
  86. sprintf(
  87. '"%s" can not be wrapped in Not()',
  88. get_class($rule)
  89. )
  90. );
  91. }
  92. if ($rule instanceof self && $rule->getNegatedRule() instanceof self) {
  93. return $this->extractNegatedRule($rule->getNegatedRule()->getNegatedRule());
  94. }
  95. if (!$rule instanceof AllOf) {
  96. return $rule;
  97. }
  98. $rules = $rule->getRules();
  99. if (count($rules) === 1) {
  100. return $this->extractNegatedRule(current($rules));
  101. }
  102. return $rule;
  103. }
  104. }