Supercharge Your Laravel Models with Custom Collections

Supercharge Your Laravel Models with Custom Collections

Laravel's Eloquent ORM provides a powerful way to interact with your database, and one of its lesser-known features is the ability to use custom collections for your models. This allows you to add model-specific collection methods, enhancing the way you work with groups of model instances.

Implementing Custom Collections

To use a custom collection, you need to override the newCollection() method in your model:

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function newCollection(array $models = [])
    {
        return new UserCollection($models);
    }
}

Then, create your custom collection class:

use Illuminate\Database\Eloquent\Collection;

class UserCollection extends Collection
{
    public function activeUsers()
    {
        return $this->where('active', true);
    }
}

Real-World Example: E-commerce Order Management

Let's consider an e-commerce platform where we need to perform various operations on collections of orders. We'll create a custom OrderCollection to encapsulate this functionality.

First, let's define our Order model:

class Order extends Model
{
    protected $casts = [
        'total' => 'float',
        'completed_at' => 'datetime',
    ];

    public function newCollection(array $models = [])
    {
        return new OrderCollection($models);
    }
}

Now, let's create our custom OrderCollection:

class OrderCollection extends Collection
{
    public function completed()
    {
        return $this->whereNotNull('completed_at');
    }

    public function pending()
    {
        return $this->whereNull('completed_at');
    }

    public function totalRevenue()
    {
        return $this->sum('total');
    }

    public function applyBulkDiscount($percentage)
    {
        return $this->each(function ($order) use ($percentage) {
            $order->total *= (1 - $percentage / 100);
            $order->save();
        });
    }

    public function groupByMonth()
    {
        return $this->groupBy(function ($order) {
            return $order->created_at->format('Y-m');
        });
    }
}

Here's how we can use this in our application:

class OrderController extends Controller
{
    public function dashboard()
    {
        $orders = Order::all();

        return view('orders.dashboard', [
            'completedOrders' => $orders->completed(),
            'pendingOrders' => $orders->pending(),
            'totalRevenue' => $orders->totalRevenue(),
            'monthlyBreakdown' => $orders->groupByMonth(),
        ]);
    }

    public function applyHolidayDiscount()
    {
        $pendingOrders = Order::where('completed_at', null)->get();
        $pendingOrders->applyBulkDiscount(10);

        return back()->with('message', 'Holiday discount applied successfully!');
    }
}

By leveraging custom collections, you can create more expressive, maintainable, and powerful Laravel applications. This approach allows you to encapsulate complex business logic at the collection level, keeping your controllers lean and focused on their primary responsibilities.

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe