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

Laravel分类编辑部分字段提交后重定向不更新问题

Laravel分类编辑功能部分提交失效问题

问题表现

  • 分类创建后,仅编辑部分表单项提交,页面直接重定向回当前编辑页,数据库无任何更新
  • 编辑全部输入项、或同时修改英语、阿拉伯语双语名称时,更新功能可正常运行
  • 项目基于Laravel开发,使用spatie/mcmara扩展实现多语言本地化

相关代码

视图文件(分类编辑表单)

<form class="form" method="POST" action="/admin/categories/{{$category->route}}/update" enctype="multipart/form-data">
@csrf
{{-- @method('PATCH') --}}
<div class="form-group">
    <div class="label">
        <label for="ArabicName">{{__('admin.CategoryArabicName')}}</label>
        <input type="text" class="form-control" id="ArabicName" name="ArabicName" placeholder="{{__('admin.CategoryArabicName')}}" value="{{$category->getTranslation('title','ar')}}">
        @error('ArabicName')
        <span class="error">{{ $message }}</span>
        @enderror
    </div>
    <div class="label">
        <label for="EnglishName">{{__('admin.CategoryEnglishName')}}</label>
        <input type="text" class="form-control" id="EnglishName" name="EnglishName" placeholder="{{__('admin.CategoryEnglishName')}}" value="{{$category->getTranslation('title','en')}}">
        @error('EnglishName')
        <span class="error">{{ $message }}</span>
        @enderror
    </div>
</div>
<div class="form-group">
    <div class="label">
        <label for="route">{{__('admin.Route')}}</label>
        <input type="text" class="form-control" id="route" name="route" placeholder="{{__('admin.Route')}}" value="{{$category->route}}">
        @error('route')
        <span class="error">{{ $message }}</span>
        @enderror
    </div>
    <div class="label">
        <label for="upload_image">{{__('admin.UploadImage')}}</label>
        <input type="file" class="form-control" accept="image/*" id="upload_image" name="upload_image[]" value="{{$category->image}}" multiple>
        @error('upload_image')
        <span class="error">{{ $message }}</span>
        @enderror
    </div>
</div>
<input type="submit" class="submit" value="{{__('admin.Update')}}">
</form>

路由定义

Route::group([
    'prefix' => 'admin',
],function () {
    Route::group([
        'prefix' => 'categories',
    ],function(){
        Route::post('/{category:route}/update',[CategoriesAdminController::class,'update']);
    });
});

表单验证类(UpdateCategoryRequest)

public function authorize()
{
    return true;
}

/**
 * Get the validation rules that apply to the request.
 *
 * @return array<string, mixed>
 */
public function rules()
{
    return [
        'ArabicName' => 'required|max:255',
        'EnglishName' => 'required|max:255',
        'route' => ['required', Rule::unique('categories', 'route'), 'max:255'],
        'upload_image.*' => 'required|image|max:2048',
    ];
}

public function messages()
{
    return [
        'ArabicName.required' => __('validation.required'),
        'EnglishName.required' => __('validation.required'),
        'route.required' => __('validation.required'),
        'route.unique' => __('validation.unique'),
    ];
}

控制器更新方法

public function update(UpdateCategoryRequest $request ,Category $category)
{
    if(Category::where('title->ar', request()->ArabicName)->orWhere('title->en', request()->EnglishName)->exists()){
        return redirect()->back()->with('storeError', __('admin.NameIsAlreadyTaken'));
    }
    try {
        $attributes = $request->validated();
        Category::updateCategory($category,$attributes);
        return redirect('/admin/categories')->with('updateSuccess', __('admin.CategoryUpdatedSuccessfully'));
    }catch (\Exception $e) {
        return redirect()->back()->withErrors($e->getMessage());
    }
}

模型层更新方法

public static function updateCategory($category,$attributes){
    $file = array();
    $Newfiles = array();
    if($file = request()->hasFile('upload_image')){
        $imageArray = explode('|',$category->image);
        foreach ($imageArray as $image) {
            Storage::disk('public')->delete($image);
        }
        foreach (request()->file('upload_image') as $file) {
            $fileName = md5(rand(100,1000)) . time() . '.' . strtolower($file->getClientOriginalExtension());
            $folderName = "categories/" . request()->EnglishName;
            $fullUrl = $folderName . '/' . $fileName;
            $file->storeAs($folderName, $fileName , 'public');
            $Newfiles[] = $fullUrl;
        }
    }
    $image = implode('|' , $Newfiles);
    $category->update([
        'image' => $image,
        'title' => ['ar' => $attributes['ArabicName'], 'en' => $attributes['EnglishName']],
        'route' => $attributes['route'],
    ]);
}

故障原因

一共三处逻辑错误共同导致该问题:

  1. 名称重复校验未排除当前分类:控制器里判断名称是否重复的查询,没有排除正在编辑的分类本身。只要提交的阿拉伯语名、英语名任意一个和当前分类原有名称一致(也就是只改了单语名称、或者没改名称的场景),查询就会命中当前分类的记录,直接返回重定向提示名称占用,不会执行后续更新逻辑。只有同时修改双语名称时,查询匹配不到现有记录,才能往下执行。
  2. 路由字段唯一校验未排除当前分类:验证类里route字段的unique规则没有添加忽略当前分类的配置,只要提交时不修改route值,校验就会判定route已被当前分类自身占用,直接验证失败打回。
  3. 图片字段校验规则错误:验证类里给upload_image.*加了required规则,编辑场景下用户不需要每次更新都重新上传图片,只要未上传新图片,该字段为空数组就会触发校验失败。只有重新上传图片时才能通过该规则校验。

另外模型层还存在隐藏bug:未上传新图片时,$Newfiles为空数组,implode后生成空字符串,会把分类原有图片路径覆盖为空。
只有当用户把所有字段都修改(双语名称都改、route改、重新上传图片)时,三处校验才能全部通过,更新才会正常执行,和反馈的现象完全吻合。


修复方案

  1. 修改控制器的名称重复校验,排除当前分类ID,同时修正orWhere的查询优先级问题:
    if(Category::where('id', '!=', $category->id)
        ->where(function($q) {
            $q->where('title->ar', request()->ArabicName)
              ->orWhere('title->en', request()->EnglishName);
        })->exists()){
        return redirect()->back()->with('storeError', __('admin.NameIsAlreadyTaken'));
    }
    
  2. 修改验证类的route规则,忽略当前分类的route:
    'route' => ['required', Rule::unique('categories', 'route')->ignore($this->category->id), 'max:255'],
    
  3. 修改验证类的图片规则,去掉编辑场景下的必填要求,同时修复模型层未上传新图片时覆盖原有图片路径的问题:
    • 验证规则修改为:'upload_image.*' => 'image|max:2048'
    • 模型层更新逻辑调整,未上传新图片时保留原有图片路径:
      $image = $category->image; // 默认保留原图
      if(request()->hasFile('upload_image')){
          $imageArray = explode('|',$category->image);
          foreach ($imageArray as $oldImage) {
              Storage::disk('public')->delete($oldImage);
          }
          $Newfiles = [];
          foreach (request()->file('upload_image') as $file) {
              $fileName = md5(rand(100,1000)) . time() . '.' . strtolower($file->getClientOriginalExtension());
              $folderName = "categories/" . $attributes['EnglishName'];
              $fullUrl = $folderName . '/' . $fileName;
              $file->storeAs($folderName, $fileName , 'public');
              $Newfiles[] = $fullUrl;
          }
          $image = implode('|' , $Newfiles);
      }
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:06:32