Passed
Pull Request — master (#222)
by Rustam
02:28
created

Count   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 19
eloc 32
c 1
b 0
f 0
dl 0
loc 107
ccs 34
cts 34
cp 1
rs 10
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\PreValidatableRuleInterface;
14
use Yiisoft\Validator\Rule\Trait\HandlerClassNameTrait;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_TRAIT, expecting T_STRING or '{' on line 14 at column 27
Loading history...
15
use Yiisoft\Validator\Rule\Trait\PreValidatableTrait;
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, PreValidatableRuleInterface
25
{
26
    use HandlerClassNameTrait;
27
    use PreValidatableTrait;
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) {
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)) {
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) {
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