30日1845-修复技能使用记录时间格式错误.md 5.5 KB

修复FarmUserSummaryController中技能使用记录时间格式错误

任务描述

修复在显示技能使用记录时,used_at字段调用format方法失败的错误

错误分析

错误信息

Call to a member function format() on string in FarmUserSummaryController.php:1062

错误原因

getRecentSkillUsageSection方法中,代码假设$log->used_at是Carbon对象,直接调用format()方法:

$usedAt = $log->used_at->format('Y-m-d H:i:s');

但实际上,used_at字段可能是字符串类型,导致调用format()方法失败。

根本原因

  1. 模型配置问题PetSkillLog模型中使用了过时的$dates属性
  2. 类型不一致:数据库中的时间字段没有被正确转换为Carbon对象
  3. 缺少安全检查:代码没有检查字段类型就直接调用方法

解决方案

1. 修复模型配置

更新PetSkillLog模型

将过时的$dates属性改为现代的$casts属性:

// 修改前
protected $dates = [
    'used_at',
    'created_at',
];

protected $casts = [
    'pet_id' => 'integer',
    'skill_id' => 'integer',
    'effect_result' => 'json',
];

// 修改后
protected $casts = [
    'pet_id' => 'integer',
    'skill_id' => 'integer',
    'used_at' => 'datetime',
    'created_at' => 'datetime',
    'effect_result' => 'json',
];

2. 增加安全的时间处理

正常情况下的时间处理

// 安全处理时间格式
$usedAt = '未知时间';
if ($log->used_at) {
    try {
        if ($log->used_at instanceof \Carbon\Carbon) {
            $usedAt = $log->used_at->format('Y-m-d H:i:s');
        } else {
            // 尝试解析字符串时间
            $usedAt = date('Y-m-d H:i:s', strtotime($log->used_at));
        }
    } catch (\Exception $e) {
        $usedAt = (string) $log->used_at;
    }
}

异常情况下的时间处理

} catch (\Throwable $e) {
    // 如果出现异常,添加一个错误行
    $usedAtDisplay = '未知';
    if ($log->used_at) {
        try {
            if ($log->used_at instanceof \Carbon\Carbon) {
                $usedAtDisplay = $log->used_at->format('Y-m-d H:i:s');
            } else {
                $usedAtDisplay = (string) $log->used_at;
            }
        } catch (\Exception $e) {
            $usedAtDisplay = '时间格式错误';
        }
    }
    
    $rows[] = [
        $usedAtDisplay,
        // ... 其他字段
    ];
}

修改内容

修改文件

  1. app/Module/Pet/Models/PetSkillLog.php - 更新模型配置
  2. app/Module/Game/AdminControllers/FarmUserSummaryController.php - 增加安全的时间处理

具体修改

1. PetSkillLog模型修改

  • 移除过时的$dates属性
  • $casts中添加used_atcreated_at的datetime转换
  • 确保时间字段被正确转换为Carbon对象

2. FarmUserSummaryController修改

  • 在正常处理流程中增加类型检查
  • 在异常处理流程中增加安全的时间格式化
  • 提供多层次的降级处理机制

技术细节

1. Laravel时间字段处理演进

旧版本($dates属性)

protected $dates = ['used_at', 'created_at'];

新版本($casts属性)

protected $casts = [
    'used_at' => 'datetime',
    'created_at' => 'datetime',
];

2. 类型安全检查

if ($log->used_at instanceof \Carbon\Carbon) {
    // Carbon对象,可以安全调用format方法
    $usedAt = $log->used_at->format('Y-m-d H:i:s');
} else {
    // 字符串或其他类型,使用PHP原生函数处理
    $usedAt = date('Y-m-d H:i:s', strtotime($log->used_at));
}

3. 多层次异常处理

  1. 第一层:检查字段是否存在
  2. 第二层:检查字段类型并选择合适的处理方法
  3. 第三层:捕获处理过程中的异常
  4. 第四层:提供最终的降级显示

防护机制

1. 类型检查

  • 使用instanceof检查对象类型
  • 避免在非Carbon对象上调用Carbon方法

2. 异常捕获

  • 使用try-catch包装可能失败的操作
  • 提供有意义的错误信息

3. 降级处理

  • 当理想处理失败时,提供备选方案
  • 确保在任何情况下都能显示基本信息

4. 数据验证

  • 检查数据是否存在
  • 验证数据格式的有效性

测试建议

1. 数据类型测试

  • 测试Carbon对象的时间字段
  • 测试字符串类型的时间字段
  • 测试null或空值的时间字段

2. 格式测试

  • 测试标准时间格式
  • 测试非标准时间格式
  • 测试无效时间格式

3. 异常测试

  • 模拟数据库返回异常数据
  • 测试模型关联失败的情况
  • 测试JSON解析失败的情况

预防措施

1. 模型规范

  • 统一使用$casts属性定义字段类型
  • 避免使用过时的$dates属性
  • 为所有时间字段明确指定类型

2. 代码规范

  • 在调用对象方法前进行类型检查
  • 使用try-catch包装可能失败的操作
  • 提供有意义的错误处理和降级机制

3. 测试覆盖

  • 为时间字段处理编写单元测试
  • 测试各种边界情况和异常情况
  • 确保代码在各种数据状态下都能正常工作

任务状态

✅ 已完成

相关文件

  • app/Module/Pet/Models/PetSkillLog.php - 宠物技能使用记录模型
  • app/Module/Game/AdminControllers/FarmUserSummaryController.php - 农场用户信息汇总控制器

影响范围

  • 修复了技能使用记录显示功能
  • 提高了系统的稳定性和容错能力
  • 为类似的时间字段处理提供了最佳实践参考