Nested::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1
c 2
b 0
f 0
nc 1
nop 13
dl 0
loc 20
cc 1
rs 10
ccs 9
cts 9
cp 1
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Attribute;
8
use Closure;
9
use InvalidArgumentException;
10
use JetBrains\PhpStorm\ArrayShape;
11
use ReflectionProperty;
12
use Traversable;
13
use Yiisoft\Strings\StringHelper;
14
use Yiisoft\Validator\AfterInitAttributeEventInterface;
15
use Yiisoft\Validator\DataSet\ObjectDataSet;
16
use Yiisoft\Validator\Helper\PropagateOptionsHelper;
17
use Yiisoft\Validator\PropagateOptionsInterface;
18
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
19
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
20
use Yiisoft\Validator\Rule\Trait\WhenTrait;
21
use Yiisoft\Validator\RuleInterface;
22
use Yiisoft\Validator\Helper\RulesDumper;
23
use Yiisoft\Validator\RulesProvider\AttributesRulesProvider;
24
use Yiisoft\Validator\RulesProviderInterface;
25
use Yiisoft\Validator\DumpedRuleInterface;
26
use Yiisoft\Validator\SkipOnEmptyInterface;
27
use Yiisoft\Validator\SkipOnErrorInterface;
28
use Yiisoft\Validator\Tests\Rule\NestedTest;
29
use Yiisoft\Validator\WhenInterface;
30
31
use function array_pop;
32
use function count;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Yiisoft\Validator\Rule\count. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
33
use function implode;
34
use function is_array;
35
use function is_int;
36
use function is_string;
37
use function ltrim;
38
use function rtrim;
39
use function sprintf;
40
41
/**
42
 * Used to define rules for validation of nested structures:
43
 *
44
 * - For one-to-one relation, using `Nested` rule is enough.
45
 * - One-to-many and many-to-many relations require pairing with {@see Each} rule.
46
 *
47
 * An example with blog post:
48
 *
49
 * ```php
50
 * $rule = new Nested([
51
 *     'title' => [new Length(max: 255)],
52
 *     // One-to-one relation
53
 *     'author' => new Nested([
54
 *         'name' => [new Length(min: 1)],
55
 *     ]),
56
 *     // One-to-many relation
57
 *     'files' => new Each([
58
 *          new Nested([
59
 *             'url' => [new Url()],
60
 *         ]),
61
 *     ]),
62
 * ]);
63
 * ```
64
 *
65
 * There is an alternative way to write this using dot notation and shortcuts:
66
 *
67
 * ```php
68
 * $rule = new Nested([
69
 *     'title' => [new Length(max: 255)],
70
 *     'author.name' => [new Length(min: 1)],
71
 *     'files.*.url' => [new Url()],
72
 * ]);
73
 * ```
74
 *
75 26
 * Also it's possible to use plain keys and omit arrays for single rules:
76
 *
77
 *  * ```php
78
 * $rules = [
79
 *     new Nested([
80
 *         'author' => [
81
 *             'name' => new Length(min: 1),
82
 *         ],
83
 *     ]),
84
 * ];
85
 * ```
86
 *
87
 * For more examples please refer to the guide.
88
 *
89
 * It's also possible to use DTO objects with PHP attributes, see {@see ObjectDataSet} documentation and guide for
90
 * details.
91
 *
92
 * Supports propagation of options (see {@see PropagateOptionsHelper::propagate()} for available options and
93
 * requirements).
94
 *
95
 * @see NestedHandler Corresponding handler performing the actual validation.
96
 *
97
 * @psalm-import-type WhenType from WhenInterface
98
 *
99
 * @psalm-type RawNestedRulesArray = array<array<RuleInterface>|RuleInterface>
100
 * @psalm-type NormalizedNestedRulesArray = array<list<RuleInterface>|RuleInterface>
101
 */
102
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
103
final class Nested implements
104
    DumpedRuleInterface,
105
    SkipOnEmptyInterface,
106
    SkipOnErrorInterface,
107
    WhenInterface,
108
    PropagateOptionsInterface,
109
    AfterInitAttributeEventInterface
110
{
111 26
    use SkipOnEmptyTrait;
112
    use SkipOnErrorTrait;
113
    use WhenTrait;
114 2
115
    /**
116 2
     * A character acting as a separator when using alternative (short) syntax.
117
     */
118
    private const SEPARATOR = '.';
119
    /**
120
     * A character acting as a shortcut when using alternative (short) syntax with {@see Nested} and {@see Each}
121
     * combinations.
122 53
     */
123
    private const EACH_SHORTCUT = '*';
124 53
125
    /**
126
     * @var array|null A set of ready to use rule instances. The 1st level is always
127 11
     * an array of rules, the 2nd level is either a list of rules or a single rule.
128
     *
129 11
     * @psalm-var NormalizedNestedRulesArray|null
130
     */
131
    private array|null $rules;
132 5
133
    /**
134 5
     * @param iterable|object|string|null $rules Rules for validating nested structure. The following types are
135
     * supported:
136
     *
137 3
     * - Array or object implementing {@see Traversable} interface containing rules. Either iterables containing
138
     * {@see RuleInterface} implementations or a single rule instances are expected. All iterables regardless of the
139 3
     * nesting level will be converted to arrays at the end.
140
     * - Object implementing {@see RulesProviderInterface}.
141
     * - Name of a class containing rules declared via PHP attributes.
142 5
     * - `null` if validated value is an object. It can either implement {@see RulesProviderInterface} or contain rules
143
     * declared via PHP attributes.
144 5
     *
145
     * @psalm-param iterable|object|class-string|null $rules
146
     *
147 39
     * @param int $validatedObjectPropertyVisibility Visibility levels to use for parsed properties when validated value
148
     * is an object providing rules / data. For example: public and protected only, this means that the rest (private
149 39
     * ones) will be skipped. Defaults to all visibility levels (public, protected and private). See
150
     * {@see ObjectDataSet} for details on providing rules / data in validated object and {@see ObjectParser} for
151
     * overview how parsing works.
152 10
     *
153
     * @psalm-param int-mask-of<ReflectionProperty::IS_*> $validatedObjectPropertyVisibility
154 10
     *
155
     * @param int $rulesSourceClassPropertyVisibility Visibility levels to use for parsed properties when {@see $rules}
156
     * source is a name of the class providing rules. For example: public and protected only, this means that the rest
157
     * (private ones) will be skipped. Defaults to all visibility levels (public, protected and private). See
158
     * {@see ObjectDataSet} for details on providing rules via class and {@see ObjectParser} for overview how parsing
159
     * works.
160 26
     *
161
     * @psalm-param int-mask-of<ReflectionProperty::IS_*> $rulesSourceClassPropertyVisibility
162 26
     *
163 16
     * @param string $noRulesWithNoObjectMessage Error message used when validation fails because the validated value is
164
     * not an object and the rules were not explicitly specified via {@see $rules}:
165 16
     *
166
     * You may use the following placeholders in the message:
167
     *
168 10
     * - `{attribute}`: the translated label of the attribute being validated.
169 1
     * - `{type}`: the type of the value being validated.
170 9
     * @param string $incorrectDataSetTypeMessage Error message used when validation fails because the validated value
171 4
     * is an object providing wrong type of data (neither array nor an object).
172
     *
173 5
     * You may use the following placeholders in the message:
174
     *
175
     * - `{type}`: the type of the data set retrieved from the validated object.
176 10
     * @param string $incorrectInputMessage Error message used when validation fails because the validated value is
177 8
     * neither an array nor an object.
178
     *
179 8
     * You may use the following placeholders in the message:
180 8
     *
181
     * - `{attribute}`: the translated label of the attribute being validated.
182
     * - `{type}`: the type of the value being validated.
183 7
     * @param bool $requirePropertyPath Whether to require a single data item to be passed in data according to declared
184 1
     * nesting level structure (all keys in the sequence must be the present). Used only when validated value is an
185
     * array. Enabled by default. See {@see $noPropertyPathMessage} for customization of error message.
186
     * @param string $noPropertyPathMessage Error message used when validation fails because {@see $requirePropertyPath}
187
     * option was enabled and the validated array contains missing data item.
188
     *
189
     * You may use the following placeholders in the message:
190
     *
191 10
     * - `{path}`: the path of the value being validated. Can be either a simple key of integer / string type for a
192
     * single nesting level or a sequence of keys concatenated using dot notation (see {@see SEPARATOR}).
193 10
     * - `{attribute}`: the translated label of the attribute being validated.
194
     * @param bool $handleEachShortcut Whether to handle {@see EACH_SHORTCUT}. Enabled by default meaning shortcuts are
195 10
     * supported. Can be disabled if they are not used to prevent additional checks and improve performance.
196 9
     * @param bool $propagateOptions Whether the propagation of options is enabled (see
197 7
     * {@see PropagateOptionsHelper::propagate()} for supported options and requirements). Disabled by default.
198 9
     * @param bool|callable|null $skipOnEmpty Whether to skip this `Nested` rule with all defined {@see $rules} if the
199 2
     * validated value is empty / not passed. See {@see SkipOnEmptyInterface}.
200
     * @param bool $skipOnError Whether to skip this `Nested` rule with all defined {@see $rules} if any of the previous
201
     * rules gave an error. See {@see SkipOnErrorInterface}.
202 2
     * @param Closure|null $when  A callable to define a condition for applying this `Nested` rule with all defined
203
     * {@see $rules}. See {@see WhenInterface}.
204
     *
205 2
     * @psalm-param WhenType $when
206
     */
207
    public function __construct(
208
        iterable|object|string|null $rules = null,
209
        private int $validatedObjectPropertyVisibility = ReflectionProperty::IS_PRIVATE
210 8
        | ReflectionProperty::IS_PROTECTED
211
        | ReflectionProperty::IS_PUBLIC,
212
        private int $rulesSourceClassPropertyVisibility = ReflectionProperty::IS_PRIVATE
213 8
        | ReflectionProperty::IS_PROTECTED
214 8
        | ReflectionProperty::IS_PUBLIC,
215 8
        private string $noRulesWithNoObjectMessage = 'Nested rule without rules can be used for objects only.',
216 8
        private string $incorrectDataSetTypeMessage = 'An object data set data can only have an array type.',
217
        private string $incorrectInputMessage = 'The value must be an array or an object.',
218 8
        private bool $requirePropertyPath = false,
219 7
        private string $noPropertyPathMessage = 'Property "{path}" is not found.',
220 1
        private bool $handleEachShortcut = true,
221
        private bool $propagateOptions = false,
222
        private mixed $skipOnEmpty = null,
223 6
        private bool $skipOnError = false,
224
        private Closure|null $when = null,
225
    ) {
226
        $this->prepareRules($rules);
227
    }
228 6
229 6
    public function getName(): string
230
    {
231
        return self::class;
232
    }
233
234
    /**
235
     * Gets a set of rules for running the validation.
236
     *
237
     * @return array|null A set of rules. `null` means the rules are expected to be provided with a validated value.
238
     *
239
     * @psalm-return NormalizedNestedRulesArray
240
     */
241
    public function getRules(): array|null
242
    {
243
        return $this->rules;
244
    }
245
246
    /**
247
     * Gets visibility levels to use for parsed properties when validated value is an object providing rules / data.
248
     * Defaults to all visibility levels (public, protected and private)
249
     *
250
     * @return int A number representing visibility levels.
251
     *
252
     * @psalm-return int-mask-of<ReflectionProperty::IS_*>
253
     *
254
     * @see $validatedObjectPropertyVisibility
255
     */
256 7
    public function getValidatedObjectPropertyVisibility(): int
257
    {
258
        return $this->validatedObjectPropertyVisibility;
259
    }
260
261
    /**
262
     * Gets error message used when validation fails because the validated value is not an object and the rules were not
263
     * explicitly specified via {@see $rules}.
264
     *
265
     * @return string Error message / template.
266
     *
267 7
     * @see $incorrectInputMessage
268 7
     */
269
    public function getNoRulesWithNoObjectMessage(): string
270
    {
271
        return $this->noRulesWithNoObjectMessage;
272 7
    }
273
274
    /**
275 1
     * Gets error message used when validation fails because the validated value is an object providing wrong type of
276
     * data (neither array nor an object).
277 1
     *
278
     * @return string Error message / template.
279
     *
280
     * @see $incorrectDataSetTypeMessage
281
     */
282
    public function getIncorrectDataSetTypeMessage(): string
283
    {
284
        return $this->incorrectDataSetTypeMessage;
285
    }
286 1
287 1
    /**
288 1
     * Gets error message used when validation fails because the validated value is neither an array nor an object.
289 1
     *
290
     * @return string Error message / template.
291 1
     *
292 1
     * @see $incorrectInputMessage
293
     */
294 1
    public function getIncorrectInputMessage(): string
295 1
    {
296
        return $this->incorrectInputMessage;
297
    }
298 1
299
    /**
300 1
     * Whether to require a single data item to be passed in data according to declared nesting level structure (all
301 1
     * keys in the sequence must be the present). Enabled by default.
302
     *
303
     * @return bool `true` if required and `false` otherwise.
304
     *
305
     * @see $requirePropertyPath
306 1
     */
307
    public function isPropertyPathRequired(): bool
308
    {
309 5
        return $this->requirePropertyPath;
310
    }
311
312
    /**
313
     * Gets error message used when validation fails because {@see $requirePropertyPath} option was enabled and the
314
     * validated array contains missing data item.
315
     *
316
     * @return string Error message / template.
317
     *
318
     * @see $getNoPropertyPathMessage
319
     */
320
    public function getNoPropertyPathMessage(): string
321
    {
322
        return $this->noPropertyPathMessage;
323 5
    }
324
325
    /**
326
     * Prepares raw rules passed in the constructor for usage in handler. As a result, {@see $rules} property will
327 5
     * contain ready to use rules.
328
     *
329
     * @param iterable|object|string|null $source Raw rules passed in the constructor.
330
     *
331 5
     * @throws InvalidArgumentException When rules' source has wrong type.
332
     * @throws InvalidArgumentException When source contains items that are not rules.
333
     */
334
    private function prepareRules(iterable|object|string|null $source): void
335 5
    {
336
        if ($source === null) {
337
            $this->rules = null;
338 5
            return;
339 5
        }
340 5
341 5
        if ($source instanceof RulesProviderInterface) {
342
            $rules = $source->getRules();
343
        } elseif (is_string($source) && class_exists($source)) {
344
            $rules = (new AttributesRulesProvider($source, $this->rulesSourceClassPropertyVisibility))->getRules();
345 53
        } elseif (is_iterable($source)) {
346
            $rules = $source;
347 53
        } else {
348
            throw new InvalidArgumentException(
349
                'The $rules argument passed to Nested rule can be either: a null, an object implementing ' .
350
                'RulesProviderInterface, a class string or an iterable.'
351
            );
352
        }
353
354
        self::ensureArrayHasRules($rules);
355
356
        if ($this->handleEachShortcut) {
357
            $this->handleEachShortcut($rules);
358
        }
359
360
        $preparedRules = [];
361
        $this->flattenKeys($rules, $preparedRules);
362
363
        $this->rules = $preparedRules;
364
365
        if ($this->propagateOptions) {
366
            $this->propagateOptions();
367
        }
368
    }
369
370
    /**
371
     * Recursively flattens plain keys to allow any nesting level. The keys in the result array are joined using
372
     * {@see SEPARATOR}.
373
     *
374
     * Example of input:
375
     *
376
     * ```php
377
     * [
378
     *     'key1' => [
379
     *         'key2' => [
380
     *             'key3 => [
381
     *                 // ...
382
     *             ],
383
     *         ],
384
     *     ],
385
     * ];
386
     * ```
387
     *
388
     * Example of output for default {@see SEPARATOR}:
389
     *
390
     * ```php
391
     * [
392
     *     'key1.key2.key3' => [
393
     *         // ...
394
     *     ],
395
     * ],
396
     * ```
397
     *
398
     * @param array $rawRules Raw rules array which keys need to be flattened.
399
     *
400
     * @psalm-param RawNestedRulesArray $rawRules
401
     *
402
     * @param array $resultRules Result rules array with flattened keys passed by reference.
403
     *
404
     * @psalm-param NormalizedNestedRulesArray $resultRules
405
     *
406
     * @param string|null $baseValuePath Base value path string. Can be a single key or multiple keys joined with
407
     * {@see SEPARATOR}. `null` is used for the first call.
408
     */
409
    private function flattenKeys(array $rawRules, array &$resultRules, ?string $baseValuePath = null): void
410
    {
411
        foreach ($rawRules as $valuePath => $validationRules) {
412
            if (is_int($valuePath)) {
413
                $key = $baseValuePath;
414
            } else {
415
                $key = ($baseValuePath !== null ? $baseValuePath . self::SEPARATOR : '') . $valuePath;
416
            }
417
418
            if (is_array($validationRules)) {
419
                $this->flattenKeys($validationRules, $resultRules, $key);
420
                continue;
421
            }
422
423
            if ($key === null) {
424
                $resultRules[] = $validationRules;
425
            } else {
426
                /** @psalm-suppress UndefinedInterfaceMethod */
427
                $resultRules[$key][] = $validationRules;
428
            }
429
        }
430
    }
431
432
    /**
433
     * Recursively checks that every item of source iterable is a valid rule instance ({@see RuleInterface}). As a
434
     * result, all iterables will be converted to arrays at the end, while single rules will be kept as is.
435
     *
436
     * @param iterable $rules Source iterable that will be checked and converted to array (so it's passed by reference).
437
     *
438
     * @psalm-param-out RawNestedRulesArray $rules
439
     *
440
     * @throws InvalidArgumentException When iterable contains items that are not rules.
441
     *
442
     * @psalm-suppress ReferenceConstraintViolation
443
     */
444
    private static function ensureArrayHasRules(iterable &$rules): void
445
    {
446
        if ($rules instanceof Traversable) {
447
            $rules = iterator_to_array($rules);
448
        }
449
450
        /** @var mixed $rule */
451
        foreach ($rules as &$rule) {
452
            if (is_iterable($rule)) {
453
                self::ensureArrayHasRules($rule);
454
            } elseif (!$rule instanceof RuleInterface) {
455
                $message = sprintf(
456
                    'Every rule must be an instance of %s, %s given.',
457
                    RuleInterface::class,
458
                    get_debug_type($rule)
459
                );
460
461
                throw new InvalidArgumentException($message);
462
            }
463
        }
464
    }
465
466
    /**
467
     * Converts rules defined with {@see EACH_SHORTCUT} to separate `Nested` and `Each` rules.
468
     *
469
     * @oaram array $rules Rules array for replacing {@see EACH_SHORTCUT} passed by reference.
470
     *
471
     * @psalm-param RawNestedRulesArray $rules
472
     */
473
    private function handleEachShortcut(array &$rules): void
474
    {
475
        while (true) {
476
            $breakWhile = true;
477
            $rulesMap = [];
478
479
            foreach ($rules as $valuePath => $rule) {
480
                if ($valuePath === self::EACH_SHORTCUT) {
481
                    throw new InvalidArgumentException('Bare shortcut is prohibited. Use "Each" rule instead.');
482
                }
483
484
                $parts = StringHelper::parsePath(
485
                    (string) $valuePath,
486
                    delimiter: self::EACH_SHORTCUT,
487
                    preserveDelimiterEscaping: true
488
                );
489
                if (count($parts) === 1) {
490
                    continue;
491
                }
492
493
                /**
494
                 * Might be a bug of XDebug, because these lines are covered by tests.
495
                 *
496
                 * @see NestedTest::dataWithOtherNestedAndEach() for test cases prefixed with "withShortcut".
497
                 */
498
                // @codeCoverageIgnoreStart
499
                $breakWhile = false;
500
501
                $lastValuePath = array_pop($parts);
502
                $lastValuePath = ltrim($lastValuePath, self::SEPARATOR);
503
                $lastValuePath = str_replace('\\' . self::EACH_SHORTCUT, self::EACH_SHORTCUT, $lastValuePath);
504
505
                $remainingValuePath = implode(self::EACH_SHORTCUT, $parts);
506
                $remainingValuePath = rtrim($remainingValuePath, self::SEPARATOR);
507
508
                if (!isset($rulesMap[$remainingValuePath])) {
509
                    $rulesMap[$remainingValuePath] = [];
510
                }
511
512
                $rulesMap[$remainingValuePath][$lastValuePath] = $rule;
513
                unset($rules[$valuePath]);
514
                // @codeCoverageIgnoreEnd
515
            }
516
517
            foreach ($rulesMap as $valuePath => $nestedRules) {
518
                /**
519
                 * Might be a bug of XDebug, because this line is covered by tests.
520
                 *
521
                 * @see NestedTest::dataWithOtherNestedAndEach() for test cases prefixed with "withShortcut".
522
                 */
523
                // @codeCoverageIgnoreStart
524
                $rules[$valuePath] = new Each([new self($nestedRules, handleEachShortcut: false)]);
525
                // @codeCoverageIgnoreEnd
526
            }
527
528
            if ($breakWhile === true) {
529
                break;
530
            }
531
        }
532
    }
533
534
    public function propagateOptions(): void
535
    {
536
        if ($this->rules === null) {
537
            return;
538
        }
539
540
        $rules = [];
541
        foreach ($this->rules as $attributeRulesIndex => $attributeRules) {
542
            $rules[$attributeRulesIndex] = is_iterable($attributeRules)
543
                ? PropagateOptionsHelper::propagate($this, $attributeRules)
544
                : PropagateOptionsHelper::propagateToRule($this, $attributeRules);
545
        }
546
547
        $this->rules = $rules;
548
    }
549
550
    public function afterInitAttribute(object $object): void
551
    {
552
        if ($this->rules === null) {
553
            return;
554
        }
555
556
        foreach ($this->rules as $rules) {
557
            if (is_array($rules)) {
558
                foreach ($rules as $rule) {
559
                    if ($rule instanceof AfterInitAttributeEventInterface) {
560
                        $rule->afterInitAttribute($object);
561
                    }
562
                }
563
            } else {
564
                if ($rules instanceof AfterInitAttributeEventInterface) {
565
                    $rules->afterInitAttribute($object);
566
                }
567
            }
568
        }
569
    }
570
571
    #[ArrayShape([
572
        'requirePropertyPath' => 'bool',
573
        'noRulesWithNoObjectMessage' => 'array',
574
        'incorrectDataSetTypeMessage' => 'array',
575
        'incorrectInputMessage' => 'array',
576
        'noPropertyPathMessage' => 'array',
577
        'skipOnEmpty' => 'bool',
578
        'skipOnError' => 'bool',
579
        'rules' => 'array|null',
580
    ])]
581
    public function getOptions(): array
582
    {
583
        return [
584
            'noRulesWithNoObjectMessage' => [
585
                'template' => $this->noRulesWithNoObjectMessage,
586
                'parameters' => [],
587
            ],
588
            'incorrectDataSetTypeMessage' => [
589
                'template' => $this->incorrectDataSetTypeMessage,
590
                'parameters' => [],
591
            ],
592
            'incorrectInputMessage' => [
593
                'template' => $this->incorrectInputMessage,
594
                'parameters' => [],
595
            ],
596
            'noPropertyPathMessage' => [
597
                'template' => $this->getNoPropertyPathMessage(),
598
                'parameters' => [],
599
            ],
600
            'requirePropertyPath' => $this->isPropertyPathRequired(),
601
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
602
            'skipOnError' => $this->skipOnError,
603
            'rules' => $this->rules === null ? null : RulesDumper::asArray($this->rules),
604
        ];
605
    }
606
607
    public function getHandler(): string
608
    {
609
        return NestedHandler::class;
610
    }
611
}
612