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'], ]); }
故障原因
一共三处逻辑错误共同导致该问题:
- 名称重复校验未排除当前分类:控制器里判断名称是否重复的查询,没有排除正在编辑的分类本身。只要提交的阿拉伯语名、英语名任意一个和当前分类原有名称一致(也就是只改了单语名称、或者没改名称的场景),查询就会命中当前分类的记录,直接返回重定向提示名称占用,不会执行后续更新逻辑。只有同时修改双语名称时,查询匹配不到现有记录,才能往下执行。
- 路由字段唯一校验未排除当前分类:验证类里
route字段的unique规则没有添加忽略当前分类的配置,只要提交时不修改route值,校验就会判定route已被当前分类自身占用,直接验证失败打回。 - 图片字段校验规则错误:验证类里给
upload_image.*加了required规则,编辑场景下用户不需要每次更新都重新上传图片,只要未上传新图片,该字段为空数组就会触发校验失败。只有重新上传图片时才能通过该规则校验。
另外模型层还存在隐藏bug:未上传新图片时,$Newfiles为空数组,implode后生成空字符串,会把分类原有图片路径覆盖为空。
只有当用户把所有字段都修改(双语名称都改、route改、重新上传图片)时,三处校验才能全部通过,更新才会正常执行,和反馈的现象完全吻合。
修复方案
- 修改控制器的名称重复校验,排除当前分类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')); } - 修改验证类的
route规则,忽略当前分类的route:'route' => ['required', Rule::unique('categories', 'route')->ignore($this->category->id), 'max:255'], - 修改验证类的图片规则,去掉编辑场景下的必填要求,同时修复模型层未上传新图片时覆盖原有图片路径的问题:
- 验证规则修改为:
'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
相关产品推荐
相关产品推荐

