Passed
Pull Request — master (#564)
by Sergei
20:34 queued 17:40
created

Nested::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 13
dl 0
loc 20
rs 10
c 2
b 0
f 0
ccs 10
cts 10
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\RuleWithOptionsInterface;
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
 * @psalm-type RawRulesType = array<array<RuleInterface>|RuleInterface>
99
 * @psalm-type ReadyRulesType = array<list<RuleInterface>|RuleInterface>
100
 * @psalm-type OptionalReadyRulesType = ReadyRulesType|null
101
 */
102
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
103
final class Nested implements
104
    RuleWithOptionsInterface,
105
    SkipOnErrorInterface,
106
    WhenInterface,
107
    SkipOnEmptyInterface,
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 OptionalReadyRulesType A set of ready to use rule instances. The 1st level is always
0 ignored issues
show
Bug introduced by
The type Yiisoft\Validator\Rule\OptionalReadyRulesType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
127 11
     * an array of rules, the 2nd level is either a list of rules or a single rule.
128
     */
129 11
    private array|null $rules;
130
131
    /**
132 5
     * @param iterable|object|string|null $rules Rules for validating nested structure. The following types are
133
     * supported:
134 5
     *
135
     * - Array or object implementing {@see Traversable} interface containing rules. Either iterables containing
136
     * {@see RuleInterface} implementations or a single rule instances are expected. All iterables regardless of the
137 3
     * nesting level will be converted to arrays at the end.
138
     * - Object implementing {@see RulesProviderInterface}.
139 3
     * - Name of a class containing rules declared via PHP attributes.
140
     * - `null` if validated value is an object. It can either implement {@see RulesProviderInterface} or contain rules
141
     * declared via PHP attributes.
142 5
     * @psalm-param iterable|object|class-string|null $rules
143
     *
144 5
     * @param int $validatedObjectPropertyVisibility Visibility levels to use for parsed properties when validated value
145
     * is an object providing rules / data. For example: public and protected only, this means that the rest (private
146
     * ones) will be skipped. Defaults to all visibility levels (public, protected and private). See
147 39
     * {@see ObjectDataSet} for details on providing rules / data in validated object and {@see ObjectParser} for
148
     * overview how parsing works.
149 39
     * @psalm-param int-mask-of<ReflectionProperty::IS_*> $validatedObjectPropertyVisibility
150
     *
151
     * @param int $rulesSourceClassPropertyVisibility Visibility levels to use for parsed properties when {@see $rules}
152 10
     * source is a name of the class providing rules. For example: public and protected only, this means that the rest
153
     * (private ones) will be skipped. Defaults to all visibility levels (public, protected and private). See
154 10
     * {@see ObjectDataSet} for details on providing rules via class and {@see ObjectParser} for overview how parsing
155
     * works.
156
     * @psalm-param int-mask-of<ReflectionProperty::IS_*> $rulesSourceClassPropertyVisibility
157
     *
158
     * @param string $noRulesWithNoObjectMessage Error message used when validation fails because the validated value is
159
     * not an object and the rules were not explicitly specified via {@see $rules}:
160 26
     *
161
     * You may use the following placeholders in the message:
162 26
     *
163 16
     * - `{attribute}`: the translated label of the attribute being validated.
164
     * - `{type}`: the type of the value being validated.
165 16
     * @param string $incorrectDataSetTypeMessage Error message used when validation fails because the validated value
166
     * is an object providing wrong type of data (neither array nor an object).
167
     *
168 10
     * You may use the following placeholders in the message:
169 1
     *
170 9
     * - `{type}`: the type of the data set retrieved from the validated object.
171 4
     * @param string $incorrectInputMessage Error message used when validation fails because the validated value is
172
     * neither an array nor an object.
173 5
     *
174
     * You may use the following placeholders in the message:
175
     *
176 10
     * - `{attribute}`: the translated label of the attribute being validated.
177 8
     * - `{type}`: the type of the value being validated.
178
     * @param bool $requirePropertyPath Whether to require a single data item to be passed in data according to declared
179 8
     * nesting level structure (all keys in the sequence must be the present). Used only when validated value is an
180 8
     * array. Enabled by default. See {@see $noPropertyPathMessage} for customization of error message.
181
     * @param string $noPropertyPathMessage Error message used when validation fails because {@see $requirePropertyPath}
182
     * option was enabled and the validated array contains missing data item.
183 7
     *
184 1
     * You may use the following placeholders in the message:
185
     *
186
     * - `{path}`: the path of the value being validated. Can be either a simple key of integer / string type for a
187
     * single nesting level or a sequence of keys concatenated using dot notation (see {@see SEPARATOR}).
188
     * - `{attribute}`: the translated label of the attribute being validated.
189
     * @param bool $handleEachShortcut Whether to handle {@see EACH_SHORTCUT}. Enabled by default meaning shortcuts are
190
     * supported. Can be disabled if they are not used to prevent additional checks and improve performance.
191 10
     * @param bool $propagateOptions Whether the propagation of options is enabled (see
192
     * {@see PropagateOptionsHelper::propagate()} for supported options and requirements). Disabled by default.
193 10
     * @param bool|callable|null $skipOnEmpty Whether to skip this `Nested` rule with all defined {@see $rules} if the
194
     * validated value is empty / not passed. See {@see SkipOnEmptyInterface}.
195 10
     * @param bool $skipOnError Whether to skip this `Nested` rule with all defined {@see $rules} if any of the previous
196 9
     * rules gave an error. See {@see SkipOnErrorInterface}.
197 7
     * @param Closure|null $when  A callable to define a condition for applying this `Nested` rule with all defined
198 9
     * {@see $rules}. See {@see WhenInterface}.
199 2
     * @psalm-param WhenType $when
200
     */
201
    public function __construct(
202 2
        iterable|object|string|null $rules = null,
203
        private int $validatedObjectPropertyVisibility = ReflectionProperty::IS_PRIVATE
204
        | ReflectionProperty::IS_PROTECTED
205 2
        | ReflectionProperty::IS_PUBLIC,
206
        private int $rulesSourceClassPropertyVisibility = ReflectionProperty::IS_PRIVATE
207
        | ReflectionProperty::IS_PROTECTED
208
        | ReflectionProperty::IS_PUBLIC,
209
        private string $noRulesWithNoObjectMessage = 'Nested rule without rules can be used for objects only.',
210 8
        private string $incorrectDataSetTypeMessage = 'An object data set data can only have an array type.',
211
        private string $incorrectInputMessage = 'The value must be an array or an object.',
212
        private bool $requirePropertyPath = false,
213 8
        private string $noPropertyPathMessage = 'Property "{path}" is not found.',
214 8
        private bool $handleEachShortcut = true,
215 8
        private bool $propagateOptions = false,
216 8
        private mixed $skipOnEmpty = null,
217
        private bool $skipOnError = false,
218 8
        private Closure|null $when = null,
219 7
    ) {
220 1
        $this->prepareRules($rules);
221
    }
222
223 6
    public function getName(): string
224
    {
225
        return 'nested';
226
    }
227
228 6
    /**
229 6
     * Gets a set of rules for running the validation.
230
     *
231
     * @return array|null A set of rules. `null` means the rules are expected to be provided with a validated value.
232
     * @psalm-return ReadyRulesType
233
     */
234
    public function getRules(): array|null
235
    {
236
        return $this->rules;
237
    }
238
239
    /**
240
     * Gets visibility levels to use for parsed properties when validated value is an object providing rules / data.
241
     * Defaults to all visibility levels (public, protected and private)
242
     *
243
     * @return int A number representing visibility levels.
244
     * @psalm-return int-mask-of<ReflectionProperty::IS_*>
245
     *
246
     * @see $validatedObjectPropertyVisibility
247
     */
248
    public function getValidatedObjectPropertyVisibility(): int
249
    {
250
        return $this->validatedObjectPropertyVisibility;
251
    }
252
253
    /**
254
     * Gets error message used when validation fails because the validated value is not an object and the rules were not
255
     * explicitly specified via {@see $rules}.
256 7
     *
257
     * @return string Error message / template.
258
     *
259
     * @see $incorrectInputMessage
260
     */
261
    public function getNoRulesWithNoObjectMessage(): string
262
    {
263
        return $this->noRulesWithNoObjectMessage;
264
    }
265
266
    /**
267 7
     * Gets error message used when validation fails because the validated value is an object providing wrong type of
268 7
     * data (neither array nor an object).
269
     *
270
     * @return string Error message / template.
271
     *
272 7
     * @see $incorrectDataSetTypeMessage
273
     */
274
    public function getIncorrectDataSetTypeMessage(): string
275 1
    {
276
        return $this->incorrectDataSetTypeMessage;
277 1
    }
278
279
    /**
280
     * Gets error message used when validation fails because the validated value is neither an array nor an object.
281
     *
282
     * @return string Error message / template.
283
     *
284
     * @see $incorrectInputMessage
285
     */
286 1
    public function getIncorrectInputMessage(): string
287 1
    {
288 1
        return $this->incorrectInputMessage;
289 1
    }
290
291 1
    /**
292 1
     * Whether to require a single data item to be passed in data according to declared nesting level structure (all
293
     * keys in the sequence must be the present). Enabled by default.
294 1
     *
295 1
     * @return bool `true` if required and `false` otherwise.
296
     *
297
     * @see $requirePropertyPath
298 1
     */
299
    public function isPropertyPathRequired(): bool
300 1
    {
301 1
        return $this->requirePropertyPath;
302
    }
303
304
    /**
305
     * Gets error message used when validation fails because {@see $requirePropertyPath} option was enabled and the
306 1
     * validated array contains missing data item.
307
     *
308
     * @return string Error message / template.
309 5
     *
310
     * @see $getNoPropertyPathMessage
311
     */
312
    public function getNoPropertyPathMessage(): string
313
    {
314
        return $this->noPropertyPathMessage;
315
    }
316
317
    /**
318
     * Prepares raw rules passed in the constructor for usage in handler. As a result, {@see $rules} property will
319
     * contain ready to use rules.
320
     *
321
     * @param iterable|object|string|null $source Raw rules passed in the constructor.
322
     *
323 5
     * @throws InvalidArgumentException When rules' source has wrong type.
324
     * @throws InvalidArgumentException When source contains items that are not rules.
325
     */
326
    private function prepareRules(iterable|object|string|null $source): void
327 5
    {
328
        if ($source === null) {
329
            $this->rules = null;
330
            return;
331 5
        }
332
333
        if ($source instanceof RulesProviderInterface) {
334
            $rules = $source->getRules();
335 5
        } elseif (is_string($source) && class_exists($source)) {
336
            $rules = (new AttributesRulesProvider($source, $this->rulesSourceClassPropertyVisibility))->getRules();
337
        } elseif (is_iterable($source)) {
338 5
            $rules = $source;
339 5
        } else {
340 5
            throw new InvalidArgumentException(
341 5
                'The $rules argument passed to Nested rule can be either: a null, an object implementing ' .
342
                'RulesProviderInterface, a class string or an iterable.'
343
            );
344
        }
345 53
346
        self::ensureArrayHasRules($rules);
347 53
348
        if ($this->handleEachShortcut) {
349
            $this->handleEachShortcut($rules);
350
        }
351
352
        $preparedRules = [];
353
        $this->flattenKeys($rules, $preparedRules);
354
355
        $this->rules = $preparedRules;
356
357
        if ($this->propagateOptions) {
358
            $this->propagateOptions();
359
        }
360
    }
361
362
    /**
363
     * Recursively flattens plain keys to allow any nesting level. The keys in the result array are joined using
364
     * {@see SEPARATOR}.
365
     *
366
     * Example of input:
367
     *
368
     * ```php
369
     * [
370
     *     'key1' => [
371
     *         'key2' => [
372
     *             'key3 => [
373
     *                 // ...
374
     *             ],
375
     *         ],
376
     *     ],
377
     * ];
378
     * ```
379
     *
380
     * Example of output for default {@see SEPARATOR}:
381
     *
382
     * ```php
383
     * [
384
     *     'key1.key2.key3' => [
385
     *         // ...
386
     *     ],
387
     * ],
388
     * ```
389
     *
390
     * @param array $rawRules Raw rules array which keys need to be flattened.
391
     * @psalm-param RawRulesType $rawRules
392
     *
393
     * @param array $resultRules Result rules array with flattened keys passed by reference.
394
     * @psalm-param ReadyRulesType $resultRules
395
     *
396
     * @param string|null $baseValuePath Base value path string. Can be a single key or multiple keys joined with
397
     * {@see SEPARATOR}. `null` is used for the first call.
398
     */
399
    private function flattenKeys(array $rawRules, array &$resultRules, ?string $baseValuePath = null): void
400
    {
401
        foreach ($rawRules as $valuePath => $validationRules) {
402
            if (is_int($valuePath)) {
403
                $key = $baseValuePath;
404
            } else {
405
                $key = ($baseValuePath !== null ? $baseValuePath . self::SEPARATOR : '') . $valuePath;
406
            }
407
408
            if (is_array($validationRules)) {
409
                $this->flattenKeys($validationRules, $resultRules, $key);
410
                continue;
411
            }
412
413
            if ($key === null) {
414
                $resultRules[] = $validationRules;
415
            } else {
416
                /** @psalm-suppress UndefinedInterfaceMethod */
417
                $resultRules[$key][] = $validationRules;
418
            }
419
        }
420
    }
421
422
    /**
423
     * Recursively checks that every item of source iterable is a valid rule instance ({@see RuleInterface}). As a
424
     * result, all iterables will be converted to arrays at the end, while single rules will be kept as is.
425
     *
426
     * @param iterable $rules Source iterable that will be checked and converted to array (so it's passed by reference).
427
     *
428
     * @psalm-param-out RawRulesType $rules
429
     *
430
     * @throws InvalidArgumentException When iterable contains items that are not rules.
431
     *
432
     * @psalm-suppress ReferenceConstraintViolation
433
     */
434
    private static function ensureArrayHasRules(iterable &$rules): void
435
    {
436
        if ($rules instanceof Traversable) {
437
            $rules = iterator_to_array($rules);
438
        }
439
440
        /** @var mixed $rule */
441
        foreach ($rules as &$rule) {
442
            if (is_iterable($rule)) {
443
                self::ensureArrayHasRules($rule);
444
            } elseif (!$rule instanceof RuleInterface) {
445
                $message = sprintf(
446
                    'Every rule must be an instance of %s, %s given.',
447
                    RuleInterface::class,
448
                    get_debug_type($rule)
449
                );
450
451
                throw new InvalidArgumentException($message);
452
            }
453
        }
454
    }
455
456
    /**
457
     * Converts rules defined with {@see EACH_SHORTCUT} to separate `Nested` and `Each` rules.
458
     *
459
     * @oaram array $rules Rules array for replacing {@see EACH_SHORTCUT} passed by reference.
460
     * @psalm-param RawRulesType $rules
461
     */
462
    private function handleEachShortcut(array &$rules): void
463
    {
464
        while (true) {
465
            $breakWhile = true;
466
            $rulesMap = [];
467
468
            foreach ($rules as $valuePath => $rule) {
469
                if ($valuePath === self::EACH_SHORTCUT) {
470
                    throw new InvalidArgumentException('Bare shortcut is prohibited. Use "Each" rule instead.');
471
                }
472
473
                $parts = StringHelper::parsePath(
474
                    (string) $valuePath,
475
                    delimiter: self::EACH_SHORTCUT,
476
                    preserveDelimiterEscaping: true
477
                );
478
                if (count($parts) === 1) {
479
                    continue;
480
                }
481
482
                /**
483
                 * Might be a bug of XDebug, because these lines are covered by tests.
484
                 *
485
                 * @see NestedTest::dataWithOtherNestedAndEach() for test cases prefixed with "withShortcut".
486
                 */
487
                // @codeCoverageIgnoreStart
488
                $breakWhile = false;
489
490
                $lastValuePath = array_pop($parts);
491
                $lastValuePath = ltrim($lastValuePath, '.');
492
                $lastValuePath = str_replace('\\' . self::EACH_SHORTCUT, self::EACH_SHORTCUT, $lastValuePath);
493
494
                $remainingValuePath = implode(self::EACH_SHORTCUT, $parts);
495
                $remainingValuePath = rtrim($remainingValuePath, self::SEPARATOR);
496
497
                if (!isset($rulesMap[$remainingValuePath])) {
498
                    $rulesMap[$remainingValuePath] = [];
499
                }
500
501
                $rulesMap[$remainingValuePath][$lastValuePath] = $rule;
502
                unset($rules[$valuePath]);
503
                // @codeCoverageIgnoreEnd
504
            }
505
506
            foreach ($rulesMap as $valuePath => $nestedRules) {
507
                /**
508
                 * Might be a bug of XDebug, because this line is covered by tests.
509
                 *
510
                 * @see NestedTest::dataWithOtherNestedAndEach() for test cases prefixed with "withShortcut".
511
                 */
512
                // @codeCoverageIgnoreStart
513
                $rules[$valuePath] = new Each([new self($nestedRules, handleEachShortcut: false)]);
514
                // @codeCoverageIgnoreEnd
515
            }
516
517
            if ($breakWhile === true) {
518
                break;
519
            }
520
        }
521
    }
522
523
    public function propagateOptions(): void
524
    {
525
        if ($this->rules === null) {
526
            return;
527
        }
528
529
        $rules = [];
530
        foreach ($this->rules as $attributeRulesIndex => $attributeRules) {
531
            $rules[$attributeRulesIndex] = is_iterable($attributeRules)
532
                ? PropagateOptionsHelper::propagate($this, $attributeRules)
533
                : PropagateOptionsHelper::propagateToRule($this, $attributeRules);
534
        }
535
536
        $this->rules = $rules;
0 ignored issues
show
Documentation Bug introduced by
It seems like $rules of type array or array is incompatible with the declared type Yiisoft\Validator\Rule\OptionalReadyRulesType of property $rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
537
    }
538
539
    public function afterInitAttribute(object $object, int $target): void
540
    {
541
        if ($this->rules === null) {
542
            return;
543
        }
544
545
        foreach ($this->rules as $rules) {
546
            if (is_array($rules)) {
547
                foreach ($rules as $rule) {
548
                    if ($rule instanceof AfterInitAttributeEventInterface) {
549
                        $rule->afterInitAttribute($object, $target);
550
                    }
551
                }
552
            } else {
553
                if ($rules instanceof AfterInitAttributeEventInterface) {
554
                    $rules->afterInitAttribute($object, $target);
555
                }
556
            }
557
        }
558
    }
559
560
    #[ArrayShape([
561
        'requirePropertyPath' => 'bool',
562
        'noRulesWithNoObjectMessage' => 'array',
563
        'incorrectDataSetTypeMessage' => 'array',
564
        'incorrectInputMessage' => 'array',
565
        'noPropertyPathMessage' => 'array',
566
        'skipOnEmpty' => 'bool',
567
        'skipOnError' => 'bool',
568
        'rules' => 'array|null',
569
    ])]
570
    public function getOptions(): array
571
    {
572
        return [
573
            'noRulesWithNoObjectMessage' => [
574
                'template' => $this->noRulesWithNoObjectMessage,
575
                'parameters' => [],
576
            ],
577
            'incorrectDataSetTypeMessage' => [
578
                'template' => $this->incorrectDataSetTypeMessage,
579
                'parameters' => [],
580
            ],
581
            'incorrectInputMessage' => [
582
                'template' => $this->incorrectInputMessage,
583
                'parameters' => [],
584
            ],
585
            'noPropertyPathMessage' => [
586
                'template' => $this->getNoPropertyPathMessage(),
587
                'parameters' => [],
588
            ],
589
            'requirePropertyPath' => $this->isPropertyPathRequired(),
590
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
591
            'skipOnError' => $this->skipOnError,
592
            'rules' => $this->rules === null ? null : RulesDumper::asArray($this->rules),
593
        ];
594
    }
595
596
    public function getHandler(): string
597
    {
598
        return NestedHandler::class;
599
    }
600
}
601