简体   繁体   中英

How can I sort a table of Laravel Eloquent objects by a custom attribute?

I have a Laravel 4.2 project (though I'll soon upgrade it to Laravel 5, so I'm interested in answers that apply to either version of Laravel). I often define custom attributes for models to make it easier to calculate and display certain values. (See the Laravel Documentation for how this works.) Eg:

public function getFooBarAttribute() {
   // Do some complex calculations, etc.
   return $result;
}

Then in my view I can do {{ $object->foo_bar }} to print the result of that calculation.

Often such code will appear as a column of a <table> displaying a list of objects. I want to make the table sortable by that column. What is the best way to do that?

The main solution I have come up with so far is to convert any calculations in that function to equivalent SQL (and from there into Eloquent / QueryBuilder syntax). However, this is error-prone, makes the code harder to read, and is difficult to maintain (since it must be changed if the attribute function ever is).

Another solution would be to sort the resulting Collection manually, but I'm under the impression that doing so would be slower. (Is this true?)

How else can I accomplish this?

You are describing sorting a collection. Here is a similar question. Calculation and sorting should be faster if done in SQL rather than PHP. To make it easier you could create some table views in your database and query them, instead of doing all the calculation each time in Laravel.

The only way to do this would be, as you stated, convert the calculations or code in your custom attributes into SQL. If you're already doing that you might as well retrieve your custom attribute with SQL as well. You could try to accomplish that with a scope: http://laravel.com/docs/4.2/eloquent#query-scopes

Lets consider an example: You have a table products with a column price and tax. Lets say you have a custom attribute priceTotal as follows:

public function getPriceTotalAttribute() {
   return ($this->price + $this->tax);
}

In this case you could define a scope to replace this attribute.

public function scopePriceTotal($query)
{
    return $query->selectRaw($this->table . '.*, (price + tax) AS priceTotal')
    ->orderBy('priceTotal');
}

Of course this is a simple example, your code would probably be far more complex. This is also more verbose, because it would require you to call this scope every time you need the custom attribute. But it's the only way to make SQL aware of your custom attribute and to be able to order your SQL result accordingly.

Your best bet would be using the using the collection to order your result. It's actually pretty fast, so I doubt it would slow down your application by much. The documentation shows how to order your collection: http://laravel.com/docs/4.2/eloquent#collections and here's another useful article on collections: http://codebyjeff.com/blog/2015/05/stupid-collection-tricks-in-laravel

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM