Passed
Pull Request — master (#422)
by Alexander
03:36 queued 01:01
created

LimitTrait::initLimitProperties()   D

Complexity

Conditions 19
Paths 8

Size

Total Lines 49
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 19

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 19
eloc 24
c 3
b 0
f 0
nc 8
nop 8
dl 0
loc 49
ccs 9
cts 9
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
 *     int|float|null $min = null,
18
 *     int|float|null $max = null,
19
 *     int|float|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 int|float|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 int|float|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 int|float|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
     */
100
    private function initLimitProperties(
101
        int|float|null $min,
102
        int|float|null $max,
103
        int|float|null $exactly,
104
        string $lessThanMinMessage,
105
        string $greaterThanMinMessage,
106
        string $notExactlyMessage,
107
        bool $requireLimits = true,
108 91
        bool $allowNegativeLimits = false,
109
    ): void {
110 91
        $this->min = $min;
111
        $this->max = $max;
112
        $this->exactly = $exactly;
113
        $this->lessThanMinMessage = $lessThanMinMessage;
114
        $this->greaterThanMaxMessage = $greaterThanMinMessage;
115
        $this->notExactlyMessage = $notExactlyMessage;
116
117
        if ($this->min === null && $this->max === null && $this->exactly === null) {
118 91
            if ($requireLimits === false) {
119
                return;
120 91
            }
121
122
            $message = 'At least one of these attributes must be specified: $min, $max, $exactly.';
123
124
            throw new InvalidArgumentException($message);
125
        }
126
127
        if (($this->min !== null || $this->max !== null) && $this->exactly !== null) {
128 99
            throw new InvalidArgumentException('$exactly is mutually exclusive with $min and $max.');
129
        }
130 99
131
        if (
132
            $allowNegativeLimits === false &&
133
            (
134
                ($this->min !== null && $this->min <= 0) ||
135
                ($this->max !== null && $this->max <= 0) ||
136
                ($this->exactly !== null && $this->exactly <= 0)
137
            )
138 48
        ) {
139
            throw new InvalidArgumentException('Only positive values are allowed.');
140 48
        }
141
142
        if ($this->min !== null && $this->max !== null) {
143
            if ($this->min > $this->max) {
144
                throw new InvalidArgumentException('$min must be lower than $max.');
145
            }
146
147
            if ($this->min === $this->max) {
148 9
                throw new InvalidArgumentException('Use $exactly instead.');
149
            }
150 9
        }
151
    }
152
153
    /**
154
     * A getter for {@see $min} property.
155
     *
156
     * @return float|int|null A number representing minimum boundary. `null` means no lower bound.
157
     */
158 8
    public function getMin(): int|float|null
159
    {
160 8
        return $this->min;
161
    }
162
163
    /**
164
     * A getter for {@see $max property}.
165
     *
166 6
     * @return float|int|null A number representing maximum boundary. `null` means no upper bound.
167
     */
168
    public function getMax(): int|float|null
169
    {
170
        return $this->max;
171
    }
172
173
    /**
174
     * A getter for {@see $exactly} property.
175
     *
176
     * @return float|int|null A number representing "exactly" value. `null` means no strict comparison so lower / upper limits /
177 6
     * both must be set.
178 6
     */
179 6
    public function getExactly(): int|float|null
180
    {
181 6
        return $this->exactly;
182 6
    }
183
184
    /**
185 6
     * A getter for {@see $lessThanMinMessage} property.
186 6
     *
187
     * @return string Validation error message.
188
     */
189 6
    public function getLessThanMinMessage(): string
190 6
    {
191
        return $this->lessThanMinMessage;
192
    }
193
194
    /**
195
     * A getter for {@see $greaterThanMaxMessage} property.
196
     *
197
     * @return string Validation error message.
198
     */
199
    public function getGreaterThanMaxMessage(): string
200
    {
201
        return $this->greaterThanMaxMessage;
202
    }
203
204
    /**
205
     * A getter for {@see $notExactlyMessage} property.
206
     *
207
     * @return string Validation error message.
208
     */
209
    public function getNotExactlyMessage(): string
210
    {
211
        return $this->notExactlyMessage;
212
    }
213
214
    /**
215
     * Limit related options intended to be merged with other rule options.
216
     *
217
     * @return array<string, mixed> A map between property name and property value.
218
     */
219
    #[ArrayShape([
220
        'min' => 'int|null',
221
        'max' => 'int|null',
222
        'exactly' => 'int|null',
223
        'lessThanMinMessage' => 'array',
224
        'greaterThanMaxMessage' => 'array',
225
        'notExactlyMessage' => 'array',
226
    ])]
227
    private function getLimitOptions(): array
228
    {
229
        return [
230
            'min' => $this->min,
231
            'max' => $this->max,
232
            'exactly' => $this->exactly,
233
            'lessThanMinMessage' => [
234
                'template' => $this->lessThanMinMessage,
235
                'parameters' => ['min' => $this->min],
236
            ],
237
            'greaterThanMaxMessage' => [
238
                'template' => $this->greaterThanMaxMessage,
239
                'parameters' => ['max' => $this->max],
240
            ],
241
            'notExactlyMessage' => [
242
                'template' => $this->notExactlyMessage,
243
                'parameters' => ['exactly' => $this->exactly],
244
            ],
245
        ];
246
    }
247
}
248