Passed
Pull Request — master (#246)
by Rustam
02:22
created

CompareTo::getCompareAttribute()   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
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
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 Attribute;
8
use Closure;
9
use InvalidArgumentException;
10
use JetBrains\PhpStorm\ArrayShape;
11
use RuntimeException;
12
use Yiisoft\Validator\ParametrizedRuleInterface;
13
use Yiisoft\Validator\BeforeValidationInterface;
14
use Yiisoft\Validator\Rule\Trait\HandlerClassNameTrait;
15
use Yiisoft\Validator\Rule\Trait\BeforeValidationTrait;
16
use Yiisoft\Validator\Rule\Trait\RuleNameTrait;
17
use Yiisoft\Validator\ValidationContext;
18
19
/**
20
 * Compares the specified value with another value.
21
 *
22
 * The value being compared with a constant {@see CompareTo::$compareValue}, which is set
23
 * in the constructor.
24
 *
25
 * It supports different comparison operators, specified
26
 * via the {@see CompareTo::$operator}.
27
 *
28
 * The default comparison function is based on string values, which means the values
29
 * are compared byte by byte. When comparing numbers, make sure to change {@see CompareTo::$type} to
30
 * {@see CompareTo::TYPE_NUMBER} to enable numeric comparison.
31
 */
32
#[Attribute(Attribute::TARGET_PROPERTY)]
33
final class CompareTo implements ParametrizedRuleInterface, BeforeValidationInterface
34
{
35
    use BeforeValidationTrait;
36
    use HandlerClassNameTrait;
37
    use RuleNameTrait;
38
39
    /**
40
     * Constant for specifying the comparison as string values.
41
     * No conversion will be done before comparison.
42
     *
43
     * @see CompareTo::$type
44
     */
45
    public const TYPE_STRING = 'string';
46
    /**
47
     * Constant for specifying the comparison as numeric values.
48
     * String values will be converted into numbers before comparison.
49
     *
50
     * @see CompareTo::$type
51
     */
52
    public const TYPE_NUMBER = 'number';
53
54
    private array $validOperators = [
55
        '==' => 1,
56
        '===' => 1,
57
        '!=' => 1,
58
        '!==' => 1,
59
        '>' => 1,
60
        '>=' => 1,
61
        '<' => 1,
62
        '<=' => 1,
63
    ];
64
65 2
    public function __construct(
66
        /**
67
         * @var mixed the constant value to be compared with. When both this property
68
         * and {@see $compareAttribute} are set, this property takes precedence.
69
         */
70
        private $compareValue = null,
71
        /**
72
         * @var string|null the name of the attribute to be compared with. When both this property
73
         * and {@see $compareValue} are set, the previous one takes precedence.
74
         *
75
         * @see $compareValue
76
         */
77
        private ?string $compareAttribute = null,
78
        /**
79
         * @var string|null user-defined error message
80
         */
81
        private ?string $message = null,
82
        /**
83
         * @var string the type of the values being compared.
84
         */
85
        private string $type = self::TYPE_STRING,
86
        /**
87
         * @var string the operator for comparison. The following operators are supported:
88
         *
89
         * - `==`: check if two values are equal. The comparison is done is non-strict mode.
90
         * - `===`: check if two values are equal. The comparison is done is strict mode.
91
         * - `!=`: check if two values are NOT equal. The comparison is done is non-strict mode.
92
         * - `!==`: check if two values are NOT equal. The comparison is done is strict mode.
93
         * - `>`: check if value being validated is greater than the value being compared with.
94
         * - `>=`: check if value being validated is greater than or equal to the value being compared with.
95
         * - `<`: check if value being validated is less than the value being compared with.
96
         * - `<=`: check if value being validated is less than or equal to the value being compared with.
97
         *
98
         * When you want to compare numbers, make sure to also change @see CompareTo::$type} to
99
         * {@see CompareTo::TYPE_NUMBER}.
100
         */
101
        private string $operator = '==',
102
        private bool $skipOnEmpty = false,
103
        private bool $skipOnError = false,
104
        /**
105
         * @var Closure(mixed, ValidationContext):bool|null
106
         */
107
        private ?Closure $when = null,
108
    ) {
109 2
        if (!isset($this->validOperators[$operator])) {
110
            throw new InvalidArgumentException("Operator \"$operator\" is not supported.");
111
        }
112
    }
113
114
    /**
115
     * @return mixed
116
     */
117 34
    public function getCompareValue(): mixed
118
    {
119 34
        return $this->compareValue;
120
    }
121
122
    /**
123
     * @return string|null
124
     */
125 34
    public function getCompareAttribute(): ?string
126
    {
127 34
        return $this->compareAttribute;
128
    }
129
130
    /**
131
     * @return string
132
     */
133 34
    public function getType(): string
134
    {
135 34
        return $this->type;
136
    }
137
138
    /**
139
     * @return string
140
     */
141 34
    public function getOperator(): string
142
    {
143 34
        return $this->operator;
144
    }
145
146 26
    public function getMessage(): string
147
    {
148 26
        return $this->message ?? match ($this->operator) {
149 8
            '==', '===' => 'Value must be equal to "{compareValueOrAttribute}".',
150 7
            '!=', '!==' => 'Value must not be equal to "{compareValueOrAttribute}".',
151 2
            '>' => 'Value must be greater than "{compareValueOrAttribute}".',
152 2
            '>=' => 'Value must be greater than or equal to "{compareValueOrAttribute}".',
153 2
            '<' => 'Value must be less than "{compareValueOrAttribute}".',
154 2
            '<=' => 'Value must be less than or equal to "{compareValueOrAttribute}".',
155 26
            default => throw new RuntimeException("Unknown operator: {$this->operator}"),
156
        };
157
    }
158
159 9
    #[ArrayShape([
160
        'compareValue' => 'mixed',
161
        'compareAttribute' => '',
162
        'message' => 'array',
163
        'type' => 'string',
164
        'operator' => 'string',
165
        'skipOnEmpty' => 'bool',
166
        'skipOnError' => 'bool',
167
    ])]
168
    public function getOptions(): array
169
    {
170
        return [
171 9
            'compareValue' => $this->compareValue,
172 9
            'compareAttribute' => $this->compareAttribute,
173
            'message' => [
174 9
                'message' => $this->getMessage(),
175
                'parameters' => [
176 9
                    'compareValue' => $this->compareValue,
177 9
                    'compareAttribute' => $this->compareAttribute,
178 9
                    'compareValueOrAttribute' => $this->compareValue ?? $this->compareAttribute,
179
                ],
180
            ],
181 9
            'type' => $this->type,
182 9
            'operator' => $this->operator,
183 9
            'skipOnEmpty' => $this->skipOnEmpty,
184 9
            'skipOnError' => $this->skipOnError,
185
        ];
186
    }
187
}
188