⬆️ Go to top ⬅️ Previous (Routing) ➡️ Next (Collections)
- Image validation
- Custom validation error messages
- Validate dates with "now" or "yesterday" words
- Validation Rule with Some Conditions
- Change Default Validation Messages
- Prepare for Validation
- Stop on First Validation Error
- Throw 422 status code without using validate() or Form Request
- Rules depending on some other conditions
- With Rule::when() we can conditionally apply validation rules
- Use this property in the request classes to stop the validation of the whole request attributes
- Rule::unique doesn't take into the SoftDeletes Global Scope applied on the Model
- Validator::sometimes() method allows us to define when a validation rule should be applied
- Array elements validation
- Password::defaults method
- Form Requests for validation redirection
- Mac validation rule
- Validate email with TLD domain required
While validating uploaded images, you can specify the dimensions you require.
['photo' => 'dimensions:max_width=4096,max_height=4096']
You can customize validation error messages per field, rule and language - just create a specific language file resources/lang/xx/validation.php
with appropriate array structure.
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
You can validate dates by rules before/after and passing various strings as a parameter, like: tomorrow
, now
, yesterday
. Example: 'start_date' => 'after:now'
. It's using strtotime() under the hood.
$rules = [
'start_date' => 'after:tomorrow',
'end_date' => 'after:start_date'
];
If your validation rules depend on some condition, you can modify the rules by adding withValidator()
to your FormRequest
class, and specify your custom logic there. Like, if you want to add validation rule only for some user role.
use Illuminate\Validation\Validator;
class StoreBlogCategoryRequest extends FormRequest {
public function withValidator(Validator $validator) {
if (auth()->user()->is_admin) {
$validator->addRules(['some_secret_password' => 'required']);
}
}
}
If you want to change default validation error message for specific field and specific validation rule, just add a messages()
method into your FormRequest
class.
class StoreUserRequest extends FormRequest
{
public function rules()
{
return ['name' => 'required'];
}
public function messages()
{
return ['name.required' => 'User name should be real name'];
}
}
If you want to modify some field before default Laravel validation, or, in other words, "prepare" that field, guess what - there's a method prepareForValidation()
in FormRequest
class:
protected function prepareForValidation()
{
$this->merge([
'slug' => Illuminate\Support\Str::slug($this->slug),
]);
}
By default, Laravel validation errors will be returned in a list, checking all validation rules. But if you want the process to stop after the first error, use validation rule called bail
:
$request->validate([
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
If you need to stop validation on the first error in FormRequest
class, you can set stopOnFirstFailure
property to true
:
protected $stopOnFirstFailure = true;
If you don't use validate() or Form Request, but still need to throw errors with the same 422 status code and error structure, you can do it manually throw ValidationException::withMessages()
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
If your rules are dynamic and depend on some other condition, you can create that array of rules on the fly
public function store(Request $request)
{
$validationArray = [
'title' => 'required',
'company' => 'required',
'logo' => 'file|max:2048',
'location' => 'required',
'apply_link' => 'required|url',
'content' => 'required',
'payment_method_id' => 'required'
];
if (!Auth::check()) {
$validationArray = array_merge($validationArray, [
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:5',
'name' => 'required'
]);
}
//
}
Thanks to Rule::when() we can conditionally apply validation rules in laravel.
In this example we validate the value of the vote only if the user can actually vote the post.
use Illuminate\Validation\Rule;
public function rules()
{
return [
'vote' => Rule::when($user->can('vote', $post), 'required|int|between:1,5'),
]
}
Tip given by @cerbero90
Use this property in the request classes to stop the validation of the whole request attributes.
Hint Direct
This is different from Bail
rule that stops the validation for just a single attribute if one of its rules doesn't validate.
/**
* Indicated if the validator should stop
* the entire validation once a single
* rule failure has occurred.
*/
protected $stopOnFirstFailure = true;
Tip given by @Sala7JR
Strange that Rule::unique
doesn't take into the SoftDeletes Global Scope applied on the Model, by default.
But withoutTrashed()
method is available
Rule::unique('users', 'email')->withoutTrashed();
Tip given by @Zubairmohsin33
The laravel Validator::sometimes()
method allows us to define when a validation rule should be applied, based on the input provided.
The snippet shows how to prohibit the use of a coupon if the quantity of the purchased items is not enough.
$data = [
'coupon' => 'PIZZA_PARTY',
'items' => [
[
'id' => 1,
'quantity' => 2
],
[
'id' => 2,
'quantity' => 2,
],
],
];
$validator = Validator::make($data, [
'coupon' => 'exists:coupons,name',
'items' => 'required|array',
'items.*.id' => 'required|int',
'items.*.quantity' => 'required|int',
]);
$validator->sometimes('coupon', 'prohibited', function (Fluent $data) {
return collect($data->items)->sum('quantity') < 5;
});
// throws a ValidationException as the quantity provided is not enough
$validator->validate();
Tip given by @cerbero90
If you want to validate elements of an array that you submited use dot notation in rules with '*'
// say you have this array
// array in request 'user_info'
$request->validated()->user_info = [
[
'name' => 'Qasim',
'age' => 26,
],
[
'name' => 'Ahmed',
'age' => 23,
],
];
// Rule
$rules = [
'user_info.*.name' => ['required', 'alpha'],
'user_info.*.age' => ['required', 'numeric'],
];
Tip given by HydroMoon
You can enforce specific rules when validating user-supplied passwords by using the Password::defaults method. It includes options for requiring letters, numbers, symbols, and more.
class AppServiceProvider
{
public function boot(): void
{
Password::defaults(function () {
return Password::min(12)
->letters()
->numbers()
->symbols()
->mixedCase()
->uncompromised();
})
}
}
request()->validate([
['password' => ['required', Password::defaults()]]
])
Tip given by @mattkingshott
when using Form Requests for validation, by default the validation error will redirect back to the previous page, but you can override it.
Just define the property of $redirect
or $redirectRoute
.
Link to docs
// The URI that users should be redirected to if validation fails./
protected $redirect = '/dashboard';
// The route that users should be redirected to if validation fails.
protected $redirectRoute = 'dashboard';
New mac_address validation rule added in Laravel 8.77
$trans = $this->getIlluminateArrayTranslator();
$validator = new Validator($trans, ['mac' => '01-23-45-67-89-ab'], ['mac' => 'mac_address']);
$this->assertTrue($validator->passes());
Tip given by [@Teacoders]
By default, the email
validation rule will accept an email without tld domain (ie: taylor@laravel
, povilas@ldaily
)
But if you want to make sure the email must have a tld domain (ie: taylor@laravel.com
, povilas@ldaily.com
), use email:filter
rule.
[
'email' => 'required|email', // before
'email' => 'required|email:filter', // after
],
Tip given by @Chris1904