@@ -224,6 +224,109 @@ pagination query::
224224Any requests that attempt to sort on fields not in the allowed list will be
225225ignored.
226226
227+ Advanced Sorting with SortableFieldsBuilder
228+ ============================================
229+
230+ The ``SortableFieldsBuilder `` provides a powerful way to create user-friendly
231+ sort URLs while maintaining control over database ordering. Instead of exposing
232+ raw field names in URLs, you can map friendly keys to complex sorting logic with
233+ multi-column support and direction control.
234+
235+ Using the Builder
236+ -----------------
237+
238+ You can configure sortable fields using a callable that receives a
239+ ``SortableFieldsBuilder `` instance::
240+
241+ use Cake\Datasource\Paging\SortField;
242+ use Cake\Datasource\Paging\SortableFieldsBuilder;
243+
244+ protected array $paginate = [
245+ 'sortableFields' => function (SortableFieldsBuilder $builder) {
246+ return $builder
247+ ->add('id', 'Articles.id')
248+ ->add('title', 'Articles.title')
249+ ->add('username', 'Users.username');
250+ },
251+ ];
252+
253+ This configuration allows users to sort using friendly keys like ``?sort=username ``
254+ instead of exposing the full field name ``?sort=Users.username ``.
255+
256+ Multi-Column Sorting
257+ --------------------
258+
259+ The builder supports mapping a single sort key to multiple database fields with
260+ independent direction control. Use the ``SortField `` class to define complex
261+ sorting::
262+
263+ use Cake\Datasource\Paging\SortField;
264+
265+ protected array $paginate = [
266+ 'sortableFields' => function ($builder) {
267+ return $builder
268+ ->add('best-deal', [
269+ SortField::desc('in_stock'),
270+ SortField::asc('price'),
271+ ])
272+ ->add('popularity', [
273+ SortField::desc('view_count'),
274+ SortField::asc('title'),
275+ ]);
276+ },
277+ ];
278+
279+ Now ``?sort=best-deal `` will order by in-stock items first (descending), then by
280+ price (ascending). When users toggle the direction (e.g., ``?sort=best-deal&direction=asc ``),
281+ all fields in the array will toggle their directions: in_stock becomes ASC and
282+ price becomes DESC.
283+
284+ Locked Sort Directions
285+ ----------------------
286+
287+ You can lock a sort direction to prevent users from toggling it. This is useful
288+ when a field should always be sorted in a specific direction::
289+
290+ protected array $paginate = [
291+ 'sortableFields' => function ($builder) {
292+ return $builder
293+ ->add('latest', SortField::desc('created', locked: true))
294+ ->add('id', SortField::asc('id', locked: true));
295+ },
296+ ];
297+
298+ With locked directions, the sort key will always use the specified direction
299+ regardless of the ``direction `` parameter in the URL.
300+
301+ Combined Sorting Keys
302+ ---------------------
303+
304+ In addition to the traditional ``?sort=field&direction=asc `` format, you can use
305+ combined sorting keys in URLs::
306+
307+ // These are equivalent
308+ ?sort=title&direction=asc
309+ ?sort=title-asc
310+
311+ // These are equivalent
312+ ?sort=price&direction=desc
313+ ?sort=price-desc
314+
315+ This provides a cleaner URL format for applications that prefer it.
316+
317+ Simple Array Configuration
318+ ---------------------------
319+
320+ For basic use cases where you just need to allow sorting on specific fields
321+ without mapping or multi-column support, you can still use the simple array
322+ format::
323+
324+ protected array $paginate = [
325+ 'sortableFields' => [
326+ 'id', 'title', 'Users.username', 'created',
327+ ],
328+ ];
329+
227330Limit the Maximum Number of Rows per Page
228331=========================================
229332
0 commit comments