Laravel 9 Livewire报错:尝试读取数组的id属性问题排查
问题解决:Laravel 9 Livewire "attempt to read property 'id' on array" 错误
核心问题分析
- 对象与数组访问混用:代码中同时使用对象属性访问(
->)和数组索引访问([])处理查询结果,导致类型不一致报错。 - 属性类型不统一:
$polyclinics初始化为空数组,但后续赋值为Eloquent Collection对象,Livewire渲染时类型冲突触发错误。 - SQL硬编码参数:
loadSchedule中直接拼接$id到SQL语句,存在注入风险且可能导致语法异常。 - dd调试的误导:
dd()会终止代码执行,掩盖了后续可能的类型转换问题,移除后错误显现。
具体修复步骤
1. 统一查询结果的访问方式
在addItem方法中,Service::get()返回的是Eloquent Collection,元素为Model对象,需用对象属性访问:
public function addItem($id) { $BPJS = "Bpjs"; $this->stateService = Service::where('id', $id)->get(); // 修复对象属性访问,替换数组索引 if ($this->stateService[0]->clinic == 1) { if (stripos($this->stateService[0]->name, $BPJS)) { $this->isBPJS = 1; $this->loadPolyClinic($this->isBPJS); } else { $this->isBPJS = 0; $this->loadPolyClinic($this->isBPJS); } } else { $this->loadPolyClinic(); } }
2. 统一属性类型为Collection
初始化$polyclinics为Eloquent Collection,避免数组与对象的类型冲突:
// 组件属性初始化 public $state, $stateService, $schedules, $polyclinics; public function mount($id) { if ($id !== null) { $this->state = MonitorGetQueueItem::where('id', $id)->get(); $this->monitorId = $id; $this->schedules = collect(); $this->polyclinics = collect(); // 初始化为空Collection } else { $this->state = collect(); $this->schedules = collect(); $this->polyclinics = collect(); } } // 修改loadPolyClinic的空值处理 public function loadPolyClinic($isBPJS = null) { if ($isBPJS !== null) { // 原查询逻辑不变 } else { $this->polyclinics = collect(); // 设为空Collection而非数组 } }
3. 修复SQL查询的参数绑定
重构loadSchedule中的查询,使用参数绑定替代硬编码,避免注入风险:
public function loadSchedule($id = null) { if ($id) { $this->schedules = DB::connection("sqlsrv2") ->table(DB::raw("(SELECT rtds.id AS schedule_id, mmmp.full_name, mmp.name as polyclinic, CASE WHEN rtds.bpjs_starttime-CAST(LTRIM(DATEDIFF(MINUTE, 0, CONVERT(VARCHAR(5),GETDATE(),108))) AS INT) <= 120 THEN 1 ELSE 0 END AS isStart, CASE WHEN rtds.bpjs_starttime = 0 THEN 1 ELSE 0 END AS isBpjs, RIGHT('0' + CAST(rtds.cash_startime / 60 AS VARCHAR),2) + ':' + RIGHT('0' + CAST(rtds.cash_startime % 60 AS VARCHAR),2) as [CashStart], RIGHT('0' + CAST(rtds.cash_endtime / 60 AS VARCHAR),2) + ':' + RIGHT('0' + CAST(rtds.cash_endtime % 60 AS VARCHAR),2) as [CashEnd], RIGHT('0' + CAST(rtds.insurance_starttime / 60 AS VARCHAR),2) + ':' + RIGHT('0' + CAST(rtds.insurance_starttime % 60 AS VARCHAR),2) as [InsuranceStart], RIGHT('0' + CAST(rtds.insuranace_endtime / 60 AS VARCHAR),2) + ':' + RIGHT('0' + CAST(rtds.insuranace_endtime % 60 AS VARCHAR),2) as [InsuranceEnd], RIGHT('0' + CAST(rtds.bpjs_starttime / 60 AS VARCHAR),2) + ':' + RIGHT('0' + CAST(rtds.bpjs_starttime % 60 AS VARCHAR),2) as [BpjsStart], RIGHT('0' + CAST(rtds.bpjs_endtime / 60 AS VARCHAR),2) + ':' + RIGHT('0' + CAST(rtds.bpjs_endtime % 60 AS VARCHAR),2) as [BpjsEnd], rtds.cash_allocated_offline_quota + rtds.insurance_allocated_offline_quota AS totalOffNb, rtds.cash_used_offline_quota + rtds.insurance_used_offline_quota AS usedOffNb, rtds.bpjs_allocated_offline_quota AS totalOffB, rtds.bpjs_used_offline_quota AS usedOffB, rtds.cash_allocated_offline_quota + rtds.insurance_allocated_offline_quota + rtds.bpjs_allocated_offline_quota AS totalOff, rtds.cash_used_offline_quota + rtds.insurance_used_offline_quota + rtds.bpjs_used_offline_quota AS usedOff FROM reg_txn_doctor_schedule AS rtds LEFT OUTER JOIN mktg_mst_med_pract AS mmmp ON mmmp.id = rtds.doctor_id LEFT OUTER JOIN mktg_mst_clinic AS mmc ON mmc.id = rtds.clinic_id LEFT OUTER JOIN mktg_mst_polyclinic AS mmp ON mmp.id = mmc.polyclinic_id WHERE CONVERT(DATE,rtds.[date]) = CONVERT(DATE,GETDATE()) AND rtds.[disabled] = 0 AND rtds.inactive = 0) as b")) ->where('b.polyclinic_id', $id) // 移到外部用参数绑定 ->orderByRaw('b.CashStart ASC,b.CashEnd ASC') ->get(); } else { $this->schedules = collect(); } }
4. 保持视图中属性访问一致
视图中继续使用$polyclinic->id和$polyclinic->name,因为现在$polyclinics始终是Collection对象:
@foreach ($polyclinics as $polyclinic) <tr> <td wire:click="addSchedule({{ $polyclinic->id }})"> <h6 class="fs--1">{{ $polyclinic->name }}</h6> </td> </tr> @endforeach
额外优化建议
- 删除
mount中无效代码:$this->state->toArray();未赋值给变量,无实际作用,可直接移除。 - 添加空值判断:在视图遍历
$polyclinics和$schedules前增加@empty分支,避免空集合导致的渲染异常。
内容的提问来源于stack exchange,提问作者J S
相关产品推荐
相关产品推荐

