S
S
stdio962020-02-18 18:19:39
Laravel
stdio96, 2020-02-18 18:19:39

Is there a scope analog for Laravel collections?

After spending some time googling for answers, I never found an answer to the following question.

Is there a scope analog for Laravel collections?

Among the answers I read, it was stated that you can use scope for models (not collections). For example: I need to get all active (with status 1) and inactive (status 0) comments. How it's done, options:

  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 для запросов или мой вариант, изложенный выше?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
Александр Аксентьев, 2020-02-18
@stdio96

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() надо всегда, в противном случае можно нарваться на ленивую загрузку которая сгенерирует по запросу на каждую модель.

N
NubasLol, 2020-02-18
@NubasLol

If you really want to crutch

Collection::macro('inactive', function () {
    return $this->where('status', 1);
});

J
jazzus, 2020-02-19
@jazzus

It is not worth being afraid of queries, the database was created for this) If there is a lot of data, the query will be faster than filtering the collection (checked). In general, it is better to think like this - there are no ospreys, which means they should not be. With various kinds of innovative ideas without experience, you can then run into a sickly refactoring (checked). I would do so

// В модели Post
public function activeComments()
{
  return $this->commnets()->ofActive();
}

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

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

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

Remove ospreys in a trait to connect to different models with activity

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question