В Ларавеле можно из отношения «один ко многим» сделать отношение «один к одному». Например, у нас есть модель Monitor
, у которой может быть много дочерних моделей MonitorCheck
:
class Monitor extends Model
{
/**
* Monitor can have many checks
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function checks() {
return $this->hasMany(MonitorCheck::class);
}
}
тогда мы можем объявить отношение для получения последней модели MonitorCheck
так:
/**
* Monitor has a last check
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function lastCheck() {
return $this->checks()->one()->latestOfMany();
}
Однако если мы захотим объявить отношение для последней модели с условием, так сделать не получится. Допустим, мы хотим последнюю модель MonitorCheck
с проваленным тестом.
public function lastFailedCheck() {
return $this->checks()->where('passed', '=', FALSE)->one()->latestOfMany();
}
Такой вариант не сработает, будет возвращать null
. Причем, если убрать latestOfMany()
, то отношение будет работать и вернет MonitorCheck с проваленным тестом, только не последний. А с latestOfMany()
не будет работать, запрос будет составляться неправильно (точнее, не так, как мы хотели бы).
А правильно объявлять данное отношение так:
public function lastFailedCheck() {
return $this->hasOne(MonitorCheck::class)->OfMany(
['id' => 'max'],
function (Builder $query) {
$query->>where('passed', '=', FALSE);
}
);
}
Вместо id
в ['id' => 'max']
можно использовать и другие поля, например, created_at
, главное условие аггрегации описать.