firevel/sortable

A simple trait to make your Laravel Eloquent models sortable with ease.

Maintainers

Package info

github.com/firevel/sortable

pkg:composer/firevel/sortable

Statistics

Installs: 5 943

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

0.1.0 2026-05-25 02:47 UTC

This package is auto-updated.

Last update: 2026-05-25 02:53:56 UTC


README

A simple trait to make your Laravel Eloquent models sortable with ease. Designed for API usage where you can pass sort parameters directly from query strings (e.g., /users?sort=-id).

Installation

Using Composer:

composer require firevel/sortable

Setup

  1. Import the Sortable trait in your Eloquent model.

  2. Add a protected $sortable array property to your model. This array should list the fields you want to allow for sorting.

Example:

use Firevel\Sortable\Sortable;

class User extends Model {
    use Sortable;

    /**
     * Fields allowed for sorting.
     *
     * @var array
     */
    protected $sortable = ['id', 'name', 'email'];

    /**
     * Default sorting when no sort parameter is provided (optional).
     * May be an array (['-id']) or a string ('-id').
     *
     * @var array|string|null
     */
    protected $defaultSort = ['-id'];
}

Usage

You can now easily sort your models using the sort() query scope.

Ascending Order:

To sort by name in ascending order:

User::sort(['name'])->get();

Descending Order:

To sort by id in descending order:

User::sort(['-id'])->get();

The - sign before the field name indicates descending order.

Multiple Columns:

You can sort by multiple columns at once. The sorting is applied in the order specified:

User::sort(['name', '-id'])->get();

This will sort by name ascending, then by id descending.

API Usage:

This trait is particularly useful for API endpoints where you receive sort parameters from query strings. You can pass the raw JSON:API style string straight to sort() — no need to explode it yourself:

// Example: GET /users?sort=name,-id
public function index(Request $request)
{
    return User::sort($request->input('sort'))->get();
}

sort() accepts either a comma-separated string ("name,-id") or an array (['name', '-id']), so both of these are equivalent:

User::sort('name,-id')->get();
User::sort(['name', '-id'])->get();

Whitespace around fields is trimmed, so "name, -id" works too.

Note: sort() only applies fields listed in the model's $sortable allowlist. Any field that isn't allowed is silently ignored rather than raising an error — so an untrusted ?sort= value can never order by an unexpected column. If no valid fields remain, the model's $defaultSort (if any) is applied. To reject invalid input with a validation error instead, use the validation rule below.

Additional Features

Default Sorting

You can define a default sort order that will be applied when no sort parameters are provided:

class User extends Model {
    use Sortable;

    protected $sortable = ['id', 'name', 'email', 'created_at'];
    protected $defaultSort = ['-created_at'];  // Sort by newest first by default
}

// When called with no parameters, uses default sort
User::sort([])->get();  // Returns users sorted by created_at DESC

Check if Field is Sortable

You can check if a specific field is sortable using the isSortable() method:

$user = new User();

if ($user->isSortable('name')) {
    // Field is sortable
}

if ($user->isSortable('-id')) {
    // Also works with descending prefix
}

Validation Rule for Form Requests

The package provides two ways to validate sort parameters:

String-based validation:

class ListUsersRequest extends FormRequest
{
    public function rules()
    {
        return [
            'sort' => ['nullable', 'string', 'sort_fields:App\Models\User'],
        ];
    }
}

Object-based validation (provides more detailed error messages):

use Firevel\Sortable\SortField;
use App\Models\User;

class ListUsersRequest extends FormRequest
{
    public function rules()
    {
        return [
            'sort' => ['nullable', 'string', new SortField(User::class)],
        ];
    }
}

Both approaches work with string and array inputs:

// String input (e.g., from query string ?sort=name,-id)
'sort' => ['nullable', 'string', 'sort_fields:App\Models\User']

// Array input
'sort' => ['nullable', 'array', 'sort_fields:App\Models\User']

Example usage in a controller:

public function index(ListUsersRequest $request)
{
    return User::sort($request->input('sort'))->get();
}

The validation rule will automatically:

  • Check if each field is in the model's $sortable array
  • Handle both ascending (name) and descending (-name) formats
  • Provide clear error messages for invalid fields