Passed
Push — master ( 89f940...819311 )
by Alexander
02:27
created

Compare::getHandlerClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Closure;
8
use InvalidArgumentException;
9
use JetBrains\PhpStorm\ArrayShape;
10
use RuntimeException;
11
use Yiisoft\Validator\BeforeValidationInterface;
12
use Yiisoft\Validator\SerializableRuleInterface;
13
use Yiisoft\Validator\Rule\Trait\BeforeValidationTrait;
14
use Yiisoft\Validator\Rule\Trait\RuleNameTrait;
15
use Yiisoft\Validator\ValidationContext;
16
17
abstract class Compare implements SerializableRuleInterface, BeforeValidationInterface
18
{
19
    use BeforeValidationTrait;
20
    use RuleNameTrait;
21
22
    /**
23
     * Constant for specifying the comparison as string values.
24
     * No conversion will be done before comparison.
25
     *
26
     * @see $type
27
     */
28
    public const TYPE_STRING = 'string';
29
    /**
30
     * Constant for specifying the comparison as numeric values.
31
     * String values will be converted into numbers before comparison.
32
     *
33
     * @see $type
34
     */
35
    public const TYPE_NUMBER = 'number';
36
37
    private array $validOperators = [
38
        '==' => 1,
39
        '===' => 1,
40
        '!=' => 1,
41
        '!==' => 1,
42
        '>' => 1,
43
        '>=' => 1,
44
        '<' => 1,
45
        '<=' => 1,
46
    ];
47
48 15
    public function __construct(
49
        /**
50
         * @var mixed The constant value to be compared with. When both this property
51
         * and {@see $targetAttribute} are set, this property takes precedence.
52
         */
53
        private $targetValue = null,
54
        /**
55
         * @var string|null The name of the attribute to be compared with. When both this property
56
         * and {@see $targetValue} are set, the {@see $targetValue} takes precedence.
57
         *
58
         * @see $targetValue
59
         */
60
        private ?string $targetAttribute = null,
61
        /**
62
         * @var string|null User-defined error message.
63
         */
64
        private ?string $message = null,
65
        /**
66
         * @var string The type of the values being compared.
67
         */
68
        private string $type = self::TYPE_STRING,
69
        /**
70
         * @var string The operator for comparison. The following operators are supported:
71
         *
72
         * - `==`: check if two values are equal. The comparison is done is non-strict mode.
73
         * - `===`: check if two values are equal. The comparison is done is strict mode.
74
         * - `!=`: check if two values are NOT equal. The comparison is done is non-strict mode.
75
         * - `!==`: check if two values are NOT equal. The comparison is done is strict mode.
76
         * - `>`: check if value being validated is greater than the value being compared with.
77
         * - `>=`: check if value being validated is greater than or equal to the value being compared with.
78
         * - `<`: check if value being validated is less than the value being compared with.
79
         * - `<=`: check if value being validated is less than or equal to the value being compared with.
80
         *
81
         * When you want to compare numbers, make sure to also change @see $type} to
82
         * {@see TYPE_NUMBER}.
83
         */
84
        private string $operator = '==',
85
        private bool $skipOnEmpty = false,
86
        private bool $skipOnError = false,
87
        /**
88
         * @var Closure(mixed, ValidationContext):bool|null
89
         */
90
        private ?Closure $when = null,
91
    ) {
92 15
        if (!isset($this->validOperators[$operator])) {
93
            throw new InvalidArgumentException("Operator \"$operator\" is not supported.");
94
        }
95
    }
96
97 65
    public function getTargetValue(): mixed
98
    {
99 65
        return $this->targetValue;
100
    }
101
102 65
    public function getTargetAttribute(): ?string
103
    {
104 65
        return $this->targetAttribute;
105
    }
106
107 65
    public function getType(): string
108
    {
109 65
        return $this->type;
110
    }
111
112 65
    public function getOperator(): string
113
    {
114 65
        return $this->operator;
115
    }
116
117 80
    public function getMessage(): string
118
    {
119 80
        return $this->message ?? match ($this->operator) {
120 17
            '==', '===' => 'Value must be equal to "{targetValueOrAttribute}".',
121 16
            '!=', '!==' => 'Value must not be equal to "{targetValueOrAttribute}".',
122 8
            '>' => 'Value must be greater than "{targetValueOrAttribute}".',
123 8
            '>=' => 'Value must be greater than or equal to "{targetValueOrAttribute}".',
124 8
            '<' => 'Value must be less than "{targetValueOrAttribute}".',
125 8
            '<=' => 'Value must be less than or equal to "{targetValueOrAttribute}".',
126 80
            default => throw new RuntimeException("Unknown operator: $this->operator."),
127
        };
128
    }
129
130 45
    #[ArrayShape([
131
        'targetValue' => 'mixed',
132
        'targetAttribute' => 'string|null',
133
        'message' => 'array',
134
        'type' => 'string',
135
        'operator' => 'string',
136
        'skipOnEmpty' => 'bool',
137
        'skipOnError' => 'bool',
138
    ])]
139
    public function getOptions(): array
140
    {
141
        return [
142 45
            'targetValue' => $this->targetValue,
143 45
            'targetAttribute' => $this->targetAttribute,
144
            'message' => [
145 45
                'message' => $this->getMessage(),
146
                'parameters' => [
147 45
                    'targetValue' => $this->targetValue,
148 45
                    'targetAttribute' => $this->targetAttribute,
149 45
                    'targetValueOrAttribute' => $this->targetValue ?? $this->targetAttribute,
150
                ],
151
            ],
152 45
            'type' => $this->type,
153 45
            'operator' => $this->operator,
154 45
            'skipOnEmpty' => $this->skipOnEmpty,
155 45
            'skipOnError' => $this->skipOnError,
156
        ];
157
    }
158
159 6
    public function getHandlerClassName(): string
160
    {
161 6
        return CompareHandler::class;
162
    }
163
}
164