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).
Using Composer:
composer require firevel/sortableImport the
Sortabletrait in your Eloquent model.Add a protected
$sortablearray property to your model. This array should list the fields you want to allow for sorting.
useFirevel\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'];
}You can now easily sort your models using the sort() query scope.
To sort by name in ascending order:
User::sort(['name'])->get();To sort by id in descending order:
User::sort(['-id'])->get();The - sign before the field name indicates descending order.
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.
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,-idpublicfunctionindex(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$sortableallowlist. 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.
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 DESCYou can check if a specific field is sortable using the isSortable() method:
$user = newUser();
if ($user->isSortable('name')) {
// Field is sortable
}
if ($user->isSortable('-id')) {
// Also works with descending prefix
}The package provides two ways to validate sort parameters:
class ListUsersRequest extends FormRequest
{
publicfunctionrules()
{
return [
'sort' => ['nullable', 'string', 'sort_fields:App\Models\User'],
];
}
}useFirevel\Sortable\SortField;
useApp\Models\User;
class ListUsersRequest extends FormRequest
{
publicfunctionrules()
{
return [
'sort' => ['nullable', 'string', newSortField(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:
publicfunctionindex(ListUsersRequest$request)
{
return User::sort($request->input('sort'))->get();
}The validation rule will automatically:
- Check if each field is in the model's
$sortablearray - Handle both ascending (
name) and descending (-name) formats - Provide clear error messages for invalid fields