cloudcreativity / laravel-json-api

JSON API (jsonapi.org) package for Laravel applications.
http://laravel-json-api.readthedocs.io/en/latest/
Apache License 2.0
780 stars 109 forks source link

Is there any way to sort by a mutator attribute? #434

Closed defunctl closed 5 years ago

defunctl commented 5 years ago

Say in a model you add something like:

    public function getTotalAttribute( int $id ) {
        return DifferentModel::where( 'client_id', $id )->count();
    }

and in your Resource/Schema.php

    public function getAttributes( $resource ) {
        return [
            'total' => $resource->Total,
        ];
    }

This properly displays the value, but is there any way to make this a sortable attribute?

Give in the SortModels.php trait, ordering is done by the query Builder, but Laravel doesn't seem to let you sort by custom mutator attributes unless it's a collection (using SortBy())

    protected function sortBy($query, SortParameterInterface $param)
    {
        $column = $this->getQualifiedSortColumn($query, $param->getField());
        $order = $param->isAscending() ? 'asc' : 'desc';

        $query->orderBy($column, $order);
    }

Any way to accomplish this? Unfortunately unable to modify this database.

Thanks!

lindyhopchris commented 5 years ago

You'd need to sort it after the database has been queried, i.e. sort the collection. You'd need to overload the method that returns the collection, and sort it before returning it.

defunctl commented 5 years ago

Hey Chris,

Thanks for the reply. Would you mind pointing me to the class/method that returns the collection?

Appreciate this great package and the support.

lindyhopchris commented 5 years ago

queryAll() on your Eloquent adapter: https://github.com/cloudcreativity/laravel-json-api/blob/develop/src/Eloquent/AbstractAdapter.php#L636

You are going to have problems though... for example, if the client sends page parameters, then there's no way to honour the request because you'd need to sort before retrieving the page from the database, which is not possible to do.

So basically implementing this is not going to be straightforward, and would only really work if you're retrieving all of the records from the database, and then sorting them before returning them to the client.

lindyhopchris commented 5 years ago

But worth saying, it would be exactly the same problem if you were trying to list the records in a Blade template and wanting to sort them by the computed attribute... i.e. this isn't a problem with the API implementation, it's to do with wanting to sort on an attribute that you're computing after pulling records out of the database.

defunctl commented 5 years ago

Hi Chris,

Thanks again for the reply. I was worried you'd say that but very happy that you did.

I'll try to approach this from the Adapter::filter() method then and see if I can get this going with some SQL instead.

lindyhopchris commented 5 years ago

Great - I'll close this issue for now then as it looks like your questions are answered!