Passed
Push — master ( e3578b...5bb523 )
by Smoren
02:22
created

ContainerRule::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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