@@ -46,11 +46,15 @@ Library could be used in two ways: validating a single value and validating a se
4646### Validating a single value
4747
4848``` php
49+ use Yiisoft\Validator\ValidatorInterface;
4950use Yiisoft\Validator\RuleSet;
5051use Yiisoft\Validator\Rule\Required;
5152use Yiisoft\Validator\Rule\Number;
5253use Yiisoft\Validator\Result;
5354
55+ // Usually obtained from container
56+ $validator = $container->get(ValidatorInterface::class);
57+
5458$rules = [
5559 new Required(),
5660 new Number(min: 10),
@@ -65,7 +69,6 @@ $rules = [
6569 return $result;
6670 }
6771];
68- $validator = getValidator(); // Usually obtained from container
6972
7073$result = $validator->validate(41, $rules);
7174if (!$result->isValid()) {
@@ -80,6 +83,7 @@ if (!$result->isValid()) {
8083``` php
8184use Yiisoft\Validator\DataSetInterface;
8285use Yiisoft\Validator\Validator;
86+ use Yiisoft\Validator\ValidatorInterface;
8387use Yiisoft\Validator\Rule\Number;
8488use Yiisoft\Validator\Result;
8589
@@ -100,7 +104,9 @@ final class MoneyTransfer implements DataSetInterface
100104 }
101105}
102106
103- $validator = getValidator(); // Usually obtained from container
107+ // Usually obtained from container
108+ $validator = $container->get(ValidatorInterface::class);
109+
104110$moneyTransfer = new MoneyTransfer(142);
105111$rules = [
106112 'amount' => [
@@ -152,12 +158,15 @@ In many cases there is a need to validate related data in addition to current en
152158for this purpose:
153159
154160``` php
161+ use Yiisoft\Validator\ValidatorInterface;
155162use Yiisoft\Validator\Rule\HasLength;
156163use Yiisoft\Validator\Rule\Nested;
157164use Yiisoft\Validator\Rule\Number;
158165use Yiisoft\Validator\Rule\Required;
159166
160- $validator = getValidator(); // Usually obtained from container
167+ // Usually obtained from container
168+ $validator = $container->get(ValidatorInterface::class);
169+
161170$data = ['author' => ['name' => 'Alexey', 'age' => '31']];
162171$rule = new Nested([
163172 'title' => [new Required()],
@@ -210,12 +219,15 @@ A more complex real-life example is a chart that is made of points. This data is
210219combined with ` Each ` rule to validate such similar structures:
211220
212221``` php
222+ use Yiisoft\Validator\ValidatorInterface;
213223use Yiisoft\Validator\Rule\Count;
214224use Yiisoft\Validator\Rule\Each;
215225use Yiisoft\Validator\Rule\Nested;
216226use Yiisoft\Validator\RuleSet;
217227
218- $validator = getValidator(); // Usually obtained from container
228+ // Usually obtained from container
229+ $validator = $container->get(ValidatorInterface::class);
230+
219231$data = [
220232 'charts' => [
221233 [
@@ -274,31 +286,33 @@ $errors = [
274286
275287##### Basic usage
276288
277- You can also use attributes as an alternative. Declare the DTOs, relations and rules:
289+ Common flow is the same as you would use usual classes:
290+ 1 . Declare property
291+ 2 . Add rules to it
278292
279293``` php
280- use Yiisoft\Validator\Attribute\HasMany;
281- use Yiisoft\Validator\Attribute\HasOne;
294+ use Yiisoft\Validator\Attribute\Embedded;
295+ use Yiisoft\Validator\Rule\Count;
296+ use Yiisoft\Validator\Rule\Each;
282297use Yiisoft\Validator\Rule\Number;
283298
284- final class ChartsData
285- {
286- #[HasMany(Chart::class)]
287- private array $charts;
288- }
289-
290299final class Chart
291300{
292- #[HasMany(Point::class)]
301+ #[Each([
302+ new Embedded(Point::class),
303+ ])]
293304 private array $points;
294305}
295306
296307final class Point
297308{
298- #[HasOne (Coordinates::class)]
309+ #[Embedded (Coordinates::class)]
299310 private $coordinates;
300- #[Number(min: 0, max: 255)]
301- private array $rgb; // A flat array, the "Number" rule will be applied to each array element.
311+ #[Count(exactly: 3)]
312+ #[Each([
313+ new Number(min: 0, max: 255),
314+ ])]
315+ private array $rgb;
302316}
303317
304318final class Coordinates
@@ -310,44 +324,25 @@ final class Coordinates
310324}
311325```
312326
313- To combine both flat rules and "each" rules, specify ` Each ` explicitly and place flat rules above "each" ones:
314-
315- ``` php
316- use Yiisoft\Validator\Rule\Count;
317- use Yiisoft\Validator\Rule\Each;
318- use Yiisoft\Validator\Attribute\HasMany;
319- use Yiisoft\Validator\Attribute\HasOne;
320- use Yiisoft\Validator\Rule\Number;
321-
322- final class Point
323- {
324- #[HasOne(Coordinates::class)]
325- private $coordinates;
326- #[Count(exactly: 3)]
327- #[Each()]
328- #[Number(min: 0, max: 255)]
329- private array $rgb;
330- }
331- ```
332-
333- In this example ` Count ` will be applied to the whole value and ` Number ` - for each item.
334-
335327Here are some technical details:
336328
337- - ` HasOne ` uses ` Nested ` rule.
338- - ` HasMany ` uses combination of ` Each ` and ` Nested ` rules .
339- - In case of a flat array ` Point::$rgb ` , a property type ` array ` needs to be declared. It uses ` Each ` rule internally.
329+ - ` Embedded ` creates a reference to the referenced class and uses a ` GroupRule ` under the hood to make represent
330+ referenced class rules as it owns .
331+ - In case of a flat array ` Point::$rgb ` , a property type ` array ` needs to be declared.
340332
341333Pass the base DTO to ` AttributeDataSet ` and use it for validation.
342334
343335``` php
344336use Yiisoft\Validator\DataSet\AttributeDataSet;
337+ use Yiisoft\Validator\ValidatorInterface;
338+
339+ // Usually obtained from container
340+ $validator = $container->get(ValidatorInterface::class);
345341
346342$data = [
347343 // ...
348344];
349345$dataSet = new AttributeDataSet(new ChartsData(), $data);
350- $validator = getValidator(); // Usually obtained from container
351346$errors = $validator->validate($dataSet)->getErrorMessagesIndexedByPath();
352347```
353348
@@ -372,40 +367,6 @@ final class Post
372367
373368##### Limitations
374369
375- This approach has some limitations.
376-
377- ###### ` Each ` and ` Nested ` rules
378-
379- ` Each ` and ` Nested ` rules are not supported directly. Use ` HasOne ` and ` HasMany ` attributes for declaring relations (or
380- property type ` array ` for flat rules) instead. Use ` Each ` and ` Nested ` rules in addition for custom configuration if
381- needed.
382-
383- ``` php
384- use Yiisoft\Validator\Attribute\HasMany;
385- use Yiisoft\Validator\Attribute\HasOne;
386- use Yiisoft\Validator\Rule\Each;
387- use Yiisoft\Validator\Rule\Nested;
388- use Yiisoft\Validator\Rule\Number;
389-
390- final class ChartsData
391- {
392- #[Each(incorrectInputMessage: 'Custom message 1.', message: 'Custom message 2.')]
393- #[Nested(errorWhenPropertyPathIsNotFound: true, propertyPathIsNotFoundMessage: 'Custom message 3.')]
394- #[HasMany(Chart::class)]
395- private array $charts;
396- }
397-
398- final class Point
399- {
400- #[Nested(errorWhenPropertyPathIsNotFound: true, propertyPathIsNotFoundMessage: 'Custom message 4.')]
401- #[HasOne(Coordinates::class)]
402- private $coordinates;
403- #[Each(incorrectInputMessage: 'Custom message 5.', message: 'Custom message 6.')]
404- #[Number(min: 0, max: 255)]
405- private array $rgb;
406- }
407- ```
408-
409370###### ` Callback ` rule and ` callable ` type
410371
411372` Callback ` rule is not supported, also you can't use ` callable ` type with attributes. Use custom rule instead.
@@ -419,7 +380,7 @@ use Yiisoft\Validator\RuleHandlerInterface;
419380use \Yiisoft\Validator\RuleInterface;
420381use Yiisoft\Validator\ValidationContext;
421382
422- #[Attribute(Attribute::TARGET_PROPERTY)]
383+ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE )]
423384final class ValidateXRule implements RuleInterface
424385{
425386 public function __construct()
@@ -454,8 +415,7 @@ final class Coordinates
454415
455416###### ` GroupRule `
456417
457- ` GroupRule ` is not supported, but it's unnecessary since multiple attributes can be used for one property (except they
458- must be of different type).
418+ ` GroupRule ` is not supported, but it's unnecessary since multiple attributes can be used for one property.
459419
460420``` php
461421use Yiisoft\Validator\Rule\HasLength;
@@ -469,6 +429,63 @@ final class UserData
469429}
470430```
471431
432+ ###### Nested attributes
433+
434+ PHP 8.0 supports attributes, but nested declaration is allowed only in PHP 8.1 and above.
435+
436+ So such attributes as ` Each ` , ` Nested ` and ` Composite ` are not allowed in PHP 8.0.
437+
438+ The following example is not allowed in PHP 8.0:
439+
440+ ``` php
441+ use Yiisoft\Validator\Rule\Each;
442+ use Yiisoft\Validator\Rule\Number;
443+
444+ final class Color
445+ {
446+ #[Each([
447+ new Number(min: 0, max: 255),
448+ ])]
449+ private array $values;
450+ }
451+ ```
452+
453+ But you can do this by creating a new composite rule from it.
454+
455+ ``` php
456+ namespace App\Validator\Rule;
457+
458+ use Attribute;
459+ use Yiisoft\Validator\Rule\Each;
460+ use Yiisoft\Validator\Rule\GroupRule;
461+
462+ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
463+ final class RgbRule extends GroupRule
464+ {
465+ public function getRuleSet(): array
466+ {
467+ return [
468+ new Each([
469+ new Number(min: 0, max: 255),
470+ ]),
471+ ];
472+ }
473+ }
474+ ```
475+
476+ And use it after as attribute.
477+
478+ ``` php
479+ use App\Validator\Rule\RgbRule;
480+
481+ final class Color
482+ {
483+ #[RgbRule]
484+ private array $values;
485+ }
486+
487+ ```
488+
472489###### Function / method calls
473490
474491You can't use a function / method call result with attributes. Like with ` Callback ` rule and callable, this problem can
@@ -493,7 +510,7 @@ final class CustomFormatter implements FormatterInterface
493510 }
494511}
495512
496- #[Attribute(Attribute::TARGET_PROPERTY)]
513+ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE )]
497514final class ValidateXRule implements RuleInterface
498515{
499516 public function __construct(
@@ -758,9 +775,12 @@ Then it could be used like the following:
758775
759776``` php
760777use Yiisoft\Validator\Validator;
778+ use Yiisoft\Validator\ValidatorInterface;
761779use Yiisoft\Validator\Rule\Email;
762780
763- $validator = getValidator(); // Usually obtained from container
781+ // Usually obtained from container
782+ $validator = $container->get(ValidatorInterface::class);
783+
764784$rules = [
765785 'username' => new UsernameRule(),
766786 'email' => [new Email()],
0 commit comments