You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10跨控制器调用FormRequest触发validated()空对象错误

Laravel 10控制器间调用时validated()报null错误解决

问题场景

使用Laravel 10,尝试从AdminV1Controller调用AdminController的store方法时,AdminController执行到$validatedData = $request->validated();时抛出错误:Call to a member function validated() on null。

相关代码

AdminV1Controller代码

class AdminV1Controller extends Controller
{
    public function store(AdminV1Request  $request): \Illuminate\Http\JsonResponse
    {
        try {
            $validatedData = $request->validated();
            return (new AdminController)->store(new StoreEventRequest($validatedData));
        } catch (\Exception $e) {
            Log::error('Failed to store event: ' , ["error"=>$e->getMessage()]);
            return response()->json(['message' => 'Failed to store event', 'error' => $e->getMessage()], 500);
        }
    }
}

AdminController代码

class AdminController extends Controller
{
   public function store(StoreEventRequest $request)
    {
        try {
            $validatedData = $request->validated();
            $event = Event::createEvent($validatedData);
            return response()
                    ->json(['message' => 'Event created successfully', 'data' => new EventResource($event)], 201);
        } catch (\Exception $e) {
            Log::error('Failed to create event: ' , ["error" => $e->getMessage()] );
            return response()->json(['message' => 'Failed to create event', 'error' => $e->getMessage()], 500);
        }
    }
}

AdminV1Request验证规则

<?php

namespace App\Http\Requests\Admin;

use App\Enums\ValidationEnum;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;

class AdminV1Request extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'description' => 'required|string',
            'date' => 'required|date|date_format:Y-m-d',
            'location' => 'required|string|max:255',
        ];
    }

    public function failedValidation(Validator $validator): void
    {
        throw new HttpResponseException(response()->json([
            'success'   => false,
            'message'   => 'Validation errors',
            'data'      => $validator->errors()
        ]));
    }

    public function messages(): array
    {
        return [
            'name.required' => ValidationEnum::REQUIRED_MESSAGE->value,
            'name.string' => ValidationEnum::STRING_MESSAGE->value,
            'name.max' => 'The :attribute may not be greater than :max characters.',
            'description.required' => ValidationEnum::REQUIRED_MESSAGE->value,
            'description.string' => ValidationEnum::STRING_MESSAGE->value,
            'date.required' => ValidationEnum::REQUIRED_MESSAGE->value,
            'date.date' => 'The :attribute must be a valid date.',
            'date.date_format' => 'The :attribute must be a YYYY-MM-DD format.',
            'location.required' => ValidationEnum::REQUIRED_MESSAGE->value,
            'location.string' => ValidationEnum::STRING_MESSAGE->value,
            'location.max' => 'The :attribute may not be greater than :max characters.',
        ];
    }
}

StoreEventRequest验证规则

<?php

namespace App\Http\Requests\Admin;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;


class StoreEventRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'nullable|string|max:255',
            'description' => 'nullable|string',
            'date' => 'nullable|date|date_format:Y-m-d',
            'location' => 'nullable|string|max:255',
        ];
    }

    public function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(response()->json([
            'success'   => false,
            'message'   => 'Validation errors',
            'data'      => $validator->errors()
        ]));
    }

    public function messages()
    {
        return [
            'name.string' => 'The :attribute must be a string.',
            'name.max' => 'The :attribute may not be greater than :max characters.',
            'description.string' => 'The :attribute must be a string.',
            'date.date' => 'The :attribute must be a valid date.',
            'date.date_format' => 'The :attribute must be a YYYY-MM-DD format.',
            'location.string' => 'The :attribute must be a string.',
            'location.max' => 'The :attribute may not be greater than :max characters.',
        ];
    }
}

路由配置(api.php)

<?php

Route::controller(Admin::class)
       ->prefix('admin')
       ->middleware(['auth:api'])
       ->group(function () {
            Route::post('/event',  'store');
            Route::put('/event/{id}', 'update')->where('id', '[0-9]+');
            Route::delete('/event/{id}', 'destroy')->where('id', '[0-9]+');
            Route::get('/events',  'index');
});

Route::controller(AdminV1::class)
    ->prefix('admin/v1')
    ->middleware(['auth:api'])
    ->group(function () {
        Route::post('/event',  'store');
        Route::put('/event/{id}', 'update')->where('id', '[0-9]+');
        Route::delete('/event/{id}', 'destroy')->where('id', '[0-9]+');
        Route::get('/events',  'index');
    });

错误原因

Laravel的FormRequest是依赖容器解析的,框架会自动处理请求数据填充、验证逻辑等流程。直接通过new StoreEventRequest($validatedData)实例化时,没有经过框架的初始化流程,FormRequest内部的请求数据、验证状态等属性未正确设置,导致调用validated()方法时出现空指针错误。

解决方案

方案1:手动初始化FormRequest并触发验证

在AdminV1Controller中,不要直接newStoreEventRequest,而是通过create方法初始化请求数据,并手动触发验证:

public function store(AdminV1Request $request): \Illuminate\Http\JsonResponse
{
    try {
        $validatedData = $request->validated();
        
        // 初始化StoreEventRequest,传递当前请求的上下文和验证后的数据
        $storeRequest = StoreEventRequest::create(
            $request->url(),
            $request->method(),
            $validatedData,
            $request->headers->all(),
            $request->allFiles()
        );
        
        // 手动触发验证流程
        $storeRequest->validateResolved();
        
        return (new AdminController)->store($storeRequest);
    } catch (\Exception $e) {
        Log::error('Failed to store event: ', ["error" => $e->getMessage()]);
        return response()->json(['message' => 'Failed to store event', 'error' => $e->getMessage()], 500);
    }
}

方案2:重构业务逻辑到Service层(推荐)

控制器的职责应该是处理请求和响应,业务逻辑抽离到Service层可以避免控制器间的耦合,同时复用验证逻辑:

  1. 创建EventService类:
// app/Services/EventService.php
namespace App\Services;

use App\Models\Event;
use App\Http\Requests\Admin\StoreEventRequest;
use Illuminate\Support\Facades\Validator;

class EventService
{
    public function createEvent(array $data)
    {
        // 复用StoreEventRequest的验证规则
        $validator = Validator::make($data, (new StoreEventRequest)->rules());
        // 触发验证,失败则抛出异常
        $validator->validate();
        
        return Event::createEvent($validator->validated());
    }
}
  1. 修改AdminController的store方法:
public function store(StoreEventRequest $request)
{
    try {
        $event = app(\App\Services\EventService::class)->createEvent($request->validated());
        return response()
                ->json(['message' => 'Event created successfully', 'data' => new EventResource($event)], 201);
    } catch (\Exception $e) {
        Log::error('Failed to create event: ', ["error" => $e->getMessage()]);
        return response()->json(['message' => 'Failed to create event', 'error' => $e->getMessage()], 500);
    }
}
  1. 修改AdminV1Controller的store方法:
public function store(AdminV1Request $request): \Illuminate\Http\JsonResponse
{
    try {
        $event = app(\App\Services\EventService::class)->createEvent($request->validated());
        return response()
                ->json(['message' => 'Event created successfully', 'data' => new EventResource($event)], 201);
    } catch (\Exception $e) {
        Log::error('Failed to store event: ', ["error" => $e->getMessage()]);
        return response()->json(['message' => 'Failed to store event', 'error' => $e->getMessage()], 500);
    }
}

这种方式既保证了StoreEventRequest的验证规则被复用,又消除了控制器之间的依赖,符合Laravel的最佳实践。

内容的提问来源于stack exchange,提问作者CodeLove

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:40:55