vr-shopxo-plugin/plan.md

115 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Plan — DebugAgent: "Undefined array key 'id'" 调试计划
> 版本v1.0 | 日期2026-04-20 | Agentcouncil/DebugAgent
---
## 任务概述
调查 ShopXO 后台编辑票务商品goods_id=118保存时报错
```
Undefined array key "id"
```
---
## 根因分析摘要Round 1 快速结论)
### 1. 最可能触发点
**AdminGoodsSaveHandle.php 第 71 行**
```php
$template = Db::name('vr_seat_templates')->find($templateId);
$seatMap = json_decode($template['seat_map'] ?? '{}', true); // ← 危险
```
- `find()` 查不到记录时返回 `null`
- `??` 操作符只防御 `$template``null`**不防御** `$template` 存在但键 `'seat_map'` 缺失
- PHP 8+ 会报 `Undefined array key "seat_map"`,而非 "id"
**真正报 "id" 的位置**——第 77 行 `array_filter` 回调内:
```php
return in_array($r['id'], $config['selected_rooms'] ?? []);
// ^^^^^^ 如果 $rroom 对象)缺少 'id' 键则触发
```
但如果 room 数据正常(有 id则第 71 行是实际断路点。
### 2. 表前缀问题(核心根因)
| 代码 | 表名方法 | 实际 SQL 表 |
|------|---------|------------|
| `BaseService::table('seat_templates')` | `'vr_' + 'seat_templates'` | `vr_seat_templates` ✅ |
| `Db::name('vr_seat_templates')` | ThinkPHP `Db::name()` | 取决于 `database.php` 配置前缀 |
| `Db::name('Goods')` | ThinkPHP `Db::name()` | `sxo_goods`ShopXO 系统表) |
**ShopXO 数据库配置**(需确认 `shopxo/config/database.php`
-`prefix` = `'sxo_'`:则 `Db::name('vr_seat_templates')` → 查表 `sxo_vr_seat_templates`(不存在)
-`prefix` = `'vrt_'`:则 `Db::name('vr_seat_templates')` → 查表 `vrt_vr_seat_templates`(不存在)
- 正确表名应来自 ThinkPHP 原始前缀ShopXO 插件表一般不带前缀或用独立前缀)
**SeatSkuService 使用 `BaseService::table()` → `vr_seat_templates`(正确)**
**AdminGoodsSaveHandle 使用 `Db::name('vr_seat_templates')` → 可能查错表(错误)**
### 3. 如果 `find($templateId)` 返回 null
第 71 行:`$template['seat_map']` → `Undefined array key 'seat_map'`(不是 'id'
第 72 行:`$allRooms = $seatMap['rooms'] ?? [];` → 此行安全(`??` 防御)
### 4. vr_goods_config JSON 解码
```php
$configs = json_decode($rawConfig, true); // → array|null
if (is_array($configs) && !empty($configs)) { ... } // 防御正确
```
`$configs` 是数组时 `$config['template_id']` 访问安全(不会触发 "id" 错误)。
### 5. selected_rooms 数据类型
- `selected_rooms`: `string[]`room id 数组e.g. `["room_id_xxx"]`
- `$r['id']`: 来自 `seat_map.rooms[].id`,通常是字符串
- 类型匹配:无类型强制问题,但若 `room.id``null` 或缺失则触发 "id"
### 6. $data['item_type'] 访问安全
第 59 行:`($data['item_type'] ?? '') === 'ticket'` — 有 `??` 防御,安全。
---
## 任务清单Round 2 执行)
- [ ] **Task 1**: 读取 `shopxo/config/database.php`,确认 `prefix` 配置值
- [ ] **Task 2**: 读取 `AdminGoodsSaveHandle.php` 第 70-72 行,确认 `$template` 为 null 时实际报错信息
- [ ] **Task 3**: 确认 ShopXO `Db::name()` 表前缀行为(查 ShopXO 源码或文档)
- [ ] **Task 4**: 编写根因报告 `reports/DebugAgent-ROOT_CAUSE.md`
- [ ] **Task 5**: 给出修复建议(用 `BaseService::table()` 替代 `Db::name()`
---
## 阶段划分
| 阶段 | 内容 | 状态 |
|------|------|------|
| **Draft** | Round 1代码静态分析定位可疑行 | ✅ 完成 |
| **Review** | Round 2读取配置文件确认表前缀输出根因报告 | 待做 |
| **Finalize** | Round 3合并报告到 main提交调试结论 | 待做 |
---
## 依赖
- Task 1-3 必须按顺序执行(需读取配置文件)
- 不需要 BackendArchitect / SecurityEngineer 配合,可独立完成
---
## 执行顺序
Task 1 → Task 2 → Task 3串行每步确认后立即 commit→ Task 4 → Task 5
---
## 声称
- [Claimed: council/DebugAgent] — Task 1-5 全部