Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/feature-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Beyond the examples above, Respect\Validation provides specialized validators fo
- **Grouped validation**: Combine validators with AND/OR logic using [AllOf](validators/AllOf.md), [AnyOf](validators/AnyOf.md), [NoneOf](validators/NoneOf.md), [OneOf](validators/OneOf.md).
- **Iteration**: Validate every item in a collection with [Each](validators/Each.md).
- **Length, Min, Max**: Validate derived values with [Length](validators/Length.md), [Min](validators/Min.md), [Max](validators/Max.md).
- **Special cases**: Handle dynamic rules with [Lazy](validators/Lazy.md), short-circuit on first failure with [Circuit](validators/Circuit.md), or transform input before validation with [Call](validators/Call.md).
- **Special cases**: Handle dynamic rules with [Dynamic](validators/Dynamic.md), short-circuit on first failure with [Circuit](validators/Circuit.md), or transform input before validation with [Call](validators/Call.md).

## Customizing error messages

Expand Down
19 changes: 9 additions & 10 deletions docs/migrating-from-v2-to-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ composer require ramsey/uuid
| `Max` | `LessThanOrEqual` | Clearer comparison semantics |
| `Nullable` | `NullOr` | Consistent naming pattern |
| `Optional` | `UndefOr` | Validates if value is undefined or passes |
| `KeyValue` | `Lazy` | Deferred validator creation |
| `KeyValue` | `Dynamic` | Deferred validator creation |

```diff
- v::min(18)->assert($age);
Expand All @@ -373,11 +373,10 @@ composer require ramsey/uuid

In 3.0, `Min` and `Max` validators exist but have different semantics. They extract the minimum/maximum value from a collection and validate it (see [Result composition](#result-composition)).


| Validator | 2.x | 3.x |
| ---------- | --------------- | --------------------------------------------- |
| `Min` | Single value >= | Pick minimum value from iterable and validate |
| `Max` | Single value <= | Pick minimum value from iterable and validate |
| Validator | 2.x | 3.x |
| --------- | --------------- | --------------------------------------------- |
| `Min` | Single value >= | Pick minimum value from iterable and validate |
| `Max` | Single value <= | Pick minimum value from iterable and validate |

##### `NotBlank` logic inverted

Expand Down Expand Up @@ -579,7 +578,7 @@ Version 3.0 introduces several new validators:
| `Hetu` | Validates Finnish personal identity codes (henkilötunnus) |
| `KeyExists` | Checks if an array key exists |
| `KeyOptional` | Validates an array key only if it exists |
| `Lazy` | Creates validators dynamically based on input |
| `Dynamic` | Creates validators dynamically based on input |
| `Masked` | Masks sensitive input values in error messages |
| `Named` | Customizes the subject name in error messages |
| `PropertyExists` | Checks if an object property exists |
Expand Down Expand Up @@ -638,7 +637,7 @@ Validates input against a series of validators, stopping at the first failure. U
```php
$validator = v::circuit(
v::key('countryCode', v::countryCode()),
v::lazy(
v::dynamic(
fn($input) => v::key(
'subdivisionCode',
v::subdivisionCode($input['countryCode'])
Expand Down Expand Up @@ -696,13 +695,13 @@ v::keyOptional('phone', v::phone())->assert(['phone' => '+1234567890']); // pass
v::keyOptional('phone', v::phone())->assert(['phone' => 'invalid']); // fails
```

#### Lazy
#### Dynamic

Creates validators dynamically based on the input, useful for cross-field validation:

```php
// Validate that 'confirmation' matches 'password'
v::lazy(
v::dynamic(
fn($input) => v::key('confirmation', v::equals($input['password'] ?? null))
)->assert(['password' => 'secret', 'confirmation' => 'secret']); // passes
```
Expand Down
8 changes: 4 additions & 4 deletions docs/validators.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ In this page you will find a list of validators by their category.

**Booleans**: [AlwaysInvalid][] - [AlwaysValid][] - [BoolType][] - [BoolVal][] - [FalseVal][] - [TrueVal][]

**Callables**: [Call][] - [CallableType][] - [Callback][] - [Lazy][]
**Callables**: [Call][] - [CallableType][] - [Callback][] - [Dynamic][]

**Comparisons**: [All][] - [Between][] - [BetweenExclusive][] - [Equals][] - [Equivalent][] - [GreaterThan][] - [GreaterThanOrEqual][] - [Identical][] - [In][] - [Length][] - [LessThan][] - [LessThanOrEqual][] - [Max][] - [Min][]

Expand Down Expand Up @@ -41,7 +41,7 @@ In this page you will find a list of validators by their category.

**Miscellaneous**: [Blank][] - [Falsy][] - [Masked][] - [Named][] - [Templated][] - [Undef][]

**Nesting**: [AllOf][] - [AnyOf][] - [Call][] - [Circuit][] - [Each][] - [Key][] - [KeySet][] - [Lazy][] - [NoneOf][] - [Not][] - [NullOr][] - [OneOf][] - [Property][] - [PropertyOptional][] - [UndefOr][] - [When][]
**Nesting**: [AllOf][] - [AnyOf][] - [Call][] - [Circuit][] - [Dynamic][] - [Each][] - [Key][] - [KeySet][] - [NoneOf][] - [Not][] - [NullOr][] - [OneOf][] - [Property][] - [PropertyOptional][] - [UndefOr][] - [When][]

**Numbers**: [Base][] - [Decimal][] - [Digit][] - [Even][] - [Factor][] - [Finite][] - [FloatType][] - [FloatVal][] - [Infinite][] - [IntType][] - [IntVal][] - [Multiple][] - [Negative][] - [Number][] - [NumericVal][] - [Odd][] - [Positive][] - [Roman][]

Expand Down Expand Up @@ -99,6 +99,7 @@ In this page you will find a list of validators by their category.
- [Digit][] - `v::digit(' ')->assert('020 612 1851');`
- [Directory][] - `v::directory()->assert(__DIR__);`
- [Domain][] - `v::domain()->assert('google.com');`
- [Dynamic][] - `v::dynamic(static fn($input) => v::boolVal())->assert(true);`
- [Each][] - `v::each(v::dateTime())->assert($releaseDates);`
- [Email][] - `v::email()->assert('alganet@gmail.com');`
- [Emoji][] - `v::emoji()->assert('🍕');`
Expand Down Expand Up @@ -140,7 +141,6 @@ In this page you will find a list of validators by their category.
- [KeyOptional][] - `v::keyOptional('name', v::stringType())->assert([]);`
- [KeySet][] - `v::keySet(v::key('foo', v::intVal()))->assert(['foo' => 42]);`
- [LanguageCode][] - `v::languageCode()->assert('pt');`
- [Lazy][] - `v::lazy(static fn($input) => v::boolVal())->assert(true);`
- [LeapDate][] - `v::leapDate('Y-m-d')->assert('1988-02-29');`
- [LeapYear][] - `v::leapYear()->assert('1988');`
- [Length][] - `v::length(v::between(1, 5))->assert('abc');`
Expand Down Expand Up @@ -255,6 +255,7 @@ In this page you will find a list of validators by their category.
[Digit]: validators/Digit.md "Validates whether the input contains only digits."
[Directory]: validators/Directory.md "Validates if the given path is a directory."
[Domain]: validators/Domain.md "Validates whether the input is a valid domain name or not."
[Dynamic]: validators/Dynamic.md "Validates the input using a validator that is created from a callback."
[Each]: validators/Each.md "Validates whether each value in the input is valid according to another validator."
[Email]: validators/Email.md "Validates an email address."
[Emoji]: validators/Emoji.md "Validates if the input is an emoji or a sequence of emojis."
Expand Down Expand Up @@ -296,7 +297,6 @@ In this page you will find a list of validators by their category.
[KeyOptional]: validators/KeyOptional.md "Validates the value of an array against a given validator when the key exists."
[KeySet]: validators/KeySet.md "Validates a keys in a defined structure."
[LanguageCode]: validators/LanguageCode.md "Validates whether the input is language code based on ISO 639."
[Lazy]: validators/Lazy.md "Validates the input using a validator that is created from a callback."
[LeapDate]: validators/LeapDate.md "Validates if a date is leap."
[LeapYear]: validators/LeapYear.md "Validates if a year is leap."
[Length]: validators/Length.md "Validates the length of the given input against a given validator."
Expand Down
2 changes: 1 addition & 1 deletion docs/validators/Call.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ v::circuit(v::stringType(), v::call('strtolower', v::equals('abc')))->assert('AB
## See Also

- [Callback](Callback.md)
- [Dynamic](Dynamic.md)
- [Each](Each.md)
- [Lazy](Lazy.md)
- [Sorted](Sorted.md)
2 changes: 1 addition & 1 deletion docs/validators/CallableType.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ v::callableType()->assert([new DateTime(), 'format']);
- [BoolType](BoolType.md)
- [BoolVal](BoolVal.md)
- [Callback](Callback.md)
- [Dynamic](Dynamic.md)
- [FloatType](FloatType.md)
- [IntType](IntType.md)
- [Lazy](Lazy.md)
- [NullType](NullType.md)
- [Number](Number.md)
- [ObjectType](ObjectType.md)
Expand Down
6 changes: 3 additions & 3 deletions docs/validators/Circuit.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ v::circuit(v::intVal(), v::floatVal())->assert(15);

This validator can be handy for getting the least error messages possible from a chain.

This validator can be helpful in combinations with [Lazy](Lazy.md). An excellent example is when you want to validate a
This validator can be helpful in combinations with [Dynamic](Dynamic.md). An excellent example is when you want to validate a
country code and a subdivision code.

```php
$validator = v::circuit(
v::key('countryCode', v::countryCode()),
v::lazy(static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countryCode']))),
v::dynamic(static fn($input) => v::key('subdivisionCode', v::subdivisionCode($input['countryCode']))),
);

$validator->assert([]);
Expand Down Expand Up @@ -63,7 +63,7 @@ This validator does not have any templates, because it will always return the re

- [AllOf](AllOf.md)
- [AnyOf](AnyOf.md)
- [Lazy](Lazy.md)
- [Dynamic](Dynamic.md)
- [NoneOf](NoneOf.md)
- [OneOf](OneOf.md)
- [SubdivisionCode](SubdivisionCode.md)
Expand Down
10 changes: 5 additions & 5 deletions docs/validators/Lazy.md → docs/validators/Dynamic.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ SPDX-FileCopyrightText: (c) Respect Project Contributors
SPDX-License-Identifier: MIT
-->

# Lazy
# Dynamic

- `Lazy(callable(mixed): Validator $validatorCreator)`
- `Dynamic(callable(mixed): Validator $factory)`

Validates the input using a validator that is created from a callback.

```php
v::lazy(static fn($input) => v::boolVal())->assert(true);
v::dynamic(static fn($input) => v::boolVal())->assert(true);
// Validation passes successfully
```

Expand All @@ -25,10 +25,10 @@ v::key('confirmation', v::equals($_POST['password'] ?? null))->assert($_POST);
The issue with the code is that it’s hard to reuse because you’re relying upon the input itself (`$_POST`). That means
you can create a chain of validators and use it everywhere.

The `lazy()` validator makes this job much simpler and more elegantly:
The `dynamic()` validator makes this job much simpler and more elegantly:

```php
v::lazy(static fn($input) => v::key('confirmation', v::equals($input['password'] ?? null)))->assert($_POST);
v::dynamic(static fn($input) => v::key('confirmation', v::equals($input['password'] ?? null)))->assert($_POST);
// → `.confirmation` must be present
```

Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/AllBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public static function allDirectory(): Chain;

public static function allDomain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public static function allDynamic(callable $factory): Chain;

public static function allEach(Validator $validator): Chain;

public static function allEmail(): Chain;
Expand Down Expand Up @@ -174,9 +177,6 @@ public static function allJson(): Chain;
/** @param "alpha-2"|"alpha-3" $set */
public static function allLanguageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public static function allLazy(callable $validatorCreator): Chain;

public static function allLeapDate(string $format): Chain;

public static function allLeapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/AllChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public function allDirectory(): Chain;

public function allDomain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public function allDynamic(callable $factory): Chain;

public function allEach(Validator $validator): Chain;

public function allEmail(): Chain;
Expand Down Expand Up @@ -174,9 +177,6 @@ public function allJson(): Chain;
/** @param "alpha-2"|"alpha-3" $set */
public function allLanguageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public function allLazy(callable $validatorCreator): Chain;

public function allLeapDate(string $format): Chain;

public function allLeapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ public static function directory(): Chain;

public static function domain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public static function dynamic(callable $factory): Chain;

public static function each(Validator $validator): Chain;

public static function email(): Chain;
Expand Down Expand Up @@ -189,9 +192,6 @@ public static function keySet(Validator $validator, Validator ...$validators): C
/** @param "alpha-2"|"alpha-3" $set */
public static function languageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public static function lazy(callable $validatorCreator): Chain;

public static function leapDate(string $format): Chain;

public static function leapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/Chain.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public function directory(): Chain;

public function domain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public function dynamic(callable $factory): Chain;

public function each(Validator $validator): Chain;

public function email(): Chain;
Expand Down Expand Up @@ -191,9 +194,6 @@ public function keySet(Validator $validator, Validator ...$validators): Chain;
/** @param "alpha-2"|"alpha-3" $set */
public function languageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public function lazy(callable $validatorCreator): Chain;

public function leapDate(string $format): Chain;

public function leapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/KeyBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public static function keyDirectory(int|string $key): Chain;

public static function keyDomain(int|string $key, bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public static function keyDynamic(int|string $key, callable $factory): Chain;

public static function keyEach(int|string $key, Validator $validator): Chain;

public static function keyEmail(int|string $key): Chain;
Expand Down Expand Up @@ -176,9 +179,6 @@ public static function keyJson(int|string $key): Chain;
/** @param "alpha-2"|"alpha-3" $set */
public static function keyLanguageCode(int|string $key, string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public static function keyLazy(int|string $key, callable $validatorCreator): Chain;

public static function keyLeapDate(int|string $key, string $format): Chain;

public static function keyLeapYear(int|string $key): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/KeyChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public function keyDirectory(int|string $key): Chain;

public function keyDomain(int|string $key, bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public function keyDynamic(int|string $key, callable $factory): Chain;

public function keyEach(int|string $key, Validator $validator): Chain;

public function keyEmail(int|string $key): Chain;
Expand Down Expand Up @@ -176,9 +179,6 @@ public function keyJson(int|string $key): Chain;
/** @param "alpha-2"|"alpha-3" $set */
public function keyLanguageCode(int|string $key, string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public function keyLazy(int|string $key, callable $validatorCreator): Chain;

public function keyLeapDate(int|string $key, string $format): Chain;

public function keyLeapYear(int|string $key): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/NotBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public static function notDirectory(): Chain;

public static function notDomain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public static function notDynamic(callable $factory): Chain;

public static function notEach(Validator $validator): Chain;

public static function notEmail(): Chain;
Expand Down Expand Up @@ -186,9 +189,6 @@ public static function notKeySet(Validator $validator, Validator ...$validators)
/** @param "alpha-2"|"alpha-3" $set */
public static function notLanguageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public static function notLazy(callable $validatorCreator): Chain;

public static function notLeapDate(string $format): Chain;

public static function notLeapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/NotChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public function notDirectory(): Chain;

public function notDomain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public function notDynamic(callable $factory): Chain;

public function notEach(Validator $validator): Chain;

public function notEmail(): Chain;
Expand Down Expand Up @@ -186,9 +189,6 @@ public function notKeySet(Validator $validator, Validator ...$validators): Chain
/** @param "alpha-2"|"alpha-3" $set */
public function notLanguageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public function notLazy(callable $validatorCreator): Chain;

public function notLeapDate(string $format): Chain;

public function notLeapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/NullOrBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public static function nullOrDirectory(): Chain;

public static function nullOrDomain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public static function nullOrDynamic(callable $factory): Chain;

public static function nullOrEach(Validator $validator): Chain;

public static function nullOrEmail(): Chain;
Expand Down Expand Up @@ -186,9 +189,6 @@ public static function nullOrKeySet(Validator $validator, Validator ...$validato
/** @param "alpha-2"|"alpha-3" $set */
public static function nullOrLanguageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public static function nullOrLazy(callable $validatorCreator): Chain;

public static function nullOrLeapDate(string $format): Chain;

public static function nullOrLeapYear(): Chain;
Expand Down
6 changes: 3 additions & 3 deletions src/Mixins/NullOrChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ public function nullOrDirectory(): Chain;

public function nullOrDomain(bool $tldCheck = true): Chain;

/** @param callable(mixed): Validator $factory */
public function nullOrDynamic(callable $factory): Chain;

public function nullOrEach(Validator $validator): Chain;

public function nullOrEmail(): Chain;
Expand Down Expand Up @@ -186,9 +189,6 @@ public function nullOrKeySet(Validator $validator, Validator ...$validators): Ch
/** @param "alpha-2"|"alpha-3" $set */
public function nullOrLanguageCode(string $set = 'alpha-2'): Chain;

/** @param callable(mixed): Validator $validatorCreator */
public function nullOrLazy(callable $validatorCreator): Chain;

public function nullOrLeapDate(string $format): Chain;

public function nullOrLeapYear(): Chain;
Expand Down
Loading