2016-10-19 3 views
5

Laravel 5.3.Laravel. Как найти модели, которые имеют конкретную последнюю связанную модель

Модель пакета имеет много ступенчатых моделей. В шаговой модели есть столбец с номерами status, тип которых крошечный int и created_at. Например, пакет A, имеет следующие этапы:

  • 18 октября 10:00, статус 1
  • 19 октября 09:00, статус 2

И, пакет B , имеет следующие этапы:

  • 19 октября 08:00, статус 1
  • 19 октября 09:00, статус 2
  • 19 октября 10:00, статус 3

Так же, как это, многие пакеты, каждый из них имеет много шагов.

A «s последние статус шага составляет 2 и B» s является 3

Моя проблема в том, как найти пакеты которых последний шаг статус 2? Ожидаемый результат - набор пакетов, в этом примере должен содержать A.

Я пробовал добавить это в свою модель упаковки.

public function steps() 
{ 
    return $this->hasMany('App\Step'); 
} 

public function status() 
{ 
    return $this->steps()->latest()->limit(1); 
} 

и запрос с

Package::whereHas('status', function ($q) { 
    $q->where('status', 2); 
})->get(); 

, но не может получить ожидаемый результат.

Что не ожидалось, если в таблице пакетов есть только 1 строка, пакет B, ожидаемый результат - пустая коллекция. Но он возвращает коллекцию, содержащую B.

Я также попытался обновлению статусной функции в пакете модели для

public function status() 
{ 
    return $this->hasOne('App\Step')->latest(); 
} 

, но она по-прежнему не работает.

Итак, каков правильный путь? Огромное спасибо вам.

+1

Я думаю, что вы близки, вы должны попытаться добавить whereDoesntHave статус> 2 на ваш запрос ... Если у вас нет других ответов, я попробую сегодня вечером – Hammerbot

ответ

0

Это довольно сложно. Я не мог придумать решение, которое вы можете достичь, чего хотите, выполнив один запрос Eloquent. Однако я нашел способ, который дает результат в два этапа - i.e. query + filter.

Но перед тем, что вам нужно, чтобы добавить область к вашей Package модели:

public function scopeOfStatus($query, $status) 
{ 
    return $query->whereHas('steps', function($q) use ($status) 
    { 
     $q->where('status', $status); 
    }); 
} 

Шаг 1: Напишите запрос, который извлекает все пакеты, по крайней мере, один шаг, удовлетворяющие заданным критериям данный статус:

$status = 1; 
$packages = Package::with('steps')->ofStatus($status)->get(); 

Шаг 2: Отфильтровать результаты, чтобы получить только пакеты, которые соответствуют их последнему шагу:

$packages = $packages->filter(function($package) use ($status) 
{ 
    return $package->steps->last()->status == $status; 
}); 

Конечный результат представляет собой совокупность всех пакетов, их последний шаг имеет status == 1

+0

Я прочитал много ответов, все из которых сначала получают последний шаг всех пакетов, а затем фильтруют их. Из этого я думаю, что мне нужно получить результат более чем на один шаг. Итак, разумный выбор - добавить еще один столбец current_step_id, который ссылается на последний шаг в таблицу пакетов и обновляет его вручную при вставке нового шага, чтобы упростить этот запрос? –

+0

Это также возможно, но вы всегда должны помнить, что если во время процесса обновления вручную произошла ошибка, ваши данные становятся несовместимыми, то есть ссылаются на неверный последний шаг. –

0

попробовать это:

$wantedStatus = 2; 
$packages = Package::with(['steps', function($query){ 
    $query->latest(); 
}])->get(); 

$filtered = $packages->filter(function ($package) use ($wantedStatus) { 
    return $package->stpes->last()->status == $wantedStatus; 
}); 
Смежные вопросы