Passed
Pull Request — master (#369)
by
unknown
03:01
created

Compare   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 11
eloc 55
c 2
b 0
f 0
dl 0
loc 168
ccs 43
cts 43
cp 1
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getHandlerClassName() 0 3 1
A getType() 0 3 1
A getOperator() 0 3 1
A getMessage() 0 9 1
A getIncorrectInputMessage() 0 3 1
A getTargetAttribute() 0 3 1
A __construct() 0 55 2
A getTargetValue() 0 3 1
A getIncorrectDataSetTypeMessage() 0 3 1
A getOptions() 0 27 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Closure;
8
use InvalidArgumentException;
9
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
10
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
11
use Yiisoft\Validator\Rule\Trait\WhenTrait;
12
use Yiisoft\Validator\SerializableRuleInterface;
13
use Yiisoft\Validator\SkipOnEmptyInterface;
14
use Yiisoft\Validator\SkipOnErrorInterface;
15
use Yiisoft\Validator\ValidationContext;
16
use Yiisoft\Validator\WhenInterface;
17
18
abstract class Compare implements SerializableRuleInterface, SkipOnEmptyInterface, SkipOnErrorInterface, WhenInterface
19
{
20
    use SkipOnEmptyTrait;
21
    use SkipOnErrorTrait;
22
    use WhenTrait;
23
24
    /**
25
     * Constant for specifying the comparison as string values.
26
     * Values will be converted to strings before comparison.
27
     *
28
     * @see $type
29
     */
30
    public const TYPE_STRING = 'string';
31
    /**
32
     * Constant for specifying the comparison as numeric values.
33
     * Values will be converted to float numbers before comparison.
34
     *
35
     * @see $type
36
     */
37
    public const TYPE_NUMBER = 'number';
38
39
    private array $validOperatorsMap = [
40
        '==' => 1,
41
        '===' => 1,
42
        '!=' => 1,
43
        '!==' => 1,
44
        '>' => 1,
45
        '>=' => 1,
46
        '<' => 1,
47
        '<=' => 1,
48
    ];
49
50 34
    public function __construct(
51
        /**
52
         * @var scalar|null The constant value to be compared with. When both this property and {@see $targetAttribute}
53
         * are set, this property takes precedence.
54
         */
55
        private int|float|string|bool|null $targetValue = null,
56
        /**
57
         * @var string|null The name of the attribute to be compared with. When both this property and
58
         * {@see $targetValue} are set, the {@see $targetValue} takes precedence.
59
         */
60
        private string|null $targetAttribute = null,
61
        private string $incorrectInputMessage = 'The allowed types are integer, float, string, boolean and null.',
62
        private string $incorrectDataSetTypeMessage = 'The attribute value returned from a custom data set must have ' .
63
        'a scalar type.',
64
        /**
65
         * @var string|null User-defined error message.
66
         */
67
        private string|null $message = null,
68
        /**
69
         * @var string The type of the values being compared.
70
         */
71
        private string $type = self::TYPE_STRING,
72
        /**
73
         * @var string The operator for comparison. The following operators are supported:
74
         *
75
         * - `==`: check if two values are equal. The comparison is done in non-strict mode.
76
         * - `===`: check if two values are equal. The comparison is done in strict mode.
77
         * - `!=`: check if two values are NOT equal. The comparison is done in non-strict mode.
78
         * - `!==`: check if two values are NOT equal. The comparison is done in strict mode.
79
         * - `>`: check if value being validated is greater than the value being compared with.
80
         * - `>=`: check if value being validated is greater than or equal to the value being compared with.
81
         * - `<`: check if value being validated is less than the value being compared with.
82
         * - `<=`: check if value being validated is less than or equal to the value being compared with.
83
         *
84
         * When you want to compare numbers, make sure to also change {@see $type} to {@see TYPE_NUMBER}.
85
         */
86
        private string $operator = '==',
87
        /**
88
         * @var bool|callable|null
89
         */
90
        private mixed $skipOnEmpty = null,
91
        private bool $skipOnError = false,
92
        /**
93
         * @var Closure(mixed, ValidationContext):bool|null
94
         */
95
        private ?Closure $when = null,
96
    ) {
97 34
        if (!isset($this->validOperatorsMap[$this->operator])) {
98 1
            $wrapInQuotesCallable = static fn (string $operator): string => '"' . $operator . '"';
99
            /** @var string[] $validOperators */
100 1
            $validOperators = array_keys($this->validOperatorsMap);
101 1
            $validOperatorsString = implode(', ', array_map($wrapInQuotesCallable, $validOperators));
102 1
            $message = "Operator \"$operator\" is not supported. The valid operators are: $validOperatorsString.";
103
104 1
            throw new InvalidArgumentException($message);
105
        }
106
    }
107
108
    /**
109
     * @return scalar|null
110
     */
111 75
    public function getTargetValue(): int|float|string|bool|null
112
    {
113 75
        return $this->targetValue;
114
    }
115
116 75
    public function getTargetAttribute(): string|null
117
    {
118 75
        return $this->targetAttribute;
119
    }
120
121 74
    public function getType(): string
122
    {
123 74
        return $this->type;
124
    }
125
126 74
    public function getOperator(): string
127
    {
128 74
        return $this->operator;
129
    }
130
131 1
    public function getIncorrectInputMessage(): string
132
    {
133 1
        return $this->incorrectInputMessage;
134
    }
135
136 1
    public function getIncorrectDataSetTypeMessage(): string
137
    {
138 1
        return $this->incorrectDataSetTypeMessage;
139
    }
140
141 80
    public function getMessage(): string
142
    {
143 80
        return $this->message ?? match ($this->operator) {
144 22
            '==', '===' => 'Value must be equal to "{targetValueOrAttribute}".',
145 15
            '!=', '!==' => 'Value must not be equal to "{targetValueOrAttribute}".',
146 7
            '>' => 'Value must be greater than "{targetValueOrAttribute}".',
147 7
            '>=' => 'Value must be greater than or equal to "{targetValueOrAttribute}".',
148 7
            '<' => 'Value must be less than "{targetValueOrAttribute}".',
149 80
            '<=' => 'Value must be less than or equal to "{targetValueOrAttribute}".',
150
        };
151
    }
152
153 40
    public function getOptions(): array
154
    {
155 40
        $messageParameters = [
156 40
            'targetValue' => $this->targetValue,
157 40
            'targetAttribute' => $this->targetAttribute,
158 40
            'targetValueOrAttribute' => $this->targetValue ?? $this->targetAttribute,
159
        ];
160
161
        return [
162 40
            'targetValue' => $this->targetValue,
163 40
            'targetAttribute' => $this->targetAttribute,
164
            'incorrectInputMessage' => [
165 40
                'message' => $this->incorrectInputMessage,
166
                'parameters' => $messageParameters,
167
            ],
168
            'incorrectDataSetTypeMessage' => [
169 40
                'message' => $this->incorrectDataSetTypeMessage,
170
                'parameters' => $messageParameters,
171
            ],
172
            'message' => [
173 40
                'message' => $this->getMessage(),
174
                'parameters' => $messageParameters,
175
            ],
176 40
            'type' => $this->type,
177 40
            'operator' => $this->operator,
178 40
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
179 40
            'skipOnError' => $this->skipOnError,
180
        ];
181
    }
182
183 76
    public function getHandlerClassName(): string
184
    {
185 76
        return CompareHandler::class;
186
    }
187
}
188