Passed
Push — master ( 1aecc0...74f07c )
by Smoren
02:22
created

ContainerRule::getIterableCheck()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\Validator\Rules;
6
7
use ArrayAccess;
8
use Smoren\Validator\Exceptions\ValidationError;
9
use Smoren\Validator\Helpers\ContainerAccessHelper;
10
use Smoren\Validator\Interfaces\BaseRuleInterface;
11
use Smoren\Validator\Interfaces\CheckInterface;
12
use Smoren\Validator\Interfaces\ContainerRuleInterface;
13
use Smoren\Validator\Interfaces\IntegerRuleInterface;
14
use Smoren\Validator\Structs\Check;
15
16
class ContainerRule extends Rule implements ContainerRuleInterface
17
{
18
    public const ERROR_NOT_CONTAINER = 'not_container';
19
    public const ERROR_NOT_ARRAY = 'not_array';
20
    public const ERROR_NOT_INDEXED_ARRAY = 'not_array';
21
    public const ERROR_NOT_ASSOCIATIVE_ARRAY = 'not_array';
22
    public const ERROR_NOT_ITERABLE = 'not_iterable';
23
    public const ERROR_NOT_COUNTABLE = 'not_countable';
24
    public const ERROR_NOT_EMPTY = 'not_empty';
25
    public const ERROR_EMPTY = 'not_empty';
26
    public const ERROR_NOT_ARRAY_ACCESSIBLE = 'not_array_accessible';
27
    public const ERROR_NOT_OBJECT = 'not_object';
28
    public const ERROR_NOT_STD_OBJECT = 'not_std_object';
29
    public const ERROR_NOT_INSTANCE_OF = 'not_instance_of';
30
    public const ERROR_BAD_LENGTH = 'bad_length';
31
    public const ERROR_ATTRIBUTE_NOT_EXIST = 'attribute_not_exist';
32
    public const ERROR_BAD_ATTRIBUTE = 'bad_attribute';
33
    public const ERROR_SOME_KEYS_BAD = 'some_keys_bad';
34
    public const ERROR_SOME_VALUES_BAD = 'some_values_bad';
35
36
    /**
37
     * ContainerRule constructor.
38
     */
39 18
    public function __construct()
40
    {
41 18
        $this->addCheck(new Check(
42 18
            self::ERROR_NOT_CONTAINER,
43 18
            fn ($value) => \is_array($value) || \is_object($value),
44 18
            []
45 18
        ), true);
46
    }
47
48
    /**
49
     * {@inheritDoc}
50
     *
51
     * @return static
52
     */
53
    public function array(): self
54
    {
55
        return $this->addCheck($this->getArrayCheck());
56
    }
57
58
    /**
59
     * {@inheritDoc}
60
     *
61
     * @return static
62
     */
63 2
    public function indexedArray(): self
64
    {
65 2
        return $this->addCheck(new Check(
66 2
            self::ERROR_NOT_INDEXED_ARRAY,
67 2
            fn ($value) => (\array_values($value) === $value),
68 2
            [],
69 2
            [$this->getArrayCheck()]
70 2
        ));
71
    }
72
73
    /**
74
     * {@inheritDoc}
75
     *
76
     * @return static
77
     */
78 1
    public function associativeArray(): self
79
    {
80 1
        return $this->addCheck(new Check(
81 1
            self::ERROR_NOT_ASSOCIATIVE_ARRAY,
82 1
            fn ($value) => array_values($value) !== $value,
83 1
            [],
84 1
            [$this->getArrayCheck()]
85 1
        ));
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     *
91
     * @return static
92
     */
93
    public function arrayAccessible(): self
94
    {
95
        return $this->addCheck(new Check(
96
            self::ERROR_NOT_ARRAY_ACCESSIBLE,
97
            fn ($value) => is_array($value) || $value instanceof ArrayAccess
98
        ));
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     *
104
     * @return static
105
     */
106
    public function iterable(): self
107
    {
108
        return $this->addCheck($this->getIterableCheck());
109
    }
110
111
    /**
112
     * {@inheritDoc}
113
     *
114
     * @return static
115
     */
116
    public function countable(): self
117
    {
118
        return $this->addCheck($this->getCountableCheck());
119
    }
120
121
    /**
122
     * {@inheritDoc}
123
     *
124
     * @return static
125
     */
126
    public function empty(): self
127
    {
128
        return $this->addCheck(new Check(
129
            self::ERROR_NOT_EMPTY,
130
            fn ($value) => count($value) === 0,
131
            [],
132
            [$this->getCountableCheck()]
133
        ));
134
    }
135
136
    /**
137
     * {@inheritDoc}
138
     *
139
     * @return static
140
     */
141
    public function notEmpty(): self
142
    {
143
        return $this->addCheck(new Check(
144
            self::ERROR_EMPTY,
145
            fn ($value) => count($value) > 0,
146
            [],
147
            [$this->getCountableCheck()]
148
        ));
149
    }
150
151
    /**
152
     * {@inheritDoc}
153
     *
154
     * @return static
155
     */
156 2
    public function object(): self
157
    {
158 2
        return $this->addCheck(new Check(
159 2
            self::ERROR_NOT_OBJECT,
160 2
            fn ($value) => is_object($value)
161 2
        ));
162
    }
163
164
    /**
165
     * {@inheritDoc}
166
     *
167
     * @return static
168
     */
169
    public function stdObject(): self
170
    {
171
        return $this->addCheck(new Check(
172
            self::ERROR_NOT_STD_OBJECT,
173
            fn ($value) => $value instanceof \stdClass
174
        ));
175
    }
176
177
    /**
178
     * {@inheritDoc}
179
     *
180
     * @return static
181
     */
182
    public function instanceOf(string $class): self
183
    {
184
        return $this->addCheck(new Check(
185
            self::ERROR_NOT_INSTANCE_OF,
186
            fn ($value) => $value instanceof $class
187
        ));
188
    }
189
190
191
    /**
192
     * {@inheritDoc}
193
     *
194
     * @return static
195
     */
196 2
    public function lengthIs(IntegerRuleInterface $rule): self
197
    {
198
        $violations = [];
199 2
        return $this->addCheck(new Check(
200 2
            self::ERROR_BAD_LENGTH,
201 2
            static function ($value) use ($rule, &$violations) {
202
                try {
203
                    /** @var \Countable $value */
204 2
                    $rule->validate(count($value));
205 1
                    return true;
206 1
                } catch (ValidationError $e) {
207 1
                    $violations = $e->getSummary();
208 1
                    return false;
209
                }
210 2
            },
211 2
            ['violations' => &$violations],
212 2
            [$this->getCountableCheck()]
213 2
        ));
214
    }
215
216
    /**
217
     * {@inheritDoc}
218
     *
219
     * @return static
220
     */
221
    public function hasAttribute(string $name): self
222
    {
223
        return $this->addCheck($this->getHasAttributeCheck($name));
224
    }
225
226
    /**
227
     * {@inheritDoc}
228
     *
229
     * @return static
230
     */
231 1
    public function isAttribute(string $name, BaseRuleInterface $rule): self
232
    {
233
        $violations = [];
234 1
        return $this->addCheck(new Check(
235 1
            self::ERROR_BAD_ATTRIBUTE,
236 1
            function ($value) use ($name, $rule, &$violations) {
237
                try {
238 1
                    $rule->validate(ContainerAccessHelper::getAttributeValue($value, $name));
239
                    return true;
240 1
                } catch (ValidationError $e) {
241 1
                    $violations = $e->getSummary();
242 1
                    return false;
243
                }
244 1
            },
245 1
            ['name' => $name, 'violations' => &$violations],
246 1
            [$this->getHasAttributeCheck($name)]
247 1
        ));
248
    }
249
250
    /**
251
     * {@inheritDoc}
252
     *
253
     * @return static
254
     */
255
    public function everyKeyIs(BaseRuleInterface $rule): self
256
    {
257
        $violations = [];
258
        return $this->addCheck(
259
            new Check(
260
                self::ERROR_SOME_KEYS_BAD,
261
                static function ($value) use ($rule, &$violations) {
262
                    foreach ($value as $k => $v) {
263
                        try {
264
                            $rule->validate($k);
265
                            return true;
266
                        } catch (ValidationError $e) {
267
                            $violations = $e->getSummary();
268
                        }
269
                    }
270
                    return false;
271
                },
272
                ['violations' => &$violations],
273
                [$this->getIterableCheck()]
274
            )
275
        );
276
    }
277
278
    /**
279
     * {@inheritDoc}
280
     *
281
     * @return static
282
     */
283 2
    public function everyValueIs(BaseRuleInterface $rule): self
284
    {
285
        $violations = [];
286 2
        return $this->addCheck(
287 2
            new Check(
288 2
                self::ERROR_SOME_VALUES_BAD,
289 2
                static function ($value) use ($rule, &$violations) {
290 2
                    foreach ($value as $v) {
291
                        try {
292 2
                            $rule->validate($v);
293 1
                        } catch (ValidationError $e) {
294 1
                            $violations = $e->getSummary();
295 1
                            return false;
296
                        }
297
                    }
298 1
                    return true;
299 2
                },
300 2
                ['violations' => &$violations],
301 2
                [$this->getIterableCheck()]
302 2
            )
303 2
        );
304
    }
305
306 5
    protected function getArrayCheck(): CheckInterface
307
    {
308 5
        return new Check(
309 5
            self::ERROR_NOT_ARRAY,
310 5
            fn ($value) => is_array($value)
311 5
        );
312
    }
313
314 2
    protected function getCountableCheck(): CheckInterface
315
    {
316 2
        return new Check(
317 2
            self::ERROR_NOT_COUNTABLE,
318 2
            fn ($value) => is_countable($value)
319 2
        );
320
    }
321
322 2
    protected function getIterableCheck(): CheckInterface
323
    {
324 2
        return new Check(
325 2
            self::ERROR_NOT_ITERABLE,
326 2
            fn ($value) => is_iterable($value)
327 2
        );
328
    }
329
330 5
    protected function getHasAttributeCheck(string $name): CheckInterface
331
    {
332 5
        return new Check(
333 5
            self::ERROR_ATTRIBUTE_NOT_EXIST,
334 5
            fn ($value) => ContainerAccessHelper::hasAccessibleAttribute($value, $name),
335 5
            ['name' => $name]
336 5
        );
337
    }
338
}
339