@@ -71,8 +71,6 @@ final class User
7171}
7272```
7373
74- > ** Note:** [ readonly properties] are supported only starting from PHP 8.1.
75-
7674Error messages may include ` {property} ` placeholder that is replaced with the name of the property. To capitalize the
7775first letter, you can use the ` {Property} ` placeholder. If you would like the name to be replaced with a custom value,
7876you can specify it using the ` Label ` attribute:
@@ -91,8 +89,6 @@ final class User
9189}
9290```
9391
94- > ** Note:** [ readonly properties] are supported only starting from PHP 8.1.
95-
9692## Configuring for multiple entities / models with relations
9793
9894An example of rule set for a blog post configured via arrays only:
@@ -150,7 +146,6 @@ final class Post
150146 #[Nested]
151147 public Author|null $author = null;
152148
153- // Passing instances is available only since PHP 8.1.
154149 #[Each(new Nested(File::class))]
155150 public array $files = [];
156151
@@ -330,15 +325,9 @@ final class Yaml implements RuleInterface
330325
331326## Limitations and workarounds
332327
333- ### Instances
334-
335- Passing instances in the scope of attributes is only possible as of PHP 8.1. This means using attributes for complex
336- rules such as ` Composite ` , ` Each ` and ` Nested ` or rules that take instances as arguments, can be problematic with PHP 8.0.
337-
338- The first workaround is to upgrade to PHP 8.1 - this is fairly simple since it is a minor version. Tools like
339- [ Rector] can ease the process of upgrading the code base by automating routine tasks.
328+ ### Alternative approaches for complex rules
340329
341- If this is not an option, you can use other ways of providing rules, such as rule providers :
330+ For complex rules involving relations ( ` Nested ` , ` Each ` ), you can use rule providers as an alternative to attributes :
342331
343332``` php
344333use Yiisoft\Validator\Rule\Integer;
@@ -452,6 +441,15 @@ method for validation - use a `Callback` rule with [method reference]. Otherwise
452441- Use ` Composite ` or rules provider described in the [ Instances] section.
453442- Create a [ custom rule] .
454443
444+ ## Combining attributes with ` RulesProviderInterface `
445+
446+ When a data object has rules declared via PHP attributes and also implements ` RulesProviderInterface ` , rules from both
447+ sources are merged. Rules from PHP attributes are applied first, followed by rules from ` getRules() ` . If the same
448+ property has rules in both sources, they are combined.
449+
450+ > ** Note:** This merging only applies when the object is passed as the data (first argument of ` validate() ` ). When
451+ > passed as the rules argument (second argument), only ` getRules() ` is used — see [ Using validator] for details.
452+
455453## Using rules
456454
457455Well, the rules are configured. What's next? We can either:
@@ -565,7 +563,7 @@ $dataSet = new ObjectDataSet(
565563$result = (new Validator())->validate($dataSet);
566564```
567565
568- Some edge cases, like skipping DTO's static properties, require using of ` AttributeRulesProvider ` . After initializing it
566+ Some edge cases, like skipping DTO's static properties, require using of ` AttributesRulesProvider ` . After initializing it
569567can be passed for validation right away - no need to extract rules manually beforehand.
570568
571569``` php
@@ -625,6 +623,7 @@ $options = RulesDumper::asArray($rules);
625623[ Rector ] : https://github.com/rectorphp/rector
626624[ when ] : conditional-validation.md#when
627625[ conditional validation ] : conditional-validation.md
628- [ Instances ] : #instances
626+ [ Instances ] : #alternative-approaches-for-complex-rules
627+ [ Using validator ] : using-validator.md
629628[ custom rule ] : creating-custom-rules.md
630629[ method reference ] : built-in-rules-callback.md#for-property
0 commit comments