Laravel更新分类仅修改部分字段提交失败重定向问题排查
问题根因
该编辑功能异常与多语言本地化包无直接关联,是3处代码逻辑bug共同导致的:
- 验证规则存在设计缺陷:
UpdateCategoryRequest中route字段的唯一校验未排除当前正在编辑的分类本身,只要编辑时未修改route字段,提交值就会和当前分类已有route值冲突,触发验证失败;同时upload_image.*规则加了required限制,编辑场景下如果不上传新图片,会直接触发必填校验失败,页面重定向回编辑页。 - 重名判断逻辑错误:控制器中校验分类名称重复的查询是全表匹配,未排除当前编辑的分类ID,只要编辑时未修改阿语/英语名称,查询就会命中当前分类自身的记录,直接触发"名称已占用"的回退逻辑。
- 图片更新逻辑漏洞:模型的
updateCategory方法中,只要未上传新图片,存储新图片路径的数组就是空值,implode后会生成空字符串,直接把分类原有图片路径覆盖为空;同时用提交的英文分类名作为图片存储文件夹名,后续修改分类名时会导致旧图片路径失效。
修复方案
1. 调整验证层规则
编辑场景下排除当前分类的唯一校验,同时取消编辑时图片必传的限制:
public function rules() { // 获取当前路由绑定的分类实例,用于自身排除 $currentCategory = $this->route('category'); return [ 'ArabicName' => 'required|max:255', 'EnglishName' => 'required|max:255', // 唯一校验忽略当前分类本身 'route' => ['required', Rule::unique('categories', 'route')->ignore($currentCategory->id), 'max:255'], // 编辑场景允许不上传新图片,去掉required改为nullable 'upload_image.*' => 'nullable|image|max:2048', ]; }
2. 修正控制器重名判断
查询重复名称时排除当前编辑的分类,同时修正orWhere的查询作用域问题:
public function update(UpdateCategoryRequest $request ,Category $category) { // 重名查询排除当前分类,用闭包包裹多语言名称的or查询避免条件溢出 if(Category::where('id', '!=', $category->id) ->where(function($query) use ($request) { $query->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()); } }
3. 修复模型图片更新逻辑
未上传新图片时保留原有图片路径,避免覆盖已有数据:
public static function updateCategory($category,$attributes){ $Newfiles = []; // 仅当确实上传了新图片时,才执行旧图删除、新图上传逻辑 if(request()->hasFile('upload_image')){ $imageArray = explode('|',$category->image); foreach ($imageArray as $image) { // 先判断文件存在再删除,避免抛错 if(Storage::disk('public')->exists($image)){ Storage::disk('public')->delete($image); } } foreach (request()->file('upload_image') as $file) { $fileName = md5(rand(100,1000)) . time() . '.' . strtolower($file->getClientOriginalExtension()); // 固定用categories作为存储文件夹,不要用动态分类名,避免后续改名导致图片路径失效 $folderName = "categories"; $fullUrl = $folderName . '/' . $fileName; $file->storeAs($folderName, $fileName , 'public'); $Newfiles[] = $fullUrl; } } $updateData = [ 'title' => ['ar' => $attributes['ArabicName'], 'en' => $attributes['EnglishName']], 'route' => $attributes['route'], ]; // 有新图片时才更新image字段,否则保留原有图片路径 if(!empty($Newfiles)){ $updateData['image'] = implode('|' , $Newfiles); } $category->update($updateData); }
额外优化建议:视图中注释掉的
@method('PATCH')可以放开,对应将路由的POST方法改为PATCH,符合RESTful接口规范。
内容的提问来源于stack exchange,提问作者Ahmed Essam
相关产品推荐
相关产品推荐

