Is there an analogue scope for collections Laravel?

Spending some time searching answers in Google, I never found the answer to the following question.

Is there an analogue scope for collections Laravel?

Among the responses I read, it was stated that you can use for scope models (not collections). For example: I need to get all active (status 1) and inactive (status 0) comments. How this is done, the options are:
  1. $post->comments - get all comments (relation created in the model)
  2. $post->activeComments() - all comments (scope created in advance)
    $post->inActiveComments() - all inactive comments (scope created in advance)


If you use option 1 in the code I can get both types of comments:
$active_comments = $post->comments->where('status', 1);
$incative_comments = $post->comments->where('status', 0)


What, in fact, the question is: when using option 1 on the page executes only 1 SQL query to the database. When using the options 2 and 3 - 2 SQL query. So the question is: "is it Possible to cut the record from the code above, use something like scope - only collections?".

PS: as you consider whether to use a variant with a scope for queries, or my version above?
April 7th 20 at 15:43
3 answers
April 7th 20 at 15:45
Solution
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;


subverted somehow, the main thing that to follow the loading with() must always be, otherwise you can run into lazy loading which will produce on request for each model.
Thank you. Test. And how, in Your opinion, should realize this: using a scope or this option? Optimization and etc. How appropriate and optimally-right?

Can I do this:
class Post {
 // comments() relation goes here

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

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

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

$post->active_comments;
$post->inactive_comments;


Don't quite understand the use of scope in Your example. - laura.Mertz4 commented on April 7th 20 at 15:48
@abigale,
Can I do this:

Yes, it's the second option in the answer is.
Pitfall is that if you forget to do it with() accidentally, you get stopitsot queries instead of one.

Don't quite understand the use of scope in Your example.

A common use of dynamic osprey, only through the ass and virtually no query generates.
I'm not sure that would work, but probably should. - Maiya.Mosciski36 commented on April 7th 20 at 15:51
@ivy_Lehn, yeah, another nuance has emerged. The fact that the fields status in comments is not present. It is in a pivot table (many to many). And a separate model was not created for this relationship. Accordingly, when I execute this query, it reports that there is no such field. Maybe I'm not quite correctly explained. Is it possible then to work to use the attribute? If so, where it to register?

Is there any sense in it? You can in fact just 2 requests to do. Interested in Your opinion.

Thank you. - laura.Mertz4 commented on April 7th 20 at 15:54
comments->where('pivot.status', 1)
or
comments->where(function ($comment) {
 return $comment->pivot->status === 1;
})
- Maiya.Mosciski36 commented on April 7th 20 at 15:57
@ivy_Lehn, thank you. All would have been even sooner if I need a model attribute written -_-. - laura.Mertz4 commented on April 7th 20 at 16:00
2 query to the database is nothing that optimize their crutches nonsense - dagmar_Heidenrei commented on April 7th 20 at 16:03
@abigale, or about a pivot in anything he wrote directly - Maiya.Mosciski36 commented on April 7th 20 at 16:06
@juana23, it is about the collection of posts like, i.e. 2 * the number of posts will be output. - Maiya.Mosciski36 commented on April 7th 20 at 16:09
@ivy_Lehn, I only had to register only 2 attribute. I haven't used scope.

My code:
public function getActiveCommentsAttribute()
{
 return $this->comments->where('pivot.status', 1);
}

 public function getInactiveCommentsAttribute()
{
 return $this->comments->where('pivot.status', 0);
}

@forelse ($post->inactive_comments as $comment)
...
@endfoelse


An additional request has not appeared. - laura.Mertz4 commented on April 7th 20 at 16:12
public function scopeCommentsWithStatus($query, $status)
{
 return $this->comments->where('status', $status);
 }


Osprey that returns a collection???? - dagmar_Heidenrei commented on April 7th 20 at 16:15
@ivy_Lehn, 2 query of the form

$post->comments()->where('status', 1)->get();
 $post->comments()->where('status', 0)->get();


Additional requests will not get out - dagmar_Heidenrei commented on April 7th 20 at 16:18
@juana23, just tried several options and Your including additional requests are.

Option without additional queries:
$post->comments->where('status', 1); // active
$post->comments->where('status', 0); // inactive
- laura.Mertz4 commented on April 7th 20 at 16:21
@abigale, 2 request. It's nothing. Extreme savings. And not the fact. You need to test.

Maybe even php will be slower to filter the collection than to make 2 query to the database - dagmar_Heidenrei commented on April 7th 20 at 16:24
@juana23, this is also a question. I originally doubted the feasibility of this method.

Both options (using attributes and using Your proposed scope) workers. - laura.Mertz4 commented on April 7th 20 at 16:27
April 7th 20 at 15:47
If you really want to costulate
Collection::macro('inactive', function () {
 return $this->where('status', 1);
});
April 7th 20 at 15:49
Fear should not query the database is created) If the data is large the query will be faster than filtering a collection (tested). Generally it is better to think so – no Skopje, then they should not be. With various innovative ideas without experience, you can then run into a pretty big refactoring (tested). I would have done so
// In the Post model
public function activeComments()
{
 return $this->commnets()->ofActive();
}

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

// in your controller/class
$relations = ['activeComments', 'inactiveComments'];

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

The osprey put into the trait, to connect to different models with activity

Find more questions by tags Laravel