Passed
Pull Request — master (#240)
by Dmitriy
03:45
created

Count::__construct()   B

Complexity

Conditions 10
Paths 4

Size

Total Lines 59
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 59
ccs 7
cts 7
cp 1
rs 7.6666
cc 10
nc 4
nop 10
crap 10

How to fix   Long Method    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;
6
7
use Attribute;
8
use Closure;
9
use Countable;
10
use InvalidArgumentException;
11
use JetBrains\PhpStorm\ArrayShape;
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
 * Validates that the value contains certain number of items. Can be applied to arrays or classes implementing
21
 * {@see Countable} interface.
22
 */
23
#[Attribute(Attribute::TARGET_PROPERTY)]
24
final class Count implements ParametrizedRuleInterface, BeforeValidationInterface
25
{
26
    use BeforeValidationTrait;
27
    use HandlerClassNameTrait;
28
    use RuleNameTrait;
29
30 7
    public function __construct(
31
        /**
32
         * @var int|null minimum number of items. null means no minimum number limit.
33
         *
34
         * @see $tooFewItemsMessage for the customized message for a value with too few items.
35
         */
36
        private ?int $min = null,
37
        /**
38
         * @var int|null maximum number of items. null means no maximum number limit.
39
         *
40
         * @see $tooManyItemsMessage for the customized message for a value wuth too many items.
41
         */
42
        private ?int $max = null,
43
        /**
44
         * @var int|null exact number of items. null means no strict comparison. Mutually exclusive with {@see $min} and
45
         * {@see $max}.
46
         */
47
        private ?int $exactly = null,
48
        /**
49
         * @var string user-defined error message used when the value is neither an array nor implementing
50
         * {@see \Countable} interface.
51
         *
52
         * @see Countable
53
         */
54
        private string $message = 'This value must be an array or implement \Countable interface.',
55
        /**
56
         * @var string user-defined error message used when the number of items is smaller than {@see $min}.
57
         */
58
        private string $tooFewItemsMessage = 'This value must contain at least {min, number} ' .
59
        '{min, plural, one{item} other{items}}.',
60
        /**
61
         * @var string user-defined error message used when the number of items is greater than {@see $max}.
62
         */
63
        private string $tooManyItemsMessage = 'This value must contain at most {max, number} ' .
64
        '{max, plural, one{item} other{items}}.',
65
        /**
66
         * @var string user-defined error message used when the number of items does not equal {@see $exactly}.
67
         */
68
        private string $notExactlyMessage = 'This value must contain exactly {max, number} ' .
69
        '{max, plural, one{item} other{items}}.',
70
        private bool $skipOnEmpty = false,
71
        private bool $skipOnError = false,
72
        /**
73
         * @var Closure(mixed, ValidationContext):bool|null
74
         */
75
        private ?Closure $when = null,
76
    ) {
77 7
        if (!$this->min && !$this->max && !$this->exactly) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->min of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $this->max of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $this->exactly of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
78 1
            throw new InvalidArgumentException(
79
                'At least one of these attributes must be specified: $min, $max, $exactly.'
80
            );
81
        }
82
83 6
        if ($this->exactly && ($this->min || $this->max)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->max of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $this->min of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $this->exactly of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
84 3
            throw new InvalidArgumentException('$exactly is mutually exclusive with $min and $max.');
85
        }
86
87 3
        if ($this->min && $this->max && $this->min === $this->max) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->max of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $this->min of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
88 1
            throw new InvalidArgumentException('Use $exactly instead.');
89
        }
90
    }
91
92
    /**
93
     * @return int|null
94
     */
95 18
    public function getMin(): ?int
96
    {
97 18
        return $this->min;
98
    }
99
100
    /**
101
     * @return int|null
102
     */
103 18
    public function getMax(): ?int
104
    {
105 18
        return $this->max;
106
    }
107
108
    /**
109
     * @return int|null
110
     */
111 19
    public function getExactly(): ?int
112
    {
113 19
        return $this->exactly;
114
    }
115
116
    /**
117
     * @return string
118
     */
119
    public function getMessage(): string
120
    {
121
        return $this->message;
122
    }
123
124
    /**
125
     * @return string
126
     */
127 9
    public function getTooFewItemsMessage(): string
128
    {
129 9
        return $this->tooFewItemsMessage;
130
    }
131
132
    /**
133
     * @return string
134
     */
135 2
    public function getTooManyItemsMessage(): string
136
    {
137 2
        return $this->tooManyItemsMessage;
138
    }
139
140
    /**
141
     * @return string
142
     */
143 1
    public function getNotExactlyMessage(): string
144
    {
145 1
        return $this->notExactlyMessage;
146
    }
147
148 1
    #[ArrayShape([
149
        'min' => 'int|null',
150
        'max' => 'int|null',
151
        'exactly' => 'int|null',
152
        'message' => 'string[]',
153
        'tooFewItemsMessage' => 'array',
154
        'tooManyItemsMessage' => 'array',
155
        'notExactlyMessage' => 'array',
156
        'skipOnEmpty' => 'bool',
157
        'skipOnError' => 'bool',
158
    ])]
159
    public function getOptions(): array
160
    {
161
        return [
162 1
            'min' => $this->min,
163 1
            'max' => $this->max,
164 1
            'exactly' => $this->exactly,
165
            'message' => [
166 1
                'message' => $this->message,
167
            ],
168
            'tooFewItemsMessage' => [
169 1
                'message' => $this->tooFewItemsMessage,
170 1
                'parameters' => ['min' => $this->min],
171
            ],
172
            'tooManyItemsMessage' => [
173 1
                'message' => $this->tooManyItemsMessage,
174 1
                'parameters' => ['max' => $this->max],
175
            ],
176
            'notExactlyMessage' => [
177 1
                'message' => $this->notExactlyMessage,
178 1
                'parameters' => ['exactly' => $this->exactly],
179
            ],
180 1
            'skipOnEmpty' => $this->skipOnEmpty,
181 1
            'skipOnError' => $this->skipOnError,
182
        ];
183
    }
184
}
185