awurth/slim-validation
A validation package for Slim that provides a validator service and middleware, built on Respect/Validation. Define rules for request data, collect error messages, and keep controllers clean.
composer require <vendor>/<package>:^5.1. v5.1.0 widens the Symfony constraint to allow Symfony 8, so on Laravel 11/12 you can stay on Symfony 7 without any change — the upgrade only matters if something else in your dependency tree is pulling Symfony 8 components.Validator service (the entry point you'll inject), AsserterInterface (the extension point for custom assertions), and the two result types — ValidatedValueCollection (happy path) and ValidationFailureCollection (error path).Validator from the container rather than constructing it. Laravel's package discovery registers the service provider; if you need a custom asserter, bind AsserterInterface in your own provider so Validator picks it up.ValidatedValueCollection values into your DTO, convert ValidationFailureCollection into a 422. Since v5.1.0, route arguments are read from the PSR-7 request — so {id} from /users/{id} is available to rules without you manually merging it into the payload.rules option. Misconfiguration now surfaces as InvalidPropertyOptionsException at that point instead of a Symfony InvalidOptionsException, which is a much clearer signal in CI.Inject, don't instantiate. Constructor-inject Validator into form requests, actions, or a small ValidationService wrapper. Keep the PSR-7 conversion in one place (a middleware or a request macro) so the rest of the app never touches the bridge.
Route arguments come for free now. If you previously did $payload + $request->route()->parameters() before validating, delete that. Pass the PSR-7 request (with route attributes populated) and let the validator read them. Verify your Laravel→PSR-7 adapter actually copies route parameters into request attributes — that's the one link the package can't fix for you.
Collections are plain appendable containers. As of v5.1.0, $collection[] = $value appends instead of throwing. Use it for building validated DTO lists or aggregating failures from multiple sub-validations:
$failures = new ValidationFailureCollection();
foreach ($rows as $row) {
$result = $validator->validate($row);
foreach ($result->failures() as $failure) {
$failures[] = $failure; // append, no key juggling
}
}
Don't mix [] and explicit keys unless you actually want keyed semantics — later appends will not renumber existing keys.
Translate failures at the boundary. Keep the package's exception/collection vocabulary out of your controllers. One adapter that maps ValidationFailureCollection → Laravel ValidationException (with ->errors() shaped for Inertia/JSON) pays for itself immediately.
Custom asserters: fix the signature once. Validator no longer passes a third argument to AsserterInterface::assert(). If you implemented the interface with a required third parameter, it's now a hard break; make it optional or drop it. This is the only change in the release likely to touch your code.
Lean on the new PHPDoc. v5.1.0 adds array shapes and value types to the interface docblocks. If you run Larastan/PHPStan, bump the package and re-run — you'll likely get better inference on collection generics for free, and you may need to delete a few @var suppressions you'd added to work around the old untyped signatures.
Register rules centrally. Keep rule definitions in config or in an enum/constant class rather than inline arrays scattered per call site. The rules option is validated at construction, so a single well-formed definition is your best defence against InvalidPropertyOptionsException in production.
Symfony\Component\OptionsResolver\Exception\InvalidOptionsException around validator construction will now miss. During the transition, catch both — or better, catch InvalidPropertyOptionsException explicitly and let genuine Symfony options errors (from other packages) propagate.InvalidPropertyOptionsException is a programmer error, not a user error. Don't return it as a 422. Let it bubble as a 500 in production and assert on it in tests; it means your rules config is malformed, and you want to hear about it loudly.[] behaviour. If you had code that intentionally used $collection[] = $x to detect duplicates or invalid state, that guard is gone in 5.1.0. Re-add an explicit check if that was load-bearing.composer why symfony/options-resolver (and friends) before bumping. Widened constraints let Composer pick Symfony 8 if another dependency allows it; on a Laravel app that can produce a mixed Symfony 7/8 tree that resolves but behaves oddly.assert()'s third argument is now a no-op. Code that passed context through it silently loses that context. If you were relying on it for error messages, move that data into the failure objects your asserter produces.AsserterInterface implementations for domain-specific assertions, and the rules option for declarative config. Cache/compile rule definitions in production if construction is non-trivial, and add a php artisan warm-up command that instantiates the validator so misconfiguration fails at deploy time rather than on the first request.How can I help you explore Laravel packages today?