Студия разработки сайтов и приложений

Netspark.ru

Laravel и условия в отношениях с latestOfMany

В Ларавеле можно из отношения «один ко многим» сделать отношение «один к одному». Например, у нас есть модель 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, главное условие аггрегации описать.

Комментарии