Passed
Pull Request — master (#222)
by Alexander
04:33 queued 02:13
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
18
/**
19
 * Validates that the value contains certain number of items. Can be applied to arrays or classes implementing
20
 * {@see Countable} interface.
21
 */
22
#[Attribute(Attribute::TARGET_PROPERTY)]
23
final class Count implements ParametrizedRuleInterface, PreValidatableRuleInterface
24
{
25
    use HandlerClassNameTrait;
26
    use PreValidatableTrait;
27
    use RuleNameTrait;
28
29 7
    public function __construct(
30
        /**
31
         * @var int|null minimum number of items. null means no minimum number limit.
32
         *
33
         * @see $tooFewItemsMessage for the customized message for a value with too few items.
34
         */
35
        private ?int $min = null,
36
        /**
37
         * @var int|null maximum number of items. null means no maximum number limit.
38
         *
39
         * @see $tooManyItemsMessage for the customized message for a value wuth too many items.
40
         */
41
        private ?int $max = null,
42
        /**
43
         * @var int|null exact number of items. null means no strict comparison. Mutually exclusive with {@see $min} and
44
         * {@see $max}.
45
         */
46
        private ?int $exactly = null,
47
        /**
48
         * @var string user-defined error message used when the value is neither an array nor implementing
49
         * {@see \Countable} interface.
50
         *
51
         * @see Countable
52
         */
53
        private string $message = 'This value must be an array or implement \Countable interface.',
54
        /**
55
         * @var string user-defined error message used when the number of items is smaller than {@see $min}.
56
         */
57
        private string $tooFewItemsMessage = 'This value must contain at least {min, number} ' .
58
        '{min, plural, one{item} other{items}}.',
59
        /**
60
         * @var string user-defined error message used when the number of items is greater than {@see $max}.
61
         */
62
        private string $tooManyItemsMessage = 'This value must contain at most {max, number} ' .
63
        '{max, plural, one{item} other{items}}.',
64
        /**
65
         * @var string user-defined error message used when the number of items does not equal {@see $exactly}.
66
         */
67
        private string $notExactlyMessage = 'This value must contain exactly {max, number} ' .
68
        '{max, plural, one{item} other{items}}.',
69
        private bool $skipOnEmpty = false,
70
        private bool $skipOnError = false,
71
        private ?Closure $when = null,
72
    ) {
73 7
        if (!$this->min && !$this->max && !$this->exactly) {
74 1
            throw new InvalidArgumentException(
75
                'At least one of these attributes must be specified: $min, $max, $exactly.'
76
            );
77
        }
78
79 6
        if ($this->exactly && ($this->min || $this->max)) {
80 3
            throw new InvalidArgumentException('$exactly is mutually exclusive with $min and $max.');
81
        }
82
83 3
        if ($this->min && $this->max && $this->min === $this->max) {
84 1
            throw new InvalidArgumentException('Use $exactly instead.');
85
        }
86
    }
87
88
    /**
89
     * @return int|null
90
     */
91 18
    public function getMin(): ?int
92
    {
93 18
        return $this->min;
94
    }
95
96
    /**
97
     * @return int|null
98
     */
99 18
    public function getMax(): ?int
100
    {
101 18
        return $this->max;
102
    }
103
104
    /**
105
     * @return int|null
106
     */
107 19
    public function getExactly(): ?int
108
    {
109 19
        return $this->exactly;
110
    }
111
112
    /**
113
     * @return string
114
     */
115
    public function getMessage(): string
116
    {
117
        return $this->message;
118
    }
119
120
    /**
121
     * @return string
122
     */
123 9
    public function getTooFewItemsMessage(): string
124
    {
125 9
        return $this->tooFewItemsMessage;
126
    }
127
128
    /**
129
     * @return string
130
     */
131 2
    public function getTooManyItemsMessage(): string
132
    {
133 2
        return $this->tooManyItemsMessage;
134
    }
135
136
    /**
137
     * @return string
138
     */
139 1
    public function getNotExactlyMessage(): string
140
    {
141 1
        return $this->notExactlyMessage;
142
    }
143
144 1
    #[ArrayShape([
145
        'min' => 'int|null',
146
        'max' => 'int|null',
147
        'exactly' => 'int|null',
148
        'message' => 'string[]',
149
        'tooFewItemsMessage' => 'array',
150
        'tooManyItemsMessage' => 'array',
151
        'notExactlyMessage' => 'array',
152
        'skipOnEmpty' => 'bool',
153
        'skipOnError' => 'bool',
154
    ])]
155
    public function getOptions(): array
156
    {
157
        return [
158 1
            'min' => $this->min,
159 1
            'max' => $this->max,
160 1
            'exactly' => $this->exactly,
161
            'message' => [
162 1
                'message' => $this->message,
163
            ],
164
            'tooFewItemsMessage' => [
165 1
                'message' => $this->tooFewItemsMessage,
166 1
                'parameters' => ['min' => $this->min],
167
            ],
168
            'tooManyItemsMessage' => [
169 1
                'message' => $this->tooManyItemsMessage,
170 1
                'parameters' => ['max' => $this->max],
171
            ],
172
            'notExactlyMessage' => [
173 1
                'message' => $this->notExactlyMessage,
174 1
                'parameters' => ['exactly' => $this->exactly],
175
            ],
176 1
            'skipOnEmpty' => $this->skipOnEmpty,
177 1
            'skipOnError' => $this->skipOnError,
178
        ];
179
    }
180
}
181