Задать вопрос
@stdio96

Есть ли аналог scope для коллекций Laravel?

Потратив некоторое время на поиск ответов в гугле, я так и не нашел ответа на следующий вопрос.

Есть ли аналог scope для коллекций Laravel?

Среди ответов, которые я прочел, было указано, что можно использовать и scope для моделей (не коллекций). К примеру: мне надо получить все активные (со статусом 1) и неактивные (статус 0) коментарии. Как это делается, варианты:
  1. $post->comments - получаю все комментарии (relation создан в модели)
  2. $post->activeComments() - все активные комментарии (scope создан заранее)
    $post->inActiveComments() - все неактивные комментарии (scope создан заранее)


При использовании варианта 1, в коде я могу получить оба типа комментариев:
$active_comments = $post->comments->where('status', 1);
$incative_comments = $post->comments->where('status', 0)


В чем, собственно, вопрос: при использовании варианта 1 на странице выполняется всего 1 SQL-запрос к БД. При использовании вариантов 2 и 3 - 2 SQL-запроса. Поэтому и стоит вопрос: "Можно ли как-то сократить запись из кода выше использую что-то типа scope только для коллекций?".

P.S.: как вы считаете, стоит ли использовать вариант со scope для запросов или мой вариант, изложенный выше?
  • Вопрос задан
  • 351 просмотр
Подписаться 2 Средний 2 комментария
Решения вопроса 1
Sanasol
@Sanasol Куратор тега Laravel
нельзя просто так взять и загуглить ошибку
class Post {
    public function scopeCommentsWithStatus($query, $status)
    {
        return $this->comments->where('status', $status);
    }

    public function getActiveCommentsAttribute()
    {
        return $this->comments->where('status', 1);
    }
}

$post = Post::with(['comments'])->first();

$post->commentsWithStatus(1);
$post->commentsWithStatus(0);

$post->active_comments;


извращайтесь как угодно, главное что следить за загрузкой with() надо всегда, в противном случае можно нарваться на ленивую загрузку которая сгенерирует по запросу на каждую модель.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@NubasLol
Если очень хочется костылять
Collection::macro('inactive', function () {
    return $this->where('status', 1);
});
Ответ написан
Комментировать
@jazzus
Бояться запросов не стоит бд для того и создана) Если данных много запрос будет быстрее чем фильтровать коллекцию (проверено). Вообще лучше думать так – нет скопов, значит их не должно быть. С различного рода новаторскими идеями без опыта можно потом нарваться на нехилый рефакторинг (проверено). Я бы сделал так
// В модели Post
public function activeComments()
{
  return $this->commnets()->ofActive();
}

public function inactiveComments()
{
  return $this->commnets()->ofInactive();
}

// в контроллере/классе
$relations = ['activeComments', 'inactiveComments'];

Post::with($relations)
    ->withCount($relations)
    ->get();

Скопы убрать в трейт, чтобы подключать к разным моделям с активностью
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы