Skip to content
Merged
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
8 changes: 4 additions & 4 deletions docs/case-sensitiveness.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ case normalization before comparison.
For strings:

```php
v::call(strtolower(...), v::contains('cde'))->assert('ABCDEF');
v::after(strtolower(...), v::contains('cde'))->assert('ABCDEF');
// Validation passes successfully

v::call(strtolower(...), v::contains('xxx'))->assert('ABCDEF');
v::after(strtolower(...), v::contains('xxx'))->assert('ABCDEF');
// → "abcdef" must contain "xxx"
```

For arrays:

```php
v::call(
v::after(
static fn ($i) => array_map(strtolower(...), $i),
v::contains('abc')
)->assert(['ABC', 'DEF']);
// Validation passes successfully

v::call(
v::after(
static fn ($i) => array_map(strtolower(...), $i),
v::contains('xxx')
)->assert(['ABC', 'DEF']);
Expand Down
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 [Factory](validators/Factory.md), short-circuit on first failure with [Circuit](validators/Circuit.md), or transform input before validation with [After](validators/After.md).

## Customizing error messages

Expand Down
47 changes: 27 additions & 20 deletions docs/migrating-from-v2-to-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,31 +158,31 @@ These validators have been replaced by `DateTimeDiff`, which provides more flexi

##### `PrimeNumber`, `Fibonacci`, `PerfectSquare`

Combine `Callback` with a mathematical library of your choice:
Combine `Satisfies` with a mathematical library of your choice:

```diff
- v::primeNumber()->assert(7);
+ v::callback(static fn ($input) => \MathPHP\NumberTheory\Integer::isPrime($input))->assert(7);
+ v::satisfies(static fn ($input) => \MathPHP\NumberTheory\Integer::isPrime($input))->assert(7);
```

See: https://github.com/markrogoyski/math-php

##### `FilterVar`

Use `Callback` instead:
Use `Satisfies` instead:

```diff
- v::filterVar(FILTER_VALIDATE_INT)->assert(123);
+ v::callback(static fn($input) => filter_var($input, FILTER_VALIDATE_INT) !== false)->assert(123);
+ v::satisfies(static fn($input) => filter_var($input, FILTER_VALIDATE_INT) !== false)->assert(123);
```

##### `Uploaded`

Use `Callback` instead:
Use `Satisfies` instead:

```diff
- v::uploaded()->assert($fileName);
+ v::callback('is_uploaded_file')->assert($fileName);
+ v::satisfies('is_uploaded_file')->assert($fileName);
```

##### `VideoUrl`
Expand Down Expand Up @@ -295,19 +295,19 @@ v::each(v::alwaysValid())->isValid(new stdClass()); // false
+ v::intType()->assert($input);
```

##### Call does not handle errors anymore
##### `After` does not handle errors anymore

`Call` now does not handle PHP errors inside the callback you provided.
`After` (previously `Call`) now does not handle PHP errors inside the callback you provided.

```php
v::call('strtolower', v::equals('foo'))->assert(123); // Error bubbles out
v::after('strtolower', v::equals('foo'))->assert(123); // Error bubbles out
```

You can use anonymous functions to handle errors or perform type conversions
instead:

```php
v::call(static fn ($i) => strtolower((string) $i), v::equals('123'));
v::after(static fn ($i) => strtolower((string) $i), v::equals('123'));
```

##### `Contains`, `ContainsAny`, `In`, `EndsWith` and `StartsWith` strict by default.
Expand Down Expand Up @@ -359,13 +359,21 @@ composer require ramsey/uuid

| 2.x | 3.0 | Notes |
| ---------- | -------------------- | ----------------------------------------- |
| `Call` | `After` | Clearer intent |
| `Callback` | `Satisfies` | Clearer intent |
| `Min` | `GreaterThanOrEqual` | Clearer comparison semantics |
| `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` | `Factory` | Deferred validator creation |

```diff
- v::call('strtolower', v::equals('foo'))->assert($input);
+ v::after('strtolower', v::equals('foo'))->assert($input);

- v::callback('is_int')->assert($input);
+ v::satisfies('is_int')->assert($input);

- v::min(18)->assert($age);
+ v::greaterThanOrEqual(18)->assert($age);

Expand All @@ -381,11 +389,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 @@ -586,7 +593,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 |
| `Factory` | 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 @@ -645,7 +652,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::factory(
fn($input) => v::key(
'subdivisionCode',
v::subdivisionCode($input['countryCode'])
Expand Down Expand Up @@ -703,13 +710,13 @@ v::keyOptional('phone', v::phone())->assert(['phone' => '+1234567890']); // pass
v::keyOptional('phone', v::phone())->assert(['phone' => 'invalid']); // fails
```

#### Lazy
#### Factory

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

```php
// Validate that 'confirmation' matches 'password'
v::lazy(
v::factory(
fn($input) => v::key('confirmation', v::equals($input['password'] ?? null))
)->assert(['password' => 'secret', 'confirmation' => 'secret']); // passes
```
Expand Down
18 changes: 9 additions & 9 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**: [After][] - [CallableType][] - [Factory][] - [Satisfies][]

**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**: [After][] - [AllOf][] - [AnyOf][] - [Circuit][] - [Each][] - [Factory][] - [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 All @@ -51,12 +51,13 @@ In this page you will find a list of validators by their category.

**Structures**: [Attributes][] - [Key][] - [KeyExists][] - [KeyOptional][] - [KeySet][] - [Property][] - [PropertyExists][] - [PropertyOptional][]

**Transformations**: [All][] - [Call][] - [Each][] - [Length][] - [Max][] - [Min][] - [Size][]
**Transformations**: [After][] - [All][] - [Each][] - [Length][] - [Max][] - [Min][] - [Size][]

**Types**: [ArrayType][] - [ArrayVal][] - [BoolType][] - [BoolVal][] - [CallableType][] - [Countable][] - [FloatType][] - [FloatVal][] - [IntType][] - [IntVal][] - [IterableType][] - [IterableVal][] - [NullType][] - [NumericVal][] - [ObjectType][] - [ResourceType][] - [ScalarVal][] - [StringType][] - [StringVal][]

## Alphabetically

- [After][] - `v::after(str_split(...), v::arrayType()->lengthEquals(5))->assert('world');`
- [All][] - `v::all(v::dateTime())->assert($releaseDates);`
- [AllOf][] - `v::allOf(v::intVal(), v::positive())->assert(15);`
- [Alnum][] - `v::alnum(' ')->assert('foo 123');`
Expand All @@ -75,9 +76,7 @@ In this page you will find a list of validators by their category.
- [BoolType][] - `v::boolType()->assert(true);`
- [BoolVal][] - `v::boolVal()->assert('on');`
- [Bsn][] - `v::bsn()->assert('612890053');`
- [Call][] - `v::call(str_split(...), v::arrayType()->lengthEquals(5))->assert('world');`
- [CallableType][] - `v::callableType()->assert(function () {});`
- [Callback][] - `v::callback(fn (int $input): bool => $input % 5 === 0,)->assert(10);`
- [Charset][] - `v::charset('ASCII')->assert('sugar');`
- [Circuit][] - `v::circuit(v::intVal(), v::floatVal())->assert(15);`
- [Cnh][] - `v::cnh()->assert('02650306461');`
Expand Down Expand Up @@ -110,6 +109,7 @@ In this page you will find a list of validators by their category.
- [Exists][] - `v::exists()->assert(__FILE__);`
- [Extension][] - `v::extension('png')->assert('image.png');`
- [Factor][] - `v::factor(0)->assert(5);`
- [Factory][] - `v::factory(static fn($input) => v::boolVal())->assert(true);`
- [FalseVal][] - `v::falseVal()->assert(false);`
- [Falsy][] - `v::falsy()->assert('');`
- [File][] - `v::file()->assert(__FILE__);`
Expand Down Expand Up @@ -140,7 +140,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 @@ -185,6 +184,7 @@ In this page you will find a list of validators by their category.
- [Regex][] - `v::regex('/[a-z]/')->assert('a');`
- [ResourceType][] - `v::resourceType()->assert(fopen('/path/to/file.txt', 'r'));`
- [Roman][] - `v::roman()->assert('IV');`
- [Satisfies][] - `v::satisfies(fn (int $input): bool => $input % 5 === 0,)->assert(10);`
- [ScalarVal][] - `v::scalarVal()->assert(135.0);`
- [Size][] - `v::size('KB', v::greaterThan(1))->assert('/path/to/file');`
- [Slug][] - `v::slug()->assert('my-wordpress-title');`
Expand Down Expand Up @@ -213,6 +213,7 @@ In this page you will find a list of validators by their category.
- [Writable][] - `v::writable()->assert('/path/to/file');`
- [Xdigit][] - `v::xdigit()->assert('abc123');`

[After]: validators/After.md "Validates the input after applying a callable to it."
[All]: validators/All.md "Validates all items of the input against a given validator."
[AllOf]: validators/AllOf.md "Will validate if all inner validators validates."
[Alnum]: validators/Alnum.md "Validates whether the input is alphanumeric or not."
Expand All @@ -231,9 +232,7 @@ In this page you will find a list of validators by their category.
[BoolType]: validators/BoolType.md "Validates whether the type of the input is boolean."
[BoolVal]: validators/BoolVal.md "Validates if the input results in a boolean value:"
[Bsn]: validators/Bsn.md "Validates a Dutch citizen service number (BSN)."
[Call]: validators/Call.md "Validates the return of a callable for a given input."
[CallableType]: validators/CallableType.md "Validates whether the pseudo-type of the input is callable."
[Callback]: validators/Callback.md "Validates the input using the return of a given callable."
[Charset]: validators/Charset.md "Validates if a string is in a specific charset."
[Circuit]: validators/Circuit.md "Validates the input against a series of validators until the first fails."
[Cnh]: validators/Cnh.md "Validates a Brazilian driver's license."
Expand Down Expand Up @@ -266,6 +265,7 @@ In this page you will find a list of validators by their category.
[Exists]: validators/Exists.md "Validates files or directories."
[Extension]: validators/Extension.md "Validates if the file extension matches the expected one:"
[Factor]: validators/Factor.md "Validates if the input is a factor of the defined dividend."
[Factory]: validators/Factory.md "Validates the input using a validator that is created from a callback."
[FalseVal]: validators/FalseVal.md "Validates if a value is considered as `false`."
[Falsy]: validators/Falsy.md "Validates whether the given input is considered empty or falsy, similar to PHP's `empty()` function."
[File]: validators/File.md "Validates whether file input is as a regular filename."
Expand Down Expand Up @@ -296,7 +296,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 Expand Up @@ -341,6 +340,7 @@ In this page you will find a list of validators by their category.
[Regex]: validators/Regex.md "Validates whether the input matches a defined regular expression."
[ResourceType]: validators/ResourceType.md "Validates whether the input is a resource."
[Roman]: validators/Roman.md "Validates if the input is a Roman numeral."
[Satisfies]: validators/Satisfies.md "Validates the input using the return of a given callable."
[ScalarVal]: validators/ScalarVal.md "Validates whether the input is a scalar value or not."
[Size]: validators/Size.md "Validates whether the input is a file that is of a certain size or not."
[Slug]: validators/Slug.md "Validates whether the input is a valid slug."
Expand Down
33 changes: 17 additions & 16 deletions docs/validators/Call.md → docs/validators/After.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
-->

# Call
# After

- `Call(callable $callable, Validator $validator)`
- `After(callable $callable, Validator $validator)`

Validates the return of a [callable][] for a given input.
Validates the input after applying a [callable][] to it.

```php
v::call(str_split(...), v::arrayType()->lengthEquals(5))->assert('world');
v::after(str_split(...), v::arrayType()->lengthEquals(5))->assert('world');
// Validation passes successfully
```

Expand Down Expand Up @@ -41,7 +41,7 @@ v::arrayVal()
Using `v::call()` you can do this in a single chain:

```php
v::call(
v::after(
'parse_url',
v::arrayVal()
->key('scheme', v::startsWith('http'))
Expand All @@ -52,18 +52,18 @@ v::call(
// Validation passes successfully
```

Call does not handle possible errors (type mismatches). If you need to
ensure that your callback is of a certain type, use [Circuit](Circuit.md) or
`After` does not handle possible errors (type mismatches). If you need to
ensure that your callback is of a certain type, use [Circuit](Circuit.md) or
handle it using a closure:

```php
v::call('strtolower', v::equals('ABC'))->assert(123);
v::after('strtolower', v::equals('ABC'))->assert(123);
// 𝙭 strtolower(): Argument #1 ($string) must be of type string, int given

v::circuit(v::stringType(), v::call('strtolower', v::equals('abc')))->assert(123);
v::circuit(v::stringType(), v::after('strtolower', v::equals('abc')))->assert(123);
// → 123 must be a string

v::circuit(v::stringType(), v::call('strtolower', v::equals('abc')))->assert('ABC');
v::circuit(v::stringType(), v::after('strtolower', v::equals('abc')))->assert('ABC');
// Validation passes successfully
```

Expand All @@ -75,14 +75,15 @@ v::circuit(v::stringType(), v::call('strtolower', v::equals('abc')))->assert('AB

## Changelog

| Version | Description |
| ------: | :---------------------------- |
| 3.0.0 | No longer sets error handlers |
| 0.3.9 | Created |
| Version | Description |
| ------: | :------------------------------------------------------- |
| 3.0.0 | No longer sets error handlers and got renamed to `After` |
| 2.0.0 | Sets error handlers |
| 0.3.9 | Created as `Call` |

## See Also

- [Callback](Callback.md)
- [Each](Each.md)
- [Lazy](Lazy.md)
- [Factory](Factory.md)
- [Satisfies](Satisfies.md)
- [Sorted](Sorted.md)
4 changes: 2 additions & 2 deletions docs/validators/CallableType.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ v::callableType()->assert([new DateTime(), 'format']);
- [ArrayType](ArrayType.md)
- [BoolType](BoolType.md)
- [BoolVal](BoolVal.md)
- [Callback](Callback.md)
- [Factory](Factory.md)
- [FloatType](FloatType.md)
- [IntType](IntType.md)
- [Lazy](Lazy.md)
- [NullType](NullType.md)
- [Number](Number.md)
- [ObjectType](ObjectType.md)
- [ResourceType](ResourceType.md)
- [Satisfies](Satisfies.md)
- [StringType](StringType.md)
- [StringVal](StringVal.md)
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 [Factory](Factory.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::factory(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)
- [Factory](Factory.md)
- [NoneOf](NoneOf.md)
- [OneOf](OneOf.md)
- [SubdivisionCode](SubdivisionCode.md)
Expand Down
Loading