Skip to content

Advanced patterns

final class Item
{
public string $name = '';
}
final class Order
{
/** @var list<Item> */
public array $items = [];
}
ValidationRegistry::register(
Item::class,
static fn (RuleSet $rules): array => [
$rules->string('name')->min(2)->max(80),
]
);
ValidationRegistry::register(
Order::class,
static fn (RuleSet $rules): array => [
$rules->objectArray('items', Item::class)->min(1)->max(50),
]
);

Errors can be flattened to keys such as items.0.name.

Use ArrayValidator::each() when every item in a plain array has the same rule:

use Fynix\Rule;
$tags = Rule::arrayOf('tags')
->min(1)
->max(10)
->each(Rule::string('tag')->length(2, 30));
ValidationRegistry::register(
Registration::class,
static fn (RuleSet $rules): array => [
$rules->string('accountType')->in(['personal', 'business']),
$rules->string('companyName')
->optional()
->requiredIf('accountType', 'business'),
$rules->string('passwordConfirmation')->sameAs('password'),
$rules->string('nickname')->prohibitedIf('accountType', 'business'),
]
);

Available conditional methods are requiredIf(), requiredUnless(), prohibitedIf(), and prohibitedUnless(). Related-field methods are sameAs() and differentFrom().

use Fynix\Rule;
$status = Rule::string('status')
->in(['draft', 'published'])
->notIn(['archived']);
use Fynix\ValidationHandler;
$results = ValidationHandler::validateMany($firstUser, $secondUser);
$namedResults = ValidationHandler::validateManyAssoc([
'first' => $firstUser,
'second' => $secondUser,
]);

Implement ValidationListener when you need logging, metrics, or tracing around validation:

ValidationHandler::addListener($listener);
$errors = ValidationHandler::validate($order);
ValidationHandler::clearListeners();

Listeners receive the instance before validation and the resulting errors afterward.

Fynix tracks visited object instances while traversing nested DTOs. Self-referencing graphs therefore stop safely instead of recursing forever.