Skip to content

n7olkachev/laravel-computed-properties

Repository files navigation

Computed properties for Eloquent

Code quality Latest Version on Packagist Licence Build Status

Laravel 5.4+

Based on this tweet: https://twitter.com/reinink/status/899713609722449920

Some examples for better understanding of this power:

class Order extends Model
{
    use ComputedProperties;

    public function products()
    {
        return $this->hasMany(OrderProduct::class);
    }

    public function computedSum($order)
    {
        return OrderProduct::select(new Expression('sum(price * count)'))
            ->where('order_id', $order->id);
    }
}

Now, we can get order sum with $order->sum. Yep, we can get this functionality with getSumAttribute but wait! The real power of this package is that we can use this method inside our queries:

$orders = Order::withComputed('sum')->get()

We eager loaded sum attribute without N+1 problem.

But there is more! You can add having or orderBy clauses to such queries for filtering and sorting!

Order::withComputed('sum')->orderBy('sum', 'desc')->get()

Installation

You can install the package via composer:

composer require n7olkachev/laravel-computed-properties

Next, add ComputedProperties trait to your models:

use ComputedProperties;

That's all!

More examples

class Page extends Model
{
    use ComputedProperties;

    public $timestamps = false;

    protected $casts = [
        'last_view' => 'datetime',
        'first_view' => 'datetime',
    ];

    public function computedLastView($page)
    {
        return PageView::select(new Expression('max(viewed_at)'))
            ->where('page_id', $page->id);
    }

    public function computedFirstView($page)
    {
        return PageView::select(new Expression('min(viewed_at)'))
            ->where('page_id', $page->id);
    }
}

We can find Page by its first view:

$page = Page::withComputed('first_view')
    ->having('first_view', Carbon::create(2017, 8, 16, 0, 0, 0))
    ->first();

Or by both first_view and last_view

$page = Page::withComputed(['first_view', 'last_view'])
    ->having('first_view', Carbon::create(2017, 8, 16, 0, 0, 0))
    ->having('last_view', Carbon::create(2017, 8, 21, 0, 0, 0))
    ->first();

We can order pages by theirs last_view

$pages = Page::withComputed('last_view')
    ->orderBy('last_view', 'desc')
    ->get()

Testing

$ composer test

Credits

Sponsored by

https://websecret.by/

Web agency based in Minsk, Belarus

License

The MIT License (MIT)