How can I manually return or throw a validation error/exception in Laravel?
As of laravel 5.5, the ValidationException
class has a static method withMessages
that you can use:
$error = \Illuminate\Validation\ValidationException::withMessages([
'field_name_1' => ['Validation Message #1'],
'field_name_2' => ['Validation Message #2'],
]);
throw $error;
I haven't tested this, but it should work.
Update
The message does not have to be wrapped in an array. You can also do:
use Illuminate\Validation\ValidationException;
throw ValidationException::withMessages(['field_name' => 'This value is incorrect']);
Manually throw Laravel ValidationException VS FormRequestValidationException
dd($exception instanceof Exception); //gives false
I'm pretty sure this is impossible. Illuminate\Validation\ValidationException
extends directly from Exception
. Your result might have to do with the catch block in checkEmailExists
. Just so you know, you shouldn't have to catch such exceptions inside your controller, since that is what the Exception Handler is for (app/Exceptions/Handler.php
).
There shouldn't be any different behaviour on how you use this, so let me show what ways you would use such validation:
Inside a controller function
Inside controllers you have the helper $this->validate(...)
available:
public function index(\Illuminate\Http\Request $request) {
$this->validate($request, [
'test' => 'required|integer'
], [
'test.integer' => 'Some custom message for when this subvalidation fails'
]);
}
This automatically throws a ValidationException
and therefore should get picked up by your Exception handler. Your Exception handler will then decide whether to return a JSON response with the validation errors (this will happen when a header Accept: application/json
was used for instance) or flash messages to the session such that you can show them in your templates.
Outside controllers
Sometimes it is extremely handy to use the validation for things that run outside of your controllers. These could be jobs or background tasks for instance. In those cases, you would call it like so (its basically the thing what happens in the controller function):
class SomeLibrary
{
public function doSomething() {
// Quickest way:
\Illuminate\Support\Facades\Validator::make($data, [
'test' => 'required|integer'
])->validate();
// Convoluted way:
// (see your own code in the original post)
}
}
This syntax basically does the same thing and also throws a ValidationException
.
Throw a validation error immediately
Lastly, in some cases you want to immediately throw a validation exception without even needing to test any input, in that case you can use this to set the error messages:
throw \Illuminate\Validation\ValidationException::withMessages([
'amount' => 'The amount is not high enough'
]);
This will then follow the same route through the exception handler.
Laravel throw a custom ValidationException
May be you would like to try if you have field names "one_thing" and "another_thing"
$error = Illuminate\Validation\ValidationException::withMessages([
"one_thing" => ["Validation Message #1"],
"another_thing" => ['Validation Message #2']
]);
throw $error;
check the withMessages() method definition
public static function withMessages(array $messages)
{
return new static(tap(ValidatorFacade::make([], []), function ($validator) use ($messages) {
foreach ($messages as $key => $value) {
foreach (Arr::wrap($value) as $message) {
$validator->errors()->add($key, $message);
}
}
}));
}
The keys are treated as fields name, so that the $errors you will through will be related to respective fields.
so basically like
$error = \Illuminate\Validation\ValidationException::withMessages([
'field_name_1' => ['Validation Message for field name 1'],
'field_name_2' => ['Validation Message for field name 2'],
'field_name_3' => ['Validation Message for field name 3'],
]);
throw $error;
Try this
Form code is
<form action="{{ route('test-validation') }}" method="POST">
@csrf
<input type="text" name="test" value="" />
@if( $errors->has('test') )
@foreach( $errors->get('test') as $err )
{{ $err }}
@endforeach
@endif
<input type="submit" name="submit" value="Submit" />
</form>
and in your routes/web.php
use Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\Request;
Route::post('test-validation', function(Request $request){
$fields = array('test' => $request->input('test'));
$rules = array('test' => 'required|min:5');
$validator = Validator::make($fields, $rules); // Empty data and rules fields
$validator->errors()->add('test', 'This is the error message for test field');
throw new ValidationException($validator);
redirect()->withErrors($validator);
})->name('test-validation');
With this code you should be able to get the errors correctly.
Laravel validation error not returning as json response
If validation fails during a traditional HTTP request, a redirect response to the previous URL will be generated.
If the incoming request is an XHR request, a JSON response containing the validation error messages will be returned.
First I suppose that /contact-us is a Web route and not an API route.
The $request->validate()
default behavior on failure is to redirect you to the previous Web route with MessageBag
.
To prevent that default behaviour, you need to wrap the validation process in a try-catch block and catch the Illuminate\Validation\ValidationException
Exception and return error messages from [IndexController::class, 'contactForm']
.
The the error messages array will automatically get converted to a JSON response.
try {
$request->validate([
'first_name' => ['required', 'string', 'min:3', 'max:255'],
'last_name' => ['required', 'string', 'min:3', 'max:255'],
'email' => ['required', 'email', 'min:3', 'max:255'],
'message' => ['required', 'string', 'min:3']
]);
} catch (\Illuminate\Validation\ValidationException $th) {
return $th->validator->errors();
}
Example respone:
{
"first_name": [
"first name field is required."
],
"last_name": [
"last name field is required."
],
"email": [
"L'E-mail field is required."
],
"message": [
"message field is required."
]
}
How to show only one error message from Laravel request rules
-For custom message
Laravel Documents customizing-the-error-messages
-For return single error message
//In Request
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json([
'success' => false,
'message' =>$validator->errors()->first(),
'data' => null,
], 422));
}
Include extra validation in Laravel 8 using $errors Variable
You can add custom validation for this instead of if else
$request -> validate([
'folio' => 'required',
'codigo_referido_id' => ['required', function ($attribute, $value, $fail) {
if (!Empleado::find($value)) {
$fail('The '.$attribute.' is invalid.');
}
}],
'descuento_activo_id' => 'required',
'lead_id' => 'required'
]);
Ref:https://laravel.com/docs/8.x/validation#custom-validation-rules
Related Topics
How to Detect and Handle MySQL Warnings with PHP
Empty Values Passed to Zend Framework 2 Validators
Setting Element of Array from Twig
Best Way to Document Array Options in PHPdoc
Php: Possible to Automatically Get All Posted Data and Multiple Checkbox Unchecked
Securing a Rest API Accessible from Android
Checking for Empty Arrays: Count VS Empty
Magento Addfieldtofilter: Two Fields, Match as Or, Not And
PHP How to Go One Level Up on Dirname(_File_)
Group MySQL Results by Category and Display Them into Groups Under Each Category
Variable Variables Pointing to Arrays or Nested Objects
Isset() Function Is Returning True Even When Item Is Not Set
Understanding Doctrine Cascade Operations