如何通过通用CrudInterface传递不同自定义请求并触发验证?
问题分析与解决方案
核心问题
你遇到的验证未触发问题,本质是Laravel的FormRequest验证逻辑仅在通过服务容器解析时自动执行,手动new CreateTagRequest()只是创建了对象,不会触发验证流程,因此rules()中的日志不会输出,空值也未被拦截,最终导致SQL非空约束错误。
解决方案
方案一:控制器注入自定义请求(推荐,符合Laravel设计模式)
直接在控制器方法参数中注入CreateTagRequest,Laravel会自动触发验证,验证失败时直接返回422错误,无需手动处理。
- 修改控制器代码:
public function store(CreateTagRequest $request) { try { \Log::info(' -1 BEFORE CreateTagRequest::'); // 直接使用验证通过的字段,避免手动筛选数据的误差 $tag = $this->tagCrudRepository->store( data: $request->validated(), request: $request ); // 后续逻辑(如返回响应) } catch (\Exception $e) { // 异常处理 } }
- 完善
CreateTagRequest的验证规则:
class CreateTagRequest extends FormRequest { public function authorize(): bool { return true; } public function rules(): array { \Log::info( '-1 CreateTagRequest data::' . print_r( $this->all(), true ) ); return [ 'name' => 'required|string|max:255|unique:tags', ]; } }
- 仓库直接使用验证后的数据:
// TagCrudRepository public function store(array $data, $request): Tag { return Tag::create($data); }
方案二:仓库中手动触发验证(适合需要保持控制器通用性的场景)
如果必须通过通用接口传递自定义请求,可在仓库内手动触发验证逻辑:
- 调整
CrudInterface的类型声明:
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Database\Eloquent\Model; interface CrudInterface { public function store(array $data, FormRequest $request): Model; }
- 在仓库的
store方法中触发验证:
// TagCrudRepository public function store(array $data, FormRequest $request): Tag { // 触发验证,获取通过验证的字段 $validatedData = $request->validated(); return Tag::create($validatedData); }
- 控制器中通过服务容器解析请求(确保绑定上下文):
public function store(Request $request) { try { \Log::info(' -1 BEFORE CreateTagRequest::'); // 用服务容器解析请求,自动绑定当前请求上下文 $tagRequest = app(CreateTagRequest::class); $tag = $this->tagCrudRepository->store( data: $request->only('name'), request: $tagRequest ); } catch (\Exception $e) { // 异常处理 } }
关键说明
- 避免手动实例化
FormRequest,因为这种方式不会触发Laravel内置的验证流程; $request->validated()仅返回通过验证的字段,比手动only()更安全,能避免遗漏验证规则;- 验证规则中添加
required约束后,空值会被拦截,从根源解决SQL非空约束错误。
内容的提问来源于stack exchange,提问作者mstdmstd
相关产品推荐
相关产品推荐

