合并多个Eloquent模型:以最新模型为基准填充空属性
优雅聚合Eloquent模型:以最新模型为基准填充非空属性
针对你需要合并多个Eloquent模型,用旧模型的非空数据填充最新模型空属性的需求,这里有几个比逐个遍历属性更高效的方案,完全贴合Laravel的Eloquent生态:
方法1:集合遍历+fill()批量填充
先获取所有需要合并的模型并按创建时间倒序排列(确保最新的模型在最前面),然后以它为基准,依次用其他模型的非空属性填充:
// 假设你的模型是User,先获取目标模型并按创建时间倒序 $models = User::whereIn('id', [1, 2, 5])->orderBy('created_at', 'desc')->get(); // 复制最新模型作为合并基准(避免修改原模型) $mergedModel = $models->first()->replicate(); // 遍历剩余模型,填充非空属性 $models->slice(1)->each(function ($model) use ($mergedModel) { // 筛选当前模型的非空属性,且只保留基准模型允许填充的字段 $fillableData = collect($model->getAttributes()) ->filter(fn ($value) => !is_null($value) && $value !== '') ->only($mergedModel->getFillable()) ->toArray(); // 用fill()批量填充,自动遵守fillable规则,安全可靠 $mergedModel->fill($fillableData); }); // 现在$mergedModel就是你要的合并结果
方法2:自定义模型方法,复用合并逻辑
如果需要多次进行这类合并操作,可以在你的Eloquent模型里封装一个mergeWith()方法,让代码更整洁:
// 在你的模型类(比如User.php)中添加方法 public function mergeWith(self $otherModel): self { $merged = $this->replicate(); $fillableData = collect($otherModel->getAttributes()) ->filter(fn ($value) => !is_null($value) && $value !== '') ->only($this->getFillable()) ->toArray(); $merged->fill($fillableData); return $merged; } // 使用示例: $latestModel = User::find(5); $olderModel1 = User::find(2); $olderModel2 = User::find(1); // 链式调用合并多个模型 $mergedModel = $latestModel->mergeWith($olderModel1)->mergeWith($olderModel2);
方法3:用集合reduce()一次性完成合并
利用Laravel集合的reduce()方法,可以更简洁地完成多模型的迭代合并:
$models = User::whereIn('id', [1, 2, 5])->orderBy('created_at', 'desc')->get(); $mergedModel = $models->reduce(function ($carry, $model) { // 第一次迭代时,把最新模型作为初始值 if (is_null($carry)) { return $model->replicate(); } // 筛选非空属性并填充 $fillableData = collect($model->getAttributes()) ->filter(fn ($value) => !is_null($value) && $value !== '') ->only($carry->getFillable()) ->toArray(); $carry->fill($fillableData); return $carry; });
注意事项
- 上述代码中的
filter()逻辑是过滤null和空字符串,如果你需要处理其他“空”情况(比如0、false),可以根据业务需求调整过滤条件。 - 使用
getFillable()确保只填充模型允许批量赋值的字段,避免安全风险;如果你的模型设置了$guarded = [](允许所有字段填充),可以去掉only($mergedModel->getFillable())这一步。 replicate()方法会复制模型的所有属性和关联(如果需要的话),如果不需要关联,可以用replicate([])。
内容的提问来源于stack exchange,提问作者stUrb
相关产品推荐
相关产品推荐

