Laravel递归获取单条模型记录含关联模型的全部$fillable数据
递归获取模型及其关联的全部$fillable数据
我来给你捋捋怎么解决这个问题——在Laravel框架下,要实现根据模型ID获取记录的全部$fillable数据,同时递归获取所有关联模型的$fillable内容,我们可以通过反射识别关联关系+递归遍历处理的方式来实现,下面是具体的方案:
核心思路
- 先获取目标模型实例的
$fillable字段对应的数据,用模型的only()方法配合getFillable()公共方法即可安全获取(不用直接访问protected属性)。 - 通过反射机制识别模型中定义的所有关联方法(比如
hasMany、belongsTo等返回Relation实例的方法)。 - 预加载所有关联数据避免N+1查询问题,然后递归处理每个关联模型的
$fillable数据。 - 合并当前模型数据与所有关联的递归数据,最终返回完整结构。
完整实现代码
辅助函数定义
function getFillableWithRelations($model, $maxDepth = 5) { // 达到最大递归深度时,仅返回当前模型的fillable数据 if ($maxDepth <= 0) { return $model->only($model->getFillable()); } // 第一步:收集当前模型的所有关联关系名称 $relationNames = []; $reflection = new ReflectionClass($model); $publicMethods = $reflection->getMethods(ReflectionMethod::IS_PUBLIC); foreach ($publicMethods as $method) { // 排除模型自带的核心方法,避免误判 $excludedMethods = ['__construct', 'save', 'create', 'update', 'delete', 'fresh', 'refresh']; if (in_array($method->getName(), $excludedMethods)) { continue; } try { // 调用方法判断是否为关联关系 $relationInstance = $method->invoke($model); if ($relationInstance instanceof \Illuminate\Database\Eloquent\Relations\Relation) { $relationNames[] = $method->getName(); } } catch (\Exception $e) { // 跳过需要参数的方法(非关联方法) continue; } } // 第二步:预加载所有关联,避免N+1查询问题 $model = $model->load($relationNames); // 第三步:获取当前模型的fillable数据 $result = $model->only($model->getFillable()); // 第四步:递归处理每个关联模型 foreach ($relationNames as $relationName) { $relatedData = $model->{$relationName}; if ($relatedData instanceof \Illuminate\Database\Eloquent\Collection) { // 关联是集合(一对多/多对多),遍历每个实例递归处理 $result[$relationName] = array_map(function ($item) use ($maxDepth) { return getFillableWithRelations($item, $maxDepth - 1); }, $relatedData->all()); } elseif ($relatedData instanceof \Illuminate\Database\Eloquent\Model) { // 关联是单个模型(一对一/属于),直接递归处理 $result[$relationName] = getFillableWithRelations($relatedData, $maxDepth - 1); } } return $result; }
使用示例
假设你有User模型,关联了Post模型,Post又关联了Comment模型,要获取ID为1的用户的所有层级$fillable数据:
// 获取目标模型实例 $user = \App\Models\User::findOrFail(1); // 调用函数获取完整数据 $fullFillableData = getFillableWithRelations($user); // 输出查看结果 dd($fullFillableData);
关键注意事项
- 避免无限递归:函数中加入了
$maxDepth参数,默认限制最大递归深度为5,防止出现模型互相关联导致的死循环。你可以根据业务需求调整这个值。 - 兼容多态关联:因为只要是返回
Relation实例的关联方法都会被识别,所以多态关联(比如morphTo、morphMany)也能正常处理。 - 跳过带参数的方法:如果模型中有需要参数的公共方法,会被自动跳过,不会影响关联识别。
- 依赖反射机制:反射是PHP的核心功能,无需额外扩展支持,兼容性良好。
内容的提问来源于stack exchange,提问作者Shardj
相关产品推荐
相关产品推荐

