#development #eloquent #laravel #php
Collections offer a lot of functionality out of the box. Sometimes you just need that little bit of extra functionality
that works best in your case. For those moments, custom collections are brilliant. The first step is to create the
actual collection, extending the base
Collection
class.
1namespace App\Collections;
2
3use Illuminate\Database\Eloquent\Collection;
4
5class PostsCollection extends Collection
6{
7 // Add your own custom methods here
8}
The class here extends Illuminate\Database\Eloquent\Collection
. This class has extra methods available for Eloquent
like load
, toQuery
, and many more. This class itself extends the base collection class
Illuminate\Support\Collection
. You can decide which class you want to extend here.
You can find all available methods here:
Luckily, we can do a lot more cool things other than just creating a class with some methods. Since we can create a
collection class that extends the Illuminate\Database\Eloquent\Collection
with all the extra Eloquent methods, it
would be really nice if we could connect this to a model as well. And of course, we can.
1namespace App\Models;
2
3use App\Collections\PostsCollection;
4use Illuminate\Database\Eloquent\Model;
5
6class Post extends Model
7{
8 public function newCollection(array $models = [])
9 {
10 return new PostsCollection($models);
11 }
12}
Every time you query a post, it will now return an instance of App\Collections\PostsCollection
instead of
Illuminate\Database\Eloquent\Collection
.
You can now add your own methods to then call inside your code. This new collection will be returned for all queries and
relationships where multiple posts are returned. For example Post::all()
, User::posts()->get()
and even
User::with('posts')->get()
. They all return a PostsCollection
.
In the above snippet, we created a custom PostsCollection
class and also made it available for the model. Let's see
how a custom method inside a collection class might look like. Remember that this custom collection class has all the
available methods of a normal collection class.
1namespace App\Collections;
2
3use App\Models\Post;
4use Carbon\Carbon;
5
6class PostsCollection extends Collection
7{
8 public function markAsPublished(Carbon $publishedAt): self
9 {
10 Post::query()
11 ->whereKey($this->modelKeys())
12 ->update(['published_at', $publishedAt]);
13
14 $this->each(function (Post $post) use ($publishedAt) {
15 $post->setAttribute('published_at', $publishedAt);
16 });
17
18 return $this;
19 }
20}
21
22Post::all()->markAsPublished(Carbon::now());
In the markAsPublished
method we perform a database query to update the published_at
field. We also update the
models inside the collection. This way, we don't have to retrieve the models again from the database to get the same
data. This is a perfect use case for a custom collection class method.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.