laminas/laminas-validator
Validation component for PHP and Laminas applications. Provides a wide range of ready-to-use validators (strings, numbers, dates, files, and more), consistent error messages, and an extensible API to create custom validators and input filtering rules.
Installation:
composer require laminas/laminas-validator
For translated messages (optional but recommended for production):
composer require laminas/laminas-i18n-resources
Basic Usage:
use Laminas\Validator\EmailAddress;
$validator = new EmailAddress();
$isValid = $validator->isValid('user@example.com');
if (!$isValid) {
echo $validator->getMessages(); // Outputs error message
}
First Use Case: Validate a form input in a Laravel controller:
use Laminas\Validator\NotEmpty;
$validator = new NotEmpty();
$input = $request->input('username');
if (!$validator->isValid($input)) {
return back()->withErrors(['username' => $validator->getMessages()]);
}
laminas/laminas-i18n-resources for pre-translated messages.Single Validator:
$validator = new Laminas\Validator\Digits();
$validator->setMessage('Only numbers allowed', Laminas\Validator\Digits::NOT_DIGITS);
$isValid = $validator->isValid($input);
Validator Chaining:
use Laminas\Validator\ValidatorChain;
$chain = new ValidatorChain();
$chain->addValidator(new Laminas\Validator\NotEmpty());
$chain->addValidator(new Laminas\Validator\StringLength(['min' => 5, 'max' => 20]));
if (!$chain->isValid($input)) {
foreach ($chain->getMessages() as $message) {
// Handle each error
}
}
Custom Validator (Laravel Service Provider):
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind('custom.validator', function () {
return new \MyValid\Float(); // Your custom validator
});
}
Integration with Laravel Forms:
use Laminas\Validator\EmailAddress;
$validator = new EmailAddress();
$request->validate([
'email' => [$validator, 'required', 'email'],
]);
Form Request Validation:
Extend Illuminate\Foundation\Http\FormRequest and use Laminas validators:
public function rules()
{
return [
'username' => 'required|string|min:3',
'email' => ['required', new Laminas\Validator\EmailAddress()],
];
}
public function validateCustomAttribute($attribute, $value, $fail)
{
$validator = new Laminas\Validator\NotEmpty();
if (!$validator->isValid($value)) {
$fail($validator->getMessages());
}
}
API Validation:
Use Laminas validators in app/Http/Controllers/Controller.php:
public function store(Request $request)
{
$validator = new Laminas\Validator\ValidatorChain();
$validator->addValidator(new Laminas\Validator\NotEmpty(), true);
$validator->addValidator(new Laminas\Validator\StringLength(['max' => 100]));
if (!$validator->isValid($request->input('data'))) {
return response()->json(['errors' => $validator->getMessages()], 422);
}
}
Dynamic Validation:
$validator = new Laminas\Validator\Between(['min' => $min, 'max' => $max]);
$validator->setMessage('Value must be between %min% and %max%', Laminas\Validator\Between::NOT_BETWEEN);
Message Overrides:
Forgetting to specify the failure key when using setMessage() will override all messages for the validator:
// ❌ Overrides ALL messages
$validator->setMessage('Invalid input');
// ✅ Overrides only NOT_DIGITS
$validator->setMessage('Only numbers allowed', Laminas\Validator\Digits::NOT_DIGITS);
Case Sensitivity in Custom Validators:
Ensure isValid() returns false and calls error() for each failure case:
// ❌ Missing error() call
if (!is_numeric($value)) {
return false; // Forgets to log the error
}
Validator Chain Short-Circuiting:
By default, ValidatorChain stops validation on the first failure. Use setContinueOnError(true) to validate all rules:
$chain->setContinueOnError(true);
Translations Not Loading: If translations fail, verify:
laminas-i18n-resources package is installed.AbstractValidator:
AbstractValidator::setDefaultTranslator($translator);
Magic Parameters in Messages:
Undefined magic parameters (e.g., %min%) will throw errors. Always define them in messageVariables:
protected array $messageVariables = [
'min' => 'minimum',
'max' => 'maximum',
];
Inspect All Messages:
$validator->getMessageTemplates(); // See all possible error messages
$validator->getMessages(); // See current errors
Log Validator Output:
\Log::debug('Validation failed:', [
'value' => $validator->getValue(),
'messages' => $validator->getMessages(),
]);
Test Edge Cases:
"").null or undefined values.Custom Validators:
Extend AbstractValidator for reusable logic:
final class LaravelSpecificValidator extends AbstractValidator
{
public const ERR_LARAVEL_SPECIFIC = 'laravelSpecific';
protected array $messageTemplates = [
self::ERR_LARAVEL_SPECIFIC => 'Laravel-specific error: %value%',
];
public function isValid($value): bool
{
if ($value === 'laravel') {
$this->error(self::ERR_LARAVEL_SPECIFIC);
return false;
}
return true;
}
}
Override Default Translator: For multi-language apps, dynamically set the translator:
$translator = app('translator');
AbstractValidator::setDefaultTranslator($translator);
Message Length Truncation: Globally limit message lengths:
AbstractValidator::setMessageLength(100); // Truncate all messages to 100 chars
Validator Factories:
Create a factory for complex validators (e.g., in Laravel's AppServiceProvider):
$this->app->bind('complex.validator', function () {
$validator = new ValidatorChain();
$validator->addValidator(new EmailAddress());
$validator->addValidator(new StringLength(['max' => 255]));
return $validator;
});
Integration with Laravel Packages:
Use Laminas validators in packages like laravel-form or spatie/laravel-validation for extended functionality.
How can I help you explore Laravel packages today?