diff --git a/cake/libs/controller/components/paginator.php b/cake/libs/controller/components/paginator.php index bb33177e1..9755d47f2 100644 --- a/cake/libs/controller/components/paginator.php +++ b/cake/libs/controller/components/paginator.php @@ -95,41 +95,12 @@ class PaginatorComponent extends Component { throw new MissingModelException($object); } - $options = $this->mergeOptions($object->alias, $scope, $whitelist); - if (isset($options['show'])) { $options['limit'] = $options['show']; } - if (isset($options['sort'])) { - $direction = null; - if (isset($options['direction'])) { - $direction = strtolower($options['direction']); - } - if ($direction != 'asc' && $direction != 'desc') { - $direction = 'asc'; - } - $options['order'] = array($options['sort'] => $direction); - } - - if (!empty($options['order']) && is_array($options['order'])) { - $alias = $object->alias ; - $key = $field = key($options['order']); - - if (strpos($key, '.') !== false) { - list($alias, $field) = explode('.', $key); - } - $value = $options['order'][$key]; - unset($options['order'][$key]); - - if ($object->hasField($field)) { - $options['order'][$alias . '.' . $field] = $value; - } elseif ($object->hasField($field, true)) { - $options['order'][$field] = $value; - } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) { - $options['order'][$alias . '.' . $field] = $value; - } - } + $options = $this->mergeOptions($object->alias, $scope, $whitelist); + $options = $this->validateSort($object, $options); $conditions = $fields = $order = $limit = $page = $recursive = null; @@ -312,4 +283,47 @@ class PaginatorComponent extends Component { return array_merge($defaults, $request, $options); } + +/** + * Validate that the desired sorting can be performed on the $object. Only fields or + * virtualFields can be sorted on. The direction param will also be sanitized. Lastly + * sort + direction keys will be converted into the model friendly order key. + * + * @param Model $object The model being paginated. + * @param array $options The pagination options being used for this request. + * @return array An array of options with sort + direction removed and replaced with order if possible. + */ + public function validateSort($object, $options) { + if (isset($options['sort'])) { + $direction = null; + if (isset($options['direction'])) { + $direction = strtolower($options['direction']); + } + if ($direction != 'asc' && $direction != 'desc') { + $direction = 'asc'; + } + $options['order'] = array($options['sort'] => $direction); + } + + if (!empty($options['order']) && is_array($options['order'])) { + $alias = $object->alias ; + $key = $field = key($options['order']); + + if (strpos($key, '.') !== false) { + list($alias, $field) = explode('.', $key); + } + $value = $options['order'][$key]; + unset($options['order'][$key]); + + if ($object->hasField($field)) { + $options['order'][$alias . '.' . $field] = $value; + } elseif ($object->hasField($field, true)) { + $options['order'][$field] = $value; + } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) { + $options['order'][$alias . '.' . $field] = $value; + } + } + + return $options; + } } \ No newline at end of file diff --git a/cake/tests/cases/libs/controller/components/paginator.test.php b/cake/tests/cases/libs/controller/components/paginator.test.php index 063dfaf02..9fb22993e 100644 --- a/cake/tests/cases/libs/controller/components/paginator.test.php +++ b/cake/tests/cases/libs/controller/components/paginator.test.php @@ -696,4 +696,45 @@ class PaginatorTest extends CakeTestCase { ); $this->assertEquals($expected, $result); } + +/** + * test that invalid directions are ignored. + * + * @return void + */ + function testValidateSortInvalidDirection() { + $model = $this->getMock('Model'); + $model->alias = 'model'; + $model->expects($this->any())->method('hasField')->will($this->returnValue(true)); + + $options = array('sort' => 'something', 'direction' => 'boogers'); + $result = $this->Paginator->validateSort($model, $options); + + $this->assertEquals('asc', $result['order']['model.something']); + } + +/** + * test that virtual fields work. + * + * @return void + */ + function testValidateSortVirtualField() { + $model = $this->getMock('Model'); + $model->alias = 'model'; + + $model->expects($this->at(0)) + ->method('hasField') + ->with('something') + ->will($this->returnValue(false)); + + $model->expects($this->at(1)) + ->method('hasField') + ->with('something', true) + ->will($this->returnValue(true)); + + $options = array('sort' => 'something', 'direction' => 'desc'); + $result = $this->Paginator->validateSort($model, $options); + + $this->assertEquals('desc', $result['order']['something']); + } } \ No newline at end of file