Laravel8实现跨表移动数据至watchlist功能的报错排查
问题排查与修复方案
你遇到的「尝试获取非对象的firstname属性」报错,连带之前的逻辑问题,总共有6处代码错误,逐一修复即可正常运行:
一、核心错误点说明
- 视图层ID传值错误:你把存放多条访客数据的集合对象
$visitor直接取->id,集合本身没有id属性,导致传到后端的ID为null,查不到对应访客记录,$record返回空值,自然无法读取firstname属性 - 输入框属性错误:reason输入框写了两个name属性,第一个还带了多余空格
name="reason ",后端无法正常接收到提交的reason参数 - 删除逻辑错误:用
DB::table()查询返回的是通用标准对象,不是Eloquent模型对象,没有内置delete()方法,直接调用会触发报错 - 冗余无效代码:你实例化了
$watchlist = new watchlist()但没有给它赋值任何属性,最后调用save()属于无效操作,因为你已经用QueryBuilder的insert方法完成了数据写入 - 重定向语法错误:
redirect('visitor.visitorlist')后面缺少连接符,正确写法是->with(),如果调用命名路由应该用route()方法,直接传字符串需要填写实际访问路径 - 交互逻辑缺失:列表复选框没有绑定行ID,点击全局按钮时无法识别要操作哪条数据,逻辑不成立
二、分步修复代码
1. 修正控制器代码
将原有的AddToWatchlist方法替换为以下内容:
public function AddToWatchlist(Request $request, $id) { // 基础参数校验,拦截非法请求 $request->validate([ 'reason' => 'required|string|max:255' ]); // 查询对应访客记录,不存在则直接返回错误提示 $record = DB::table('visitors')->where('id', $id)->first(); if (!$record) { return back()->with('status', '未找到对应访客记录'); } // 写入观察名单表,自动补全时间字段 DB::table('watchlist')->insert([ 'firstname' => $record->firstname, 'lastname' => $record->lastname, 'email' => $record->email, 'phonenumber' => $record->phonenumber, 'reason' => $request->reason, 'created_at' => now(), 'updated_at' => now() ]); // 按ID删除原访客表记录,不要调用查询结果对象的delete方法 DB::table('visitors')->where('id', $id)->delete(); // 替换为你实际的访客列表路由地址 return redirect()->route('visitor.visitorlist')->with('status', '访客已成功加入观察名单'); }
2. 修正视图层代码
删除卡片头部多余的全局「Add to watchlist」按钮,将表格tbody部分和模态框替换为以下内容(每条记录对应独立操作按钮和模态框,避免ID传值错误):
<tbody> @foreach($visitor as $item) <tr> <td><input class="form-check-input visitor-check" type="checkbox" value="{{ $item->id }}" id="flexCheckDefault{{$item->id}}"></td> <td>{{ $item->id}}</td> <td>{{ $item->firstname}}</td> <td>{{ $item->lastname}}</td> <td>{{ $item->email}}</td> <td>{{ $item->phonenumber}}</td> <td> <button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#exampleModal{{$item->id}}"> Add to watchlist </button> </td> </tr> <!-- 单条记录对应模态框 --> <form action="{{ url('addtowatch/'.$item->id) }}" method="POST"> @csrf <div class="modal fade" id="exampleModal{{$item->id}}" tabindex="-1" aria-labelledby="exampleModalLabel{{$item->id}}" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel{{$item->id}}">加入观察名单</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <label for="reason{{$item->id}}"> 请输入加入观察名单的原因</label> <!-- 删除多余name属性,去掉空格 --> <input type="text" name="reason" id="reason{{$item->id}}" class="form-control" required> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button> <button type="submit" class="btn btn-primary">确认提交</button> </div> </div> </div> </div> </form> @endforeach </tbody>
3. 路由确认
确认路由文件中已正确注册POST路由,如果访客列表路由没有设置visitor.visitorlist命名,将控制器里的重定向代码改为实际访问路径即可,例如return redirect('/visitor-list')。
三、后续优化建议
- 如果需要实现勾选多条数据批量加入观察名单,可以给全局按钮加JS监听,获取所有选中复选框的ID,提交时把ID数组传给后端做批量处理
- 建议为两张数据表创建对应的Eloquent模型,相比直接用DB门面操作更便捷,也不会出现调用delete()方法报错的问题
- 数据写入时记得补全created_at、updated_at时间字段,避免数据库时间字段出现空值
内容的提问来源于stack exchange,提问作者JUSTIN CHUA
相关产品推荐
相关产品推荐

