將驗證邏輯從 Controller 剝離,實現:
authorize() 方法整合權限判斷php artisan make:request StoreCommentRequest
namespace App\Http\Requests;
class StoreCommentRequest extends Request {
public function authorize() {
return true; // 或加入權限邏輯:return $this->user()->can('comment');
}
public function rules() {
return [
'comment' => 'required|string|max:1000',
'rating' => 'required|integer|between:1,5',
];
}
// 可選:自定義錯誤信息
public function messages() {
return [
'comment.required' => '評論內容不能為空',
'rating.between' => '評分必須在 1-5 之間',
];
}
}
// Controller
public function store(StoreCommentRequest $request) {
// 驗證已通過,$request->validated() 獲取安全數據
$comment = Comment::create($request->validated());
return response()->json($comment, 201);
}
ValidationServiceProvider::registerValidationResolverHook() 監聽容器解析 ValidatesWhenResolved 接口實例validate() (來自 ValidatesWhenResolvedTrait)FormRequest::failedValidation() 拋出 HttpResponseException,攜帶構建好的 ResponseRoute::run() 捕獲 HttpResponseException 直接返回 $e->getResponse(),**繞過全局異常處理器**// FormRequest::response() 簡化版
if ($this->ajax() || $this->wantsJson()) {
return new JsonResponse($errors, 422); // API 請求
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag); // 表單請求
// app/Http/Requests/Request.php (基類)
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use App\Exceptions\ValidationException; // 自定義異常
abstract class Request extends FormRequest {
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator) {
throw new ValidationException($validator); // 攜帶 Validator 實例
}
}
// app/Exceptions/ValidationException.php
namespace App\Exceptions;
use Illuminate\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
class ValidationException extends HttpResponseException {
public function __construct(Validator $validator) {
$response = request()->ajax() || request()->wantsJson()
? response()->json(['errors' => $validator->errors()], 422)
: redirect()->back()->withErrors($validator)->withInput();
parent::__construct($response);
}
}
需在 Route::run() 之前處理,可通過中間件或重寫路由調度實現,複雜度高。
// app/Exceptions/Handler.php
public function render($request, Exception $e) {
if ($e instanceof \Illuminate\Validation\ValidationException) {
return response()->json([
'success' => false,
'message' => '驗證失敗',
'errors' => $e->errors(),
], 422);
}
return parent::render($request, $e);
}
⚠️ 注意:FormRequest 拋出的是 HttpResponseException 而非 ValidationException,需在基類中轉換或使用中間件攔截。
| 需求 | 實現 |
|---|---|
| 條件驗證 | 'email' => 'required_if:account_type,email' |
| 數組字段驗證 | 'items.*.name' => 'required|string' |
| 驗證後修改數據 | 重寫 validated() 或使用 prepareForValidation() |
| 文件上傳驗證 | 'avatar' => 'required|image|mimes:jpg,png|max:2048' |
| 唯一性驗證 (排除自己) | 'email' => 'unique:users,email,' . $this->user()->id |