Is there any difference when I throw ValidationException
manally and when ValidationException
is thrown by laravel from FormRequest.
Following code will clear the problem
UserController.php
public function checkEmailExists(Request $request){
try {
$validation = Validator::make($request->only('email'), [
'email' => 'required|email|exists:users,email',
]);
if ($validation->fails()) {
throw (new ValidationException($validation));
}
} catch (\Exception $exception){
return $exception->render(); //nothing is returned/displayed
}
}
Handler.php
public function render($request, Throwable $exception)
{
dd($exception instanceof Exception);
}
From the UserController
I am throwing ValidationException
manually and in Handler.php
render method I am checking the $exception
is an instance of Exception
.
So If I throw ValidationException manually
then
dd($exception instanceof Exception); //gives false
But when I use UserStoreRequest (FormRequest)
UserController.php
public function checkEmailExists(UserStoreRequest $request){
//Exception thrown by laravel if validation fails fro UserStoreRequest
}
then in Handler.php render()
method
dd($exception instanceof Exception); //gives true
1:- Why it has different behavior when I throw ValidationException manally and when ValidationException is thrown by laravel from FormRequest?
2:- If I throw ValidationException manually then in the catch block I get the following error
Error {#3627
#message: "Call to undefined method Illuminate\Validation\ValidationException::render()"
#code: 0
#file: "myproject/app/Http/Controllers/UserController.php"
#line: 33
CodePudding user response:
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.