Passed
Pull Request — master (#422)
by
unknown
02:32
created

LimitTrait::initLimitProperties()   D

Complexity

Conditions 19
Paths 8

Size

Total Lines 49
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 19

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 24
c 1
b 0
f 0
nc 8
nop 8
dl 0
loc 49
cc 19
ccs 10
cts 10
cp 1
crap 19
rs 4.5166

How to fix   Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule\Trait;
6
7
use InvalidArgumentException;
8
use JetBrains\PhpStorm\ArrayShape;
9
10
/**
11
 * An implementation for {@see LimitInterface} intended to be included in rules. The following arguments need to be
12
 * added in constructor and passed with {@see initLimitProperties()} call:
13
 *
14
 * ```php
15
 * public function __construct(
16
 *     // ...
17
 *     float|int|null $min = null,
18
 *     float|int|null $max = null,
19
 *     float|int|null $exactly = null,
20
 *     string $lessThanMinMessage = 'Less than {min}.',
21
 *     string $greaterThanMinMessage = 'Greater than {max}.',
22
 *     string $greaterThanMinMessage = 'Not exactly {exactly}.',
23
 *     // ...
24
 * ) {
25
 *     // ...
26
 *     $this->initLimitProperties(
27
 *         $min,
28
 *         $max,
29
 *         $exactly,
30
 *         $lessThanMinMessage,
31
 *         $greaterThanMaxMessage,
32
 *         $notExactlyMessage,
33
 *     );
34
 *     // ...
35
 * }
36
 * ```
37
 *
38
 * Also, if a rule implements {@see RuleWithOptionsInterface}, you can merge limit related options instead of adding it
39
 * manually:
40
 *
41
 * ```php
42
 * public function getOptions(): array
43
 * {
44
 *     return array_merge($this->getLimitOptions(), [
45
 *         // Other rule options.
46
 *     ]);
47
 * }
48
 * ```
49
 *
50
 * Make sure to include {@see LimitHandlerTrait} in according handler as well.
51
 */
52
trait LimitTrait
53
{
54
    /**
55
     * @var float|int|null Minimum limit. Can't be combined with {@see $exactly}.
56
     *
57
     * @see $lessThanMinMessage for related error message.
58
     */
59 52
    private float|int|null $min = null;
60
    /**
61
     * @var float|int|null Maximum limit. Can't be combined with {@see $exactly}.
62
     *
63
     * @see $greaterThanMaxMessage for related error message.
64
     */
65
    private float|int|null $max = null;
66
    /**
67 52
     * @var float|int|null "Exactly" number. A shortcut / replacement for the case when {@see $min} and {@see $max} have the
68 52
     * same not-null value. Mutually exclusive with both {@see $min} and {@see $max}. `null` means no strict comparison
69 52
     * so lower / upper limits / both must be set.
70 52
     *
71 52
     * @see $notExactlyMessage for related error message.
72 52
     */
73
    private float|int|null $exactly = null;
74 52
    /**
75 2
     * @var string Validation error message used when a validated value is less than minimum set in {@see $min}.
76
     */
77
    private string $lessThanMinMessage;
78
    /**
79
     * @var string Validation error message used when a validated value is greater than maximum set in {@see $max}.
80 50
     */
81 6
    private string $greaterThanMaxMessage;
82
    /**
83
     * @var string Validation error message used when a validated value doesn't exactly match the one set in
84
     * {@see $exactly}.
85 44
     */
86 34
    private string $notExactlyMessage;
87 44
88
    /**
89 18
     * Initializes limit related properties and runs checks for required, mutually exclusive properties and their
90
     * allowed values (including dependency on each other).
91
     *
92 26
     * @param float|int|null $min Minimum limit ({@see $min}).
93 4
     * @param float|int|null $max Maximum limit ({@see $max}).
94 2
     * @param float|int|null $exactly "Exactly" number ({@see $exactly}).
95
     * @param string $lessThanMinMessage "Less than minimum" validation error message ({@see $lessThanMinMessage}).
96
     * @param string $greaterThanMinMessage "Greater than maximum" validation error message
97 2
     * ({@see $greaterThanMinMessage}).
98 2
     * @param string $notExactlyMessage "Not exactly" validation error message ({@see $notExactlyMessage}).
99
     * @param bool $requireLimits
100
     * @param bool $allowNegativeLimits
101
     */
102
    private function initLimitProperties(
103
        float|int|null $min,
104
        float|int|null $max,
105
        float|int|null $exactly,
106
        string $lessThanMinMessage,
107
        string $greaterThanMinMessage,
108 91
        string $notExactlyMessage,
109
        bool $requireLimits = true,
110 91
        bool $allowNegativeLimits = false,
111
    ): void {
112
        $this->min = $min;
113
        $this->max = $max;
114
        $this->exactly = $exactly;
115
        $this->lessThanMinMessage = $lessThanMinMessage;
116
        $this->greaterThanMaxMessage = $greaterThanMinMessage;
117
        $this->notExactlyMessage = $notExactlyMessage;
118 91
119
        if ($this->min === null && $this->max === null && $this->exactly === null) {
120 91
            if ($requireLimits === false) {
121
                return;
122
            }
123
124
            $message = 'At least one of these attributes must be specified: $min, $max, $exactly.';
125
126
            throw new InvalidArgumentException($message);
127
        }
128 99
129
        if (($this->min !== null || $this->max !== null) && $this->exactly !== null) {
130 99
            throw new InvalidArgumentException('$exactly is mutually exclusive with $min and $max.');
131
        }
132
133
        if (
134
            $allowNegativeLimits === false &&
135
            (
136
                ($this->min !== null && $this->min <= 0) ||
137
                ($this->max !== null && $this->max <= 0) ||
138 48
                ($this->exactly !== null && $this->exactly <= 0)
139
            )
140 48
        ) {
141
            throw new InvalidArgumentException('Only positive values are allowed.');
142
        }
143
144
        if ($this->min !== null && $this->max !== null) {
145
            if ($this->min > $this->max) {
146
                throw new InvalidArgumentException('$min must be lower than $max.');
147
            }
148 9
149
            if ($this->min === $this->max) {
150 9
                throw new InvalidArgumentException('Use $exactly instead.');
151
            }
152
        }
153
    }
154
155
    /**
156
     * A getter for {@see $min} property.
157
     *
158 8
     * @return float|int|null A number representing minimum boundary. `null` means no lower bound.
159
     */
160 8
    public function getMin(): float|int|null
161
    {
162
        return $this->min;
163
    }
164
165
    /**
166 6
     * A getter for {@see $max property}.
167
     *
168
     * @return float|int|null A number representing maximum boundary. `null` means no upper bound.
169
     */
170
    public function getMax(): float|int|null
171
    {
172
        return $this->max;
173
    }
174
175
    /**
176
     * A getter for {@see $exactly} property.
177 6
     *
178 6
     * @return float|int|null A number representing "exactly" value. `null` means no strict comparison so lower / upper limits /
179 6
     * both must be set.
180
     */
181 6
    public function getExactly(): float|int|null
182 6
    {
183
        return $this->exactly;
184
    }
185 6
186 6
    /**
187
     * A getter for {@see $lessThanMinMessage} property.
188
     *
189 6
     * @return string Validation error message.
190 6
     */
191
    public function getLessThanMinMessage(): string
192
    {
193
        return $this->lessThanMinMessage;
194
    }
195
196
    /**
197
     * A getter for {@see $greaterThanMaxMessage} property.
198
     *
199
     * @return string Validation error message.
200
     */
201
    public function getGreaterThanMaxMessage(): string
202
    {
203
        return $this->greaterThanMaxMessage;
204
    }
205
206
    /**
207
     * A getter for {@see $notExactlyMessage} property.
208
     *
209
     * @return string Validation error message.
210
     */
211
    public function getNotExactlyMessage(): string
212
    {
213
        return $this->notExactlyMessage;
214
    }
215
216
    /**
217
     * Limit related options intended to be merged with other rule options.
218
     *
219
     * @return array<string, mixed> A map between property name and property value.
220
     */
221
    #[ArrayShape([
222
        'min' => 'int|null',
223
        'max' => 'int|null',
224
        'exactly' => 'int|null',
225
        'lessThanMinMessage' => 'array',
226
        'greaterThanMaxMessage' => 'array',
227
        'notExactlyMessage' => 'array',
228
    ])]
229
    private function getLimitOptions(): array
230
    {
231
        return [
232
            'min' => $this->min,
233
            'max' => $this->max,
234
            'exactly' => $this->exactly,
235
            'lessThanMinMessage' => [
236
                'template' => $this->lessThanMinMessage,
237
                'parameters' => ['min' => $this->min],
238
            ],
239
            'greaterThanMaxMessage' => [
240
                'template' => $this->greaterThanMaxMessage,
241
                'parameters' => ['max' => $this->max],
242
            ],
243
            'notExactlyMessage' => [
244
                'template' => $this->notExactlyMessage,
245
                'parameters' => ['exactly' => $this->exactly],
246
            ],
247
        ];
248
    }
249
}
250