У меня есть 3 класса, связанных следующим образом:
Exhibitor
'- Bills
'- Tickets
Счета и билеты используют черту SoftDeletes, а в классе Exhibitor у меня есть это отношение:
public function tickets()
{
return $this->hasManyThrough(Ticket::class, Bill::class);
}
Мне нужно получить все билеты, включая удаленные (withTrashed), но это также должно включать все удаленные счета. Проблема в том, что withTrashed применяется только к модели Tickets, а не к Bills.
Этот запрос
$tickets = exhibitor()->tickets()->withTrashed()
->where('bills.updated_at', '>=', Carbon::parse($since))
->orderBy('tickets.id')
->get();
Генерирует этот SQL
select `tickets`.*, `bills`.`exhibitor_id` from `tickets`
inner join `bills` on `bills`.`id` = `tickets`.`bill_id`
where `bills`.`deleted_at` is null
and `bills`.`exhibitor_id` = ?
and `bills`.`updated_at` >= ?
order by `tickets`.`id` asc
Принимая во внимание, что мне нужен этот SQL без «bills.deleted_at is null», например:
select `tickets`.*, `bills`.`exhibitor_id` from `tickets`
inner join `bills` on `bills`.`id` = `tickets`.`bill_id`
where `bills`.`exhibitor_id` = ?
and `bills`.`updated_at` >= ?
order by `tickets`.`id` asc
Но я не вижу никаких вариантов, где я могу установить withTrashed() для модели Билла. Я думал, что должна быть возможность установить запрос обратного вызова для метода hasManyThrough, но, согласно API, это не поддерживается. Это кажется таким простым, и у меня такое чувство, что я что-то упускаю из виду, но я не могу этого найти...






Я бы определил область для модели билетов, поскольку запрос становится немного сложным.
public function scopeBillsSince($query, $since)
return $query->whereHas('bills', function ($query2) use ($since) {
return $query2->withThrashed()->where('updated_at', '>=', Carbon::parse($since))
});
}
Теперь, используя эту область, вы можете запрашивать билеты следующим образом:
$tickets = exhibitor()->tickets()->withTrashed()->billsSince($since);
Просто подтвердил мое подозрение, вы не можете изменить запрос, уже определенный до области.
На данный момент это невозможно: https://github.com/laravel/framework/issues/23039
Если вы не возражаете против установки внешнего пакета, вы можете использовать этот пакет, который я создал: https://github.com/staudenmeir/eloquent-has-many-deep
class Exhibitor extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function tickets()
{
return $this->hasManyDeep(Ticket::class, [Bill::class])
->withTrashed('bills.deleted_at');
}
}
Этот пакет действительно идеален. Это также решает другую проблему, с которой я столкнулся, когда мне понадобилось 3-уровневое вложенное отношение. Спасибо, Джонас. В итоге я создал второе отношение в классе Exhibitor: >с мусоромed(); }
Насколько я знаю, запрос области основывается на
exhibitor()->tickets()->withTrashed(), и в нем уже отсутствуют удаленные счета, поэтому я не уверен, как это может помочь, но я попробую, просто чтобы выяснить это.