Validation
The Validator class provides declarative input validation with support for common rules.
Namespace: VelvetCMS\Validation\Validator
Definition #
class Validator
{
public function __construct(array $data, array $rules);
public static function make(array $data, array $rules): self;
public function validate(): array;
public static function extend(string $rule, Closure $callback): void;
public static function hasExtension(string $rule): bool;
}
Basic Usage #
Creating a Validator #
use VelvetCMS\Validation\Validator;
$validator = Validator::make($data, [
'name' => 'required|min:2|max:100',
'email' => 'required|email',
'age' => 'integer|min:18',
]);
try {
$validated = $validator->validate();
// Use $validated data
} catch (ValidationException $e) {
$errors = $e->errors();
}
Request Validation #
The Request class provides a shorthand:
public function store(Request $request): Response
{
$data = $request->validate([
'title' => 'required|max:200',
'body' => 'required',
'status' => 'in:draft,published',
]);
// $data contains only validated fields
$this->service->create($data);
}
Available Rules #
required #
Field must be present and not empty.
'name' => 'required'
Empty values: null, '', []
min #
Minimum length for strings or minimum value for numeric types.
'password' => 'min:8' // At least 8 characters
'items' => 'array|min:1' // At least 1 item
max #
Maximum length for strings or count for arrays.
'title' => 'max:200' // Up to 200 characters
'tags' => 'array|max:5' // Up to 5 items
email #
Field must be a valid email address.
'email' => 'required|email'
url #
Field must be a valid URL.
'website' => 'url'
numeric #
Field must be numeric (int, float, or numeric string).
'price' => 'numeric'
integer #
Field must be an integer.
'quantity' => 'required|integer'
boolean #
Field must be a boolean value.
Accepted values: true, false, 0, 1, '0', '1', 'true', 'false'
'active' => 'boolean'
alpha #
Field must contain only letters.
'name' => 'alpha'
alphanumeric #
Field must contain only letters and numbers.
'username' => 'alphanumeric'
in #
Field must be one of the listed values.
'status' => 'in:draft,published,archived'
'role' => 'in:admin,editor,viewer'
regex #
Field must match the regular expression.
'slug' => 'regex:/^[a-z0-9-]+$/'
'phone' => 'regex:/^\+?[0-9]{10,15}$/'
same #
Field must match another field's value.
'password_confirmation' => 'same:password'
different #
Field must differ from another field's value.
'new_password' => 'different:current_password'
date #
Field must be a valid date string.
'published_at' => 'date'
array #
Field must be an array.
'items' => 'array'
'tags' => 'array|min:1|max:10'
Rule Syntax #
Pipe-separated rules #
'email' => 'required|email|max:255'
Array of rules #
'email' => ['required', 'email', 'max:255']
Rules with parameters #
Use : to pass parameters:
'status' => 'in:draft,published' // Comma-separated values
'min_age' => 'integer|min:18' // Single parameter
Error Handling #
ValidationException #
Thrown when validation fails:
try {
$data = $request->validate($rules);
} catch (ValidationException $e) {
$errors = $e->errors();
// [
// 'email' => ['The email must be a valid email address.'],
// 'name' => ['The name field is required.']
// ]
}
API Error Responses #
public function store(Request $request): Response
{
try {
$data = $request->validate([
'email' => 'required|email',
'name' => 'required|min:2',
]);
return Response::json(['data' => $this->create($data)], 201);
} catch (ValidationException $e) {
return Response::json([
'message' => 'Validation failed',
'errors' => $e->errors()
], 422);
}
}
Error Messages #
Default error messages by rule:
| Rule | Message |
|---|---|
| required | The {field} field is required. |
| min | The {field} must be at least {value} characters. |
| max | The {field} may not be greater than {value} characters. |
| The {field} must be a valid email address. | |
| url | The {field} must be a valid URL. |
| numeric | The {field} must be a number. |
| integer | The {field} must be an integer. |
| boolean | The {field} must be true or false. |
| alpha | The {field} may only contain letters. |
| alphanumeric | The {field} may only contain letters and numbers. |
| in | The selected {field} is invalid. |
| regex | The {field} format is invalid. |
| same | The {field} must match {other}. |
| different | The {field} must be different from {other}. |
| date | The {field} is not a valid date. |
| array | The {field} must be an array. |
Usage Examples #
User Registration #
$data = $request->validate([
'username' => 'required|alphanumeric|min:3|max:20',
'email' => 'required|email|max:255',
'password' => 'required|min:8|max:128',
'password_confirmation' => 'required|same:password',
'terms' => 'required|boolean',
]);
Blog Post #
$data = $request->validate([
'title' => 'required|max:200',
'slug' => 'required|regex:/^[a-z0-9-]+$/|max:200',
'body' => 'required',
'status' => 'required|in:draft,published,scheduled',
'published_at' => 'date',
'tags' => 'array|max:10',
]);
Contact Form #
$data = $request->validate([
'name' => 'required|min:2|max:100',
'email' => 'required|email',
'subject' => 'required|max:200',
'message' => 'required|min:10|max:5000',
]);
API Filters #
$filters = $request->validate([
'page' => 'integer|min:1',
'per_page' => 'integer|min:1|max:100',
'sort' => 'in:created_at,updated_at,title',
'order' => 'in:asc,desc',
'status' => 'in:all,published,draft',
]);
Optional Fields #
Fields without required rule are optional. Validation rules only apply when the field is present and not empty:
$data = $request->validate([
'name' => 'required|max:100', // Required
'nickname' => 'max:50', // Optional, validated if present
'bio' => 'max:1000', // Optional
]);
Custom Rule Extensions #
Register custom validation rules globally using Validator::extend().
extend() #
public static function extend(string $rule, Closure $callback): void
Parameters:
$rule- Rule name to register (used as'rulename'or'rulename:param')$callback-fn(mixed $value, ?string $parameter, array $data, string $field): bool|string
Callback return values:
true- Validation passedfalse- Validation failed (generic message)string- Validation failed with custom message
Example:
Validator::extend('slug', function ($value, $parameter, $data, $field) {
if (!preg_match('/^[a-z0-9-]+$/', $value)) {
return "The {$field} must be a valid slug.";
}
return true;
});
Validator::extend('unique_email', function ($value, $parameter, $data, $field) {
$exists = app('db')->table('users')->where('email', $value)->exists();
return $exists ? "The {$field} is already taken." : true;
});
hasExtension() #
public static function hasExtension(string $rule): bool
Check if a custom rule is registered:
if (Validator::hasExtension('slug')) {
// Rule exists
}