Skip to content
Advertisement

Laravel default orderBy

Is there a clean way to enable certain models to be ordered by a property by default? It could work by extending the laravel’s QueryBuilder, but to do so, you’ll have to rewire some of it’s core features – bad practice.

reason

The main point of doing this is – one of my models get’s heavily reused by many others and right now you have to resort the order over and over again. Even when using a closure for this – you still have to call it. It would be much better to be able to apply a default sorting, so everyone who uses this model, and does not provide custom sorting options, will receive records sorted by the default option. Using a repository is not an option here, because it get’s eager loaded.

SOLUTION

Extending the base model:

protected $orderBy;
protected $orderDirection = 'ASC';

public function scopeOrdered($query)
{
    if ($this->orderBy)
    {
        return $query->orderBy($this->orderBy, $this->orderDirection);
    }

    return $query;
}

public function scopeGetOrdered($query)
{
    return $this->scopeOrdered($query)->get();
}

In your model:

protected $orderBy = 'property';
protected $orderDirection = 'DESC';

// ordering eager loaded relation
public function anotherModel()
{
    return $this->belongsToMany('SomeModel', 'some_table')->ordered();
}

In your controller:

MyModel::with('anotherModel')->getOrdered();
// or
MyModel::with('anotherModel')->ordered()->first();

Advertisement

Answer

Yes you would need to extend Eloquent to always do this as standard for any query. What’s wrong with adding an order by statement to the query when you need it ordered? That is the cleanest way, ie, you dont need to ‘unhack’ Eloquent to get results by natural order.

MyModel::orderBy('created_at', 'asc')->get();

Other than that the closest thing to what you want would be to create query scopes in your models.

public function scopeOrdered($query)
{
    return $query->orderBy('created_at', 'asc')->get();
}

You can then call ordered as a method instead of get to retrieve your ordered results.

$data = MyModel::where('foo', '=', 'bar')->ordered();

If you wanted this across different models you could create a base class and just extend it to the models you want to have access to this scoped method.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement