---
alwaysApply: true
---
# AI PHP 开发编码规范

本项目 PHP 开发必须严格遵循以下规范，所有代码编写、审查、修改均需遵守。

## 八荣八耻
以瞎猜接口为耻，以认真查询为荣。
以模糊执行为耻，以寻求确认为荣。
以臆想业务为耻，以人类确认为荣。
以创造接口为耻，以复用现有为荣。
以跳过验证为耻，以主动测试为荣。
以破坏架构为耻，以遵循规范为荣。
以假装理解为耻，以诚实无知为荣。
以盲目修改为耻，以谨慎重构为荣

---

## 0. 全局框架保护（最高优先级）

**原则：应用开发或调整时，禁止修改应用外的全局框架代码，确需修改时必须先说明原因并征得确认。**

### 开发文档规范

**原则：涉及应用的开发必须基于开发文档，确保对系统架构和应用机制的充分理解。**

#### 应用开发文档要求

- **应用开发前**，必须深度熟悉并了解 `docs/CmsPro-v5-应用开发文档.md`，该文档包含了应用开发的完整规范（目录结构、命名空间、数据库隔离、视图、钩子系统、安装卸载流程等）
- **应用视图开发与调整**，必须遵守 `docs/应用视图规范.md` 规范（后台列表页/表单页布局、Layui 模板 `@verbatim` 包裹、公共资源引用等）
- **关联应用开发时**，需阅读了解对应应用目录下的 `doc` 文档（如 `app/Apps/{AppName}/doc/`，即该应用的文档），理解目标应用的功能结构、扩展点和集成方式
- **应用调整时**，对已有应用做出修改后，必须同步检查该应用目录 `doc/` 下对应的文档是否需要更新，确保文档与代码保持一致
- 违反上述规范导致的返工或质量问题，由开发者承担相应责任

### 保护范围

以下目录和文件属于全局框架范畴，**禁止**在应用开发过程中随意修改：

| 类别 | 路径 | 说明 |
|------|------|------|
| 框架核心 | `vendor/laravel/framework/` | Laravel 框架源码 |
| 框架核心 | `vendor/` 下其他第三方依赖 | Composer 安装的第三方包 |
| 系统基础配置 | `config/app.php`、`config/auth.php`、`config/database.php` 等 | 全局系统配置 |
| 系统核心类 | `app/Console/`、`app/Exceptions/`、`app/Providers/`（非应用级） | 系统级核心类 |
| 公共路由 | `routes/` 下的系统路由文件（非应用路由） | 全局路由定义 |
| 公共中间件 | `app/Http/Middleware/` 下的系统中间件 | 全局中间件 |

> **应用级代码**指 `app/Apps/{AppName}/` 目录下的专属代码，不在本规则限制范围内。

### 违规示例

```
❌ 直接修改 vendor/laravel/framework/src/Illuminate/... 下的源码
❌ 修改 config/database.php 的默认数据库连接配置
❌ 在 routes/web.php 中添加应用专属路由
❌ 修改 app/Http/Kernel.php 注入全局中间件
```

### 正确做法

- 应用功能通过 **应用模块** (`app/Apps/{AppName}/`) 实现，不侵入框架层
- 需要扩展框架行为时，优先使用 Laravel 提供的 **扩展机制**（Service Provider、Macro、Event 等）
- 如确实需要修改全局框架代码，**必须提前说明**：
  1. 修改的具体文件和位置
  2. 修改的原因和业务背景
  3. 修改的影响范围评估
  4. 是否有替代方案及为何不可行

### 审批流程

1. 开发者发现需修改全局框架 → 停止操作
2. 提交修改申请（含上述四项说明）
3. 获得确认后方可执行修改
4. 修改后必须在代码注释中标注修改原因和审批记录

---

## 1. 日期时间处理

**原则：数据库中的日期字段直接读取输出，禁止二次格式化加工。**

### 正确格式

```
2026-05-23 15:29:13
```

### 禁止格式

```
2026-05-23T00:16:39.000000Z    // ISO 8601 带时区格式（Laravel 默认序列化格式）
2026-05-23T00:16:39+08:00      // ISO 8601 带偏移格式
May 23, 2026 3:29 PM           // 英文可读格式
```

### 实现方式

**Eloquent 模型层统一处理**，在 Model 中配置 `$casts` 或重写 `serializeDate()`：

```php
// 方案一：使用 $casts 将日期转为字符串（推荐）
protected $casts = [
    'created_at' => 'datetime:Y-m-d H:i:s',
    'updated_at' => 'datetime:Y-m-d H:i:s',
];

// 方案二：重写 serializeDate 方法（全局生效）
protected function serializeDate(DateTimeInterface $date): string
{
    return $date->format('Y-m-d H:i:s');
}
```

### 注意事项

- **禁止**在 Controller / Service 层对已从模型取出的日期字段再次调用 `format()` 方法
- **禁止**在前端视图或 API 响应中对日期做二次格式化
- **禁止**使用 Laravel 默认的 ISO 8601 序列化格式返回给前端
- 数据库存储什么格式，API/页面就展示什么格式（`Y-m-d H:i:s`）
- 新建模型时必须包含上述日期格式化配置

### 外部 ISO 8601 日期写入数据库

第三方 API（微信支付、支付宝等）返回的日期字段通常为 ISO 8601 格式（如 `2026-05-23T00:16:39+08:00`），**禁止直接赋值给 Eloquent 模型的日期字段**，MySQL 的 `datetime` 列不接受此格式，会抛出 `Invalid datetime format` 异常。

**必须**在写入数据库前，将 ISO 8601 字符串解析为 `Y-m-d H:i:s` 格式：

```php
// 正确：解析外部 ISO 8601 日期后写入
$paidAt = $result['paid_at'] ?? now();
if (is_string($paidAt)) {
    try {
        $paidAt = \Carbon\Carbon::parse($paidAt)->format('Y-m-d H:i:s');
    } catch (\Throwable $e) {
        $paidAt = now()->format('Y-m-d H:i:s');
    }
}
$order->update(['paid_at' => $paidAt]);

// 错误：直接将 ISO 8601 字符串写入数据库
$order->update(['paid_at' => $result['paid_at']]);  // 2026-05-23T00:16:39+08:00 → MySQL 报错
```

**适用场景**：
- 支付渠道回调/查询返回的 `paid_at`、`success_time` 等字段
- 任何第三方 API 返回的日期时间字段
- 手动构建 JSON 响应时，Carbon 对象必须显式 `format('Y-m-d H:i:s')`，不可直接放入 `response()->json()`

**不适用场景**：
- 从 Eloquent 模型取出的日期字段（已通过 `$casts` 或 `serializeDate()` 自动格式化，直接使用即可）
- `now()` 赋值给 Eloquent 模型时（Eloquent 自动处理 Carbon → MySQL datetime）