Skip to main content
Sorting is route-level. You declare which fields the endpoint will sort by (and their default direction); clients send ?order_by=... to override it; the framework parses, validates, and populates $request->sorting() for you.

1. Declare sortable fields

Sort::asc('name') means: “sortable on name; if the client doesn’t override, default direction is ascending”. Sort::desc(...) is the reverse.

2. Clients pass order_by

The format is a comma-separated list of field names, each optionally prefixed with + (ascending, default) or - (descending):
RequestValidationMiddleware rejects anything not declared — ?order_by=hacked_field422. Routes without sorting([...]) skip this check entirely (nothing to validate against).

3. Read the resolved sorts

$request->sorting() returns a SortBag. It implements IteratorAggregate, so iterate directly:
The bag is always populated — if the client omits order_by, it contains the defaults from Sort::asc(...) / Sort::desc(...) in the order you declared them. Iteration order matches user intent: any sorts the client submitted via ?order_by= come first (in submission order), followed by the route’s defaults for fields the client didn’t specify. So foreach produces the right ORDER BY sequence — primary user choice first, defaults as tiebreakers — without you having to merge anything.

4. Tell user-requested sorts from defaults

Each Sort knows whether it came from ?order_by= or from the route declaration. Branch on isRequested() when you need to:
To get only the user’s submitted sorts (without route defaults), use getRequested():
has($field) only tells you whether the field is in the bag at all — for declared fields, that’s always true because defaults seed the bag. Use isRequested() to ask “did the user ask for this?”.

Inside a resource

Resources expose availableSortings():
AbstractListResourceController reads this and calls $route->sorting([...]) for you. The DocBlock generator also emits typed @method annotations on *ListRequest so $request->sorting()->name autocompletes. See generate OpenAPI + docblocks.

OpenAPI side effects

One query parameter — order_by — is added to the operation with:
  • type: string
  • Description listing supported fields and the + / - syntax.
  • Example matching your declared defaults.

Reference

Full behaviour and edge cases live at HTTP / Sorting.