手动抛出 Laravel ValidationException VS FormRequestValidationException

Manually throw Laravel ValidationException VS FormRequestValidationException

当我手动抛出 ValidationException 和当 ValidationException 被 laravel 从 FormRequest 抛出 时有什么不同吗.

以下代码将解决问题

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);
}

UserController 我正在抛出 ValidationException 手动 并且在 Handler.php 渲染方法中我正在检查 $exceptionException 的实例。 所以如果我抛出 ValidationException manually 那么

dd($exception instanceof Exception); //gives false

但是当我使用 UserStoreRequest (FormRequest)

UserController.php

public function checkEmailExists(UserStoreRequest $request){
    //Exception thrown by laravel if validation fails fro UserStoreRequest
}

然后在Handler.php render()方法

dd($exception instanceof Exception); //gives true

1:- 为什么当我手动抛出 ValidationException 时和 laravel 从 FormRequest 抛出 ValidationException 时它有不同的行为?

2:- 如果我手动抛出 ValidationException,那么在 catch 块中我会收到以下错误

Error {#3627
  #message: "Call to undefined method Illuminate\Validation\ValidationException::render()"
  #code: 0
  #file: "myproject/app/Http/Controllers/UserController.php"
  #line: 33
dd($exception instanceof Exception); //gives false

我很确定这是不可能的。 Illuminate\Validation\ValidationException 直接扩展自 Exception。您的结果可能与 checkEmailExists 中的 catch 块有关。正如您所知,您不必在控制器中捕获此类异常,因为这就是异常处理程序的用途 (app/Exceptions/Handler.php).

你如何使用它不应该有任何不同的行为,所以让我展示你将如何使用这种验证:

控制器函数内部

在控制器内部你有可用的助手$this->validate(...)

public function index(\Illuminate\Http\Request $request) {
    $this->validate($request, [
        'test' => 'required|integer'
    ], [
        'test.integer' => 'Some custom message for when this subvalidation fails'
    ]);
}

这会自动抛出一个 ValidationException,因此应该被您的异常处理程序接收到。然后,您的异常处理程序将决定是否 return 带有验证错误的 JSON 响应(例如,当使用 header Accept: application/json 时会发生这种情况)或向session 这样您就可以在模板中显示它们。

外部控制者

有时,对 运行 控制器之外的事物使用验证非常方便。例如,这些可以是作业或后台任务。在那些情况下,你会这样称呼它(它基本上就是控制器函数中发生的事情):

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)
        
    }
}

这个语法基本上做了同样的事情,并且抛出一个 ValidationException.

立即抛出验证错误

最后,在某些情况下你想立即抛出验证异常而不需要测试任何输入,在这种情况下你可以使用它来设置错误消息:

throw \Illuminate\Validation\ValidationException::withMessages([
    'amount' => 'The amount is not high enough'
]);

这将通过异常处理程序遵循相同的路线。