return 模型的类似作用域的函数

Scope-like function to return Model

的答案解释说,模型范围并不意味着 return 除了查询生成器实例和自定义 getter 应该用于 return 模型实例。

问题

在我的例子中,我有一个 UserContract 模型,其中一个用户有很多合同。合同期限可能重叠,但在任何给定时间,只有具有最晚开始日期的合同才应被视为有效(例如,给定合同 1 从 2017-01-012017-07-31 和合同 2 从 2017-06-012017-12-31,对于 2017-07-01 合同 2 应 returned)

当前解

使用范围我总是要调用 ->first():

public function scopeByDate(Builder $query, $date) {
    return $query->whereDate('start', '<=', $date)
                 ->whereDate('end', '>=', $date)
                 ->orderBy('start', 'desc');
}
public function scopeCurrent(Builder $query) {
    return $this->scopeByDate($query, date('Y-m-d'));
}
...
$user->contracts()->byDate('some-date')->first();
$user->contracts()->current()->first();

(更糟?)替代解决方案

否则我可以使 byDate()current() 静态,接受 Builder(对我来说看起来很糟糕)或 User(甚至更糟?)实例和手动传递参数 like

public static function byDate(Builder $query, $date) {
    return $query->whereDate(...)->whereDate(...)->orderBy(...)->first();
}
...
Contract::byDate($user->contracts(), 'some-date');

public static function byUserAndDate(User $user, $date) {
    return $user->contracts()->where...->where...->orderBy(...)->first()
}
...
Contract::byUserAndDate($user, 'some-date');

问题

有没有什么方法可以直接在查询构建器(关系)上调用 byDate()current(),比如范围,而不传递额外的参数和 return 模型实例而不是构建器并且每次都必须调用 first()

对于您的情况,您可以将逻辑包装在 User 模型的方法中,然后在需要时调用它而不需要 ->first() :

用户模型

public function currentContract() { 
    return $this->contracts()->current()->first(); 
}

public function contractByDate($date) { 
    return $this->contracts()->byDate($date)->first(); 
}

电话:

$user->contractByDate('some-date');
$user->currentContract();

干净整洁:)