
本文详解如何在 Laravel 自定义仓库类中实现类似 Eloquent 的链式调用(如 where()->get()),核心在于复用查询构建器实例而非静态模型调用,避免每次调用都重置查询上下文。
本文详解如何在 laravel 自定义仓库类中实现类似 eloquent 的链式调用(如 `where()->get()`),核心在于复用查询构建器实例而非静态模型调用,避免每次调用都重置查询上下文。
在 Laravel 中,auth()->user()->where(...)->get() 这类链式调用之所以能正常工作,是因为 Eloquent 的每个查询方法(如 where、orderBy、limit)都返回同一个 Builder 实例,从而支持持续追加约束;最终调用 get() 时,才真正执行已累积全部条件的查询。
而你在 SkillKeyRepository 中的原始实现存在一个关键误区:所有方法均直接调用 $this->model::where(...) 或 $this->model::get() —— 这属于静态调用模型类本身,每次都会创建全新的查询上下文,导致 where() 的调用被完全忽略,get() 实际执行的是无任何条件的全表查询。
✅ 正确做法是:在构造函数中初始化一次查询构建器($model->newQuery()),并将该 Builder 实例作为状态持久化在仓库对象中。后续所有查询方法均操作该同一实例:
class SkillKeyRepository
{
protected $query;
public function __construct(SkillKey $model)
{
// ✅ 关键:获取可链式操作的 Builder 实例,而非模型类
$this->query = $model->newQuery();
}
public function where($column, $value): self
{
// ✅ 在同一 Builder 上追加 where 条件
$this->query->where($column, $value);
return $this;
}
public function get(): Collection
{
// ✅ 执行当前 Builder 已累积的所有条件
return $this->query->get();
}
public function all(array $columns = ['*']): Collection
{
// ⚠️ 注意:all() 不应覆盖已有查询条件,建议移除或重命名为 freshAll()
return $this->query->get($columns);
}
}
? 补充说明:Model::where() 是静态代理,内部仍会调用 newQuery()->where();但若你反复调用 Model::where(),每次都是新 Builder,无法链式累积。因此必须显式持有并复用同一个 Builder 实例。
此外,在服务层调用时也需确保逻辑连贯:
class SkillKeyService
{
public function __construct(protected SkillKeyRepository $repository) {}
public function getTagNames(): Collection
{
// ✅ 此处将正确返回 key = 'TagName' 的记录集合
return $this->repository->where('key', 'TagName')->get();
}
}
? 注意事项总结:
- ❌ 避免在仓库方法中使用 Model::xxx() 静态调用(除非明确需要全新查询);
- ✅ 始终基于单个 Builder 实例进行链式构建;
- ? 若需支持多种查询路径(如带条件的 get() 和无条件的 all()),建议将 all() 设计为重置查询(newQuery()->get()),或另提供 fresh() 方法;
- ? 进阶可添加 select()、orderBy()、paginate() 等方法,统一操作 $this->query,保持接口与 Eloquent 高度一致。
掌握这一模式,你就能在自定义仓库、服务或 DSL 层中,优雅复刻 Laravel 强大的流畅式查询体验。











