Skip to content

Commit

Permalink
Re-adding ability to order by virtual fields in DboSource::order
Browse files Browse the repository at this point in the history
Adding support for paginating virtual model fields in controller
  • Loading branch information
lorenzo committed Dec 11, 2009
1 parent 051d352 commit cf359a3
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 96 deletions.
6 changes: 4 additions & 2 deletions cake/libs/controller/controller.php
Expand Up @@ -1076,9 +1076,11 @@ function paginate($object = null, $scope = array(), $whitelist = array()) {
$value = $options['order'][$key];
unset($options['order'][$key]);

if (isset($object->{$alias}) && $object->{$alias}->hasField($field)) {
if ($object->hasField($field)) {
$options['order'][$alias . '.' . $field] = $value;
} elseif ($object->hasField($field)) {
} elseif ($object->hasField($field,true)) {
$options['order'][$field] = $value;
} elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) {
$options['order'][$alias . '.' . $field] = $value;
}
}
Expand Down
89 changes: 14 additions & 75 deletions cake/libs/model/datasources/dbo_source.php
Expand Up @@ -2216,6 +2216,14 @@ function limit($limit, $offset = null) {
return null;
}

/**
* Returns an ORDER BY clause as a string.
*
* @param string $key Field reference, as a key (i.e. Post.title)
* @param string $direction Direction (ASC or DESC)
* @param object $model model reference (used to look for virtual field)
* @return string ORDER BY clause
*/
function order($keys, $direction = 'ASC', &$model = null) {
if (!is_array($keys)) {
$keys = array($keys);
Expand Down Expand Up @@ -2246,7 +2254,7 @@ function order($keys, $direction = 'ASC', &$model = null) {
}
continue;
}

if (preg_match('/\\x20ASC|\\x20DESC/i', $key, $_dir)) {
$dir = $_dir[0];
$key = preg_replace('/\\x20ASC|\\x20DESC/i', '', $key);
Expand All @@ -2264,7 +2272,11 @@ function order($keys, $direction = 'ASC', &$model = null) {

$key = trim($key);
if (!preg_match('/\s/', $key) && !strpos($key,'.')) {
$key = $this->name($key);
if (!empty($model->virtualFields[$key])) {
$key = $model->virtualFields[$key];
} else {
$key = $this->name($key);
}
}
$key .= ' ' . trim($dir);
$result[] = $key;
Expand All @@ -2275,79 +2287,6 @@ function order($keys, $direction = 'ASC', &$model = null) {
return '';
}

/**
* Returns an ORDER BY clause as a string.
*
* @param string $key Field reference, as a key (i.e. Post.title)
* @param string $direction Direction (ASC or DESC)
* @param object $model model reference (used to look for virtual field)
* @return string ORDER BY clause
*/
function order2($keys, $direction = 'ASC', &$model = null) {
if (is_string($keys) && !empty($model->virtualFields[$keys])) {
return '(' . $model->virtualFields[$keys] . ') ' . $direction;
}
if (is_string($keys) && strpos($keys, ',') && !preg_match('/\(.+\,.+\)/', $keys)) {
$keys = array_map('trim', explode(',', $keys));
}

if (is_array($keys)) {
$keys = array_filter($keys);
$dir = $direction;
}

if (empty($keys) || (is_array($keys) && isset($keys[0]) && empty($keys[0]))) {
return '';
}

if (is_array($keys)) {

foreach ($keys as $key => $value) {
if (is_numeric($key)) {
$key = $value = ltrim(str_replace('ORDER BY ', '', $this->order($value,'ASC',$model)));
$value = (!preg_match('/\\x20ASC|\\x20DESC/i', $key) ? ' ' . $direction : '');
} else {
$value = ' ' . $value;
}

if (!preg_match('/^.+\\(.*\\)/', $key) && !strpos($key, ',')) {
if (preg_match('/\\x20ASC|\\x20DESC/i', $key, $dir)) {
$dir = $dir[0];
$key = preg_replace('/\\x20ASC|\\x20DESC/i', '', $key);
} else {
$dir = '';
}
$key = trim($key);
if (!preg_match('/\s/', $key)) {
$key = $this->name($key);
}
$key .= ' ' . trim($dir);
}
$order[] = $this->order($key . $value,'ASC',$model);
}
return ' ORDER BY ' . trim(str_replace('ORDER BY', '', implode(',', $order)));
}
$keys = preg_replace('/ORDER\\x20BY/i', '', $keys);

if (strpos($keys, '.')) {
preg_match_all('/([a-zA-Z0-9_]{1,})\\.([a-zA-Z0-9_]{1,})/', $keys, $result, PREG_PATTERN_ORDER);
$pregCount = count($result[0]);

for ($i = 0; $i < $pregCount; $i++) {
if (!is_numeric($result[0][$i])) {
$keys = preg_replace('/' . $result[0][$i] . '/', $this->name($result[0][$i]), $keys);
}
}
$result = ' ORDER BY ' . $keys;
return $result . (!preg_match('/\\x20ASC|\\x20DESC/i', $keys) ? ' ' . $direction : '');

} elseif (preg_match('/(\\x20ASC|\\x20DESC)/i', $keys, $match)) {
$direction = $match[1];
return ' ORDER BY ' . preg_replace('/' . $match[1] . '/', '', $keys) . $direction;
}
return ' ORDER BY ' . $keys . ' ' . $direction;
}

/**
* Create a GROUP BY SQL clause
*
Expand Down
41 changes: 22 additions & 19 deletions cake/tests/cases/libs/controller/controller.test.php
Expand Up @@ -418,25 +418,6 @@ function endTest() {
App::build();
}

function testPaginateOrderVirtualField() {
$Controller =& new Controller();
$Controller->uses = array('ControllerPost', 'ControllerComment');
$Controller->passedArgs[] = '1';
$Controller->params['url'] = array();
$Controller->constructClasses();
$Controller->ControllerPost->virtualFields = array('offset_test' => 'ControllerPost.id + 1');

$Controller->paginate = array(
'fields' => array('id', 'title'),
'order' => 'offset_test',
'limit' => 1
);
$result = $Controller->paginate('ControllerPost');

$this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(2, 3));
exit;
}

/**
* testConstructClasses method
*
Expand Down Expand Up @@ -1262,5 +1243,27 @@ function testRequestHandlerPrefers(){
$this->assertEqual($Controller->RequestHandler->prefers(), 'rss');
unset($Controller);
}

function testPaginateOrderVirtualField() {
$Controller =& new Controller();
$Controller->uses = array('ControllerPost', 'ControllerComment');
$Controller->passedArgs[] = '1';
$Controller->params['url'] = array();
$Controller->constructClasses();
$Controller->ControllerPost->virtualFields = array(
'offset_test' => 'ControllerPost.id + 1'
);

$Controller->paginate = array(
'fields' => array('id', 'title','offset_test'),
'order' => array('offset_test' => 'DESC')
);
$result = $Controller->paginate('ControllerPost');
$this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(4,3,2));

$Controller->passedArgs = array('sort' => 'offset_test', 'direction' => 'asc');
$result = $Controller->paginate('ControllerPost');
$this->assertEqual(Set::extract($result, '{n}.ControllerPost.offset_test'), array(2,3,4));
}
}
?>

0 comments on commit cf359a3

Please sign in to comment.