📜 ⬆️ ⬇️

Adding sort order to CakePHP

What will the topic be about?

How to achieve that it was possible to define / see in html output using CSS or in what order (asc | desc) the table column is sorted, and not just by which of the columns the table is sorted.

In short, to do, for example, on Yandex. Schedules, like this:
the sort order

How are we going to do this?

There are several options. At one time, I shoveled a bunch of “cake” sources, and so didn’t find a sane (non-resource-intensive) solution, except for the ones below. Of the three solutions:
  1. Parse html in the overloaded afterRender () function somewhere in your controller (you can't call it resource-intensive)
  2. Patch core
  3. Create your own helper, which is inherited from the PaginatorHelper helper, and overload the method we need there

I chose the third. There are also three reasons for this:
  1. This has almost no effect on performance.
  2. While I was thinking whether to write an article here or not, a beta version of CakePHP 1.3.0 was released, and there it was already fixed, so even a ticket with a similar question. But, since this is a beta, not all have been updated, and they will not be updated soon, because the topic is still relevant
  3. This is not against the logic of CakePHP.


Implementation

We will add a little. Highly. As it was required to achieve from our idea. So.
')
Find the file \ cake \ libs \ view \ helpers \ paginator.php . We look at it, we find the sort () function. Observe the logic:
function sort($title, $key = null , $options = array()) {
$options = array_merge(array( 'url' => array(), 'model' => null ), $options);
$url = $options[ 'url' ];
unset($options[ 'url' ]);

if (empty($key)) {
$key = $title;
$title = __(Inflector::humanize(preg_replace( '/_id$/' , '' , $title)), true );
}
$dir = 'asc' ;
$sortKey = $ this ->sortKey($options[ 'model' ]);
$isSorted = ($sortKey === $key || $sortKey === $ this ->defaultModel() . '.' . $key);

if ($isSorted && $ this ->sortDir($options[ 'model' ]) === 'asc' ) {
$dir = 'desc' ;
}

if (is_array($title) && array_key_exists($dir, $title)) {
$title = $title[$dir];
}

$url = array_merge(array( 'sort' => $key, 'direction' => $dir), $url, array( 'order' => null ));
return $ this ->link($title, $url, $options);
}


* This source code was highlighted with Source Code Highlighter .


We see that all that is needed to add a sort order class is already there. The logic of the authors is incomprehensible, probably they simply did not think or forgot.
Now we can right in this file add our little codec, thereby patching the kernel and using, respectively, the number two method from my list.
After unset($options['url']); add:
// patch:
if ($title == @$ this -> params [ 'named' ][ 'sort' ]) {
$options[ 'class' ] = $ this -> params [ 'named' ][ 'direction' ];
}
// endpatch


* This source code was highlighted with Source Code Highlighter .

The advantage of this is that you do not need to carry a separately modified helper with you if you use the same framework for different projects.

And now for the more interesting method.
Create a file \ app \ views \ helpers \ my_paginator.php or with any other name as your heart desires (just don’t forget to change the class name later). We write in it:

<?php

App::import( 'Helper' , 'Paginator' );

class MyPaginatorHelper extends PaginatorHelper {

/**
* Generates a sorting link
*
* @param string $title Title for the link.
* @param string $key The name of the key that the recordset should be sorted.
* @param array $options Options for sorting link. See #options for list of keys.
* @return string A link sorting default by 'asc'. If the resultset is sorted 'asc' by the specified
* key the returned link will sort by 'desc'.
*/
function sort($title, $key = null , $options = array()) {
$options = array_merge(array( 'url' => array(), 'model' => null ), $options);
$url = $options[ 'url' ];
unset($options[ 'url' ]);

// patch:
if ($title == @$ this -> params [ 'named' ][ 'sort' ]) {
$options[ 'class' ] = $ this -> params [ 'named' ][ 'direction' ];
}
// endpath

if (empty($key)) {
$key = $title;
$title = __(Inflector::humanize(preg_replace( '/_id$/' , '' , $title)), true );
}
$dir = 'asc' ;
$sortKey = $ this ->sortKey($options[ 'model' ]);
$isSorted = ($sortKey === $key || $sortKey === $ this ->defaultModel() . '.' . $key);

if ($isSorted && $ this ->sortDir($options[ 'model' ]) === 'asc' ) {
$dir = 'desc' ;
}

if (is_array($title) && array_key_exists($dir, $title)) {
$title = $title[$dir];
}

$url = array_merge(array( 'sort' => $key, 'direction' => $dir), $url, array( 'order' => null ));
return $ this ->link($title, $url, $options);
}
}
?>

* This source code was highlighted with Source Code Highlighter .


And, in AppController, do not forget to use it:
// ...
class AppController extends Controller {
var $helpers = array( 'Html' , 'Form' , 'Ajax' , 'Javascript' , 'MyPaginator' );

// ...


* This source code was highlighted with Source Code Highlighter .


That's all! Now in your web application will be approximately the following code:
< a class ="asc" id ="link1091361951" href ="/search/page:1/sort:first_name/direction:desc" > First Name </ a >

* This source code was highlighted with Source Code Highlighter .

Accordingly, if the class asc | desc is present, then this column is sorted, and how exactly it can be recognized by the class itself.

Successes!

UPD: Considering the comments, I want to say that I know about the existence of $ this-> params and that all this information is there. But each time for each column to write the conditions is not a good idea, especially there are already ready projects to which this functionality needs to be added.

Source: https://habr.com/ru/post/84660/


All Articles