Passed
Push — master ( bc036e...f8a9bb )
by Smoren
02:19
created

ContainerRule::allValuesAre()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 3.0013

Importance

Changes 0
Metric Value
cc 3
eloc 16
nc 1
nop 1
dl 0
loc 23
ccs 18
cts 19
cp 0.9474
crap 3.0013
rs 9.7333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\Validator\Rules;
6
7
use Smoren\Validator\Checks\Check;
8
use Smoren\Validator\Exceptions\ValidationError;
9
use Smoren\Validator\Helpers\ContainerAccessHelper;
10
use Smoren\Validator\Interfaces\RuleInterface;
11
use Smoren\Validator\Interfaces\CheckInterface;
12
use Smoren\Validator\Interfaces\ContainerRuleInterface;
13
use Smoren\Validator\Interfaces\IntegerRuleInterface;
14
use Smoren\Validator\Structs\CheckErrorName;
15
use Smoren\Validator\Structs\CheckName;
16
use Smoren\Validator\Structs\Param;
17
18
class ContainerRule extends Rule implements ContainerRuleInterface
19
{
20
    /**
21
     * ContainerRule constructor.
22
     */
23 18
    public function __construct(string $name)
24
    {
25
        parent::__construct($name);
26 18
        $this->check(new Check(
27 18
            CheckName::CONTAINER,
28 18
            CheckErrorName::NOT_CONTAINER,
29 18
            fn ($value) => \is_array($value) || \is_object($value),
30 18
            []
31 18
        ), true);
32
    }
33
34
    /**
35
     * {@inheritDoc}
36
     *
37
     * @return static
38
     */
39
    public function array(): self
40
    {
41
        return $this->check($this->getArrayCheck());
42
    }
43
44
    /**
45
     * {@inheritDoc}
46
     *
47
     * @return static
48
     */
49 2
    public function indexedArray(): self
50
    {
51 2
        return $this->check(new Check(
52 2
            CheckName::INDEXED_ARRAY,
53 2
            CheckErrorName::NOT_INDEXED_ARRAY,
54 2
            fn ($value) => (\array_values($value) === $value),
55 2
            [],
56 2
            [$this->getArrayCheck()]
57 2
        ));
58
    }
59
60
    /**
61
     * {@inheritDoc}
62
     *
63
     * @return static
64
     */
65 1
    public function associativeArray(): self
66
    {
67 1
        return $this->check(new Check(
68 1
            CheckName::ASSOCIATIVE_ARRAY,
69 1
            CheckErrorName::NOT_ASSOCIATIVE_ARRAY,
70 1
            fn ($value) => \array_values($value) !== $value,
71 1
            [],
72 1
            [$this->getArrayCheck()]
73 1
        ));
74
    }
75
76
    /**
77
     * {@inheritDoc}
78
     *
79
     * @return static
80
     */
81
    public function arrayAccessible(): self
82
    {
83
        return $this->check(new Check(
84
            CheckName::ARRAY_ACCESSIBLE,
85
            CheckErrorName::NOT_ARRAY_ACCESSIBLE,
86
            fn ($value) => \is_array($value) || $value instanceof \ArrayAccess
87
        ));
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     *
93
     * @return static
94
     */
95
    public function iterable(): self
96
    {
97
        return $this->check($this->getIterableCheck());
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     *
103
     * @return static
104
     */
105
    public function countable(): self
106
    {
107
        return $this->check($this->getCountableCheck());
108
    }
109
110
    /**
111
     * {@inheritDoc}
112
     *
113
     * @return static
114
     */
115
    public function empty(): self
116
    {
117
        return $this->check(new Check(
118
            CheckName::EMPTY,
119
            CheckErrorName::NOT_EMPTY,
120
            fn ($value) => \count($value) === 0,
121
            [],
122
            [$this->getCountableCheck()]
123
        ));
124
    }
125
126
    /**
127
     * {@inheritDoc}
128
     *
129
     * @return static
130
     */
131
    public function notEmpty(): self
132
    {
133
        return $this->check(new Check(
134
            CheckName::NOT_EMPTY,
135
            CheckErrorName::EMPTY,
136
            fn ($value) => \count($value) > 0,
137
            [],
138
            [$this->getCountableCheck()]
139
        ));
140
    }
141
142
    /**
143
     * {@inheritDoc}
144
     *
145
     * @return static
146
     */
147 2
    public function object(): self
148
    {
149 2
        return $this->check(new Check(
150 2
            CheckName::OBJECT,
151 2
            CheckErrorName::NOT_OBJECT,
152 2
            fn ($value) => \is_object($value)
153 2
        ));
154
    }
155
156
    /**
157
     * {@inheritDoc}
158
     *
159
     * @return static
160
     */
161
    public function stdObject(): self
162
    {
163
        return $this->check(new Check(
164
            CheckName::STD_OBJECT,
165
            CheckErrorName::NOT_STD_OBJECT,
166
            fn ($value) => $value instanceof \stdClass
167
        ));
168
    }
169
170
    /**
171
     * {@inheritDoc}
172
     *
173
     * @return static
174
     */
175
    public function instanceOf(string $class): self
176
    {
177
        return $this->check(new Check(
178
            CheckName::INSTANCE_OF,
179
            CheckErrorName::NOT_INSTANCE_OF,
180
            fn ($value) => $value instanceof $class
181
        ));
182
    }
183
184
    /**
185
     * {@inheritDoc}
186
     *
187
     * @return static
188
     */
189 2
    public function lengthIs(IntegerRuleInterface $rule): self
190
    {
191
        $violations = [];
192 2
        return $this->check(new Check(
193 2
            CheckName::LENGTH_IS,
194 2
            CheckErrorName::BAD_LENGTH,
195 2
            static function ($value) use ($rule, &$violations) {
196
                try {
197
                    /** @var \Countable $value */
198 2
                    $rule->validate(\count($value));
199 1
                    return true;
200 1
                } catch (ValidationError $e) {
201 1
                    $violations = $e->getSummary();
202 1
                    return false;
203
                }
204 2
            },
205 2
            [Param::VIOLATIONS => &$violations],
206 2
            [$this->getCountableCheck()]
207 2
        ));
208
    }
209
210
    /**
211
     * {@inheritDoc}
212
     *
213
     * @return static
214
     */
215 2
    public function hasAttribute(string $name, ?RuleInterface $rule = null): self
216
    {
217
        if ($rule === null) {
218
            return $this->check($this->getHasAttributeCheck($name));
219
        }
220
221
        $violations = [];
222 2
        return $this->check(new Check(
223 2
            CheckName::HAS_ATTRIBUTE,
224 2
            CheckErrorName::BAD_ATTRIBUTE,
225 2
            function ($value) use ($name, $rule, &$violations) {
226
                try {
227 2
                    $rule->validate(ContainerAccessHelper::getAttributeValue($value, $name));
228 1
                    return true;
229 1
                } catch (ValidationError $e) {
230 1
                    $violations = $e->getSummary();
231 1
                    return false;
232
                }
233 2
            },
234 2
            [
235 2
                Param::ATTRIBUTE => $name,
236 2
                Param::RULE => $rule->getName(),
237 2
                Param::VIOLATIONS => &$violations,
238 2
            ],
239 2
            [$this->getHasAttributeCheck($name)]
240 2
        ));
241
    }
242
243
    /**
244
     * {@inheritDoc}
245
     *
246
     * @return static
247
     */
248
    public function hasOptionalAttribute(string $name, RuleInterface $rule): self
249
    {
250
        $violations = [];
251
        return $this->check(new Check(
252
            CheckName::HAS_ATTRIBUTE,
253
            CheckErrorName::BAD_ATTRIBUTE,
254
            function ($value) use ($name, $rule, &$violations) {
255
                if (!ContainerAccessHelper::hasAccessibleAttribute($value, $name)) {
256
                    return true;
257
                }
258
                try {
259
                    $rule->validate(ContainerAccessHelper::getAttributeValue($value, $name));
260
                    return true;
261
                } catch (ValidationError $e) {
262
                    $violations = $e->getSummary();
263
                    return false;
264
                }
265
            },
266
            [
267
                Param::ATTRIBUTE => $name,
268
                Param::RULE => $rule->getName(),
269
                Param::VIOLATIONS => &$violations,
270
            ],
271
        ));
272
    }
273
274
    /**
275
     * {@inheritDoc}
276
     *
277
     * @return static
278
     */
279
    public function allKeysAre(RuleInterface $rule): self
280
    {
281
        $violations = [];
282
        return $this->check(
283
            new Check(
284
                CheckName::ALL_KEYS_ARE,
285
                CheckErrorName::SOME_KEYS_BAD,
286
                static function ($value) use ($rule, &$violations) {
287
                    foreach ($value as $k => $v) {
288
                        try {
289
                            $rule->validate($k);
290
                        } catch (ValidationError $e) {
291
                            $violations = $e->getSummary();
292
                            return false;
293
                        }
294
                    }
295
                    return true;
296
                },
297
                [
298
                    Param::RULE => $rule->getName(),
299
                    Param::VIOLATIONS => &$violations,
300
                ],
301
                [$this->getIterableCheck()]
302
            )
303
        );
304
    }
305
306
    /**
307
     * {@inheritDoc}
308
     *
309
     * @return static
310
     */
311 2
    public function allValuesAre(RuleInterface $rule): self
312
    {
313
        $violations = [];
314 2
        return $this->check(
315 2
            new Check(
316 2
                CheckName::ALL_VALUES_ARE,
317 2
                CheckErrorName::SOME_VALUES_BAD,
318 2
                static function ($value) use ($rule, &$violations) {
319 2
                    foreach ($value as $v) {
320
                        try {
321 2
                            $rule->validate($v);
322 1
                        } catch (ValidationError $e) {
323 1
                            $violations = $e->getSummary();
324 1
                            return false;
325
                        }
326
                    }
327 1
                    return true;
328 2
                },
329 2
                [
330 2
                    Param::RULE => $rule->getName(),
331 2
                    Param::VIOLATIONS => &$violations,
332 2
                ],
333 2
                [$this->getIterableCheck()]
334 2
            )
335 2
        );
336
    }
337
338 5
    protected function getArrayCheck(): CheckInterface
339
    {
340 5
        return new Check(
341 5
            CheckName::ARRAY,
342 5
            CheckErrorName::NOT_ARRAY,
343 5
            fn ($value) => \is_array($value)
344 5
        );
345
    }
346
347 2
    protected function getCountableCheck(): CheckInterface
348
    {
349 2
        return new Check(
350 2
            CheckName::COUNTABLE,
351 2
            CheckErrorName::NOT_COUNTABLE,
352 2
            fn ($value) => \is_countable($value)
353 2
        );
354
    }
355
356 2
    protected function getIterableCheck(): CheckInterface
357
    {
358 2
        return new Check(
359 2
            CheckName::ITERABLE,
360 2
            CheckErrorName::NOT_ITERABLE,
361 2
            fn ($value) => \is_iterable($value)
362 2
        );
363
    }
364
365 5
    protected function getHasAttributeCheck(string $name): CheckInterface
366
    {
367 5
        return new Check(
368 5
            CheckName::HAS_ATTRIBUTE,
369 5
            CheckErrorName::ATTRIBUTE_NOT_EXIST,
370 5
            fn ($value) => ContainerAccessHelper::hasAccessibleAttribute($value, $name),
371 5
            [Param::ATTRIBUTE => $name]
372 5
        );
373
    }
374
}
375