Skip to content

Commit

Permalink
Move sort whitelists into the settings.
Browse files Browse the repository at this point in the history
Having one inclusive set of settings makes configuring
PaginatorComponent much simpler.
  • Loading branch information
markstory committed Nov 21, 2013
1 parent 8752235 commit e85784d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 22 deletions.
40 changes: 24 additions & 16 deletions Cake/Controller/Component/PaginatorComponent.php
Expand Up @@ -95,7 +95,23 @@ class PaginatorComponent extends Component {
*
* This would allow you to have different pagination settings for `Comments` and `Posts` tables.
*
* #### Paginating with custom finders
* ### Controlling sort fields
*
* By default CakePHP will automatically allow sorting on any column on the table object being
* paginated. Often times you will want to allow sorting on either associated columns or calculated
* fields. In these cases you will need to define a whitelist of all the columns you wish to allow
* sorting on. You can define the whitelist in the `$settings` parameter:
*
* {{{
* $settings = [
* 'Articles' => [
* 'findType' => 'custom',
* 'sortWhitelist' => ['title', 'author_id', 'comment_count'],
* ]
* ];
* }}}
*
* ### Paginating with custom finders
*
* You can paginate with any find type defined on your table using the `findType` option.
*
Expand All @@ -112,14 +128,11 @@ class PaginatorComponent extends Component {
*
* @param Table $object The table to paginate.
* @param array $settings The settings/configuration used for pagination.
* @param array $whitelist List of allowed fields for ordering. This allows you to prevent ordering
* on non-indexed, or undesirable columns. See PaginatorComponent::validateSort() for additional details
* on how the whitelisting and sort field validation works.
* @return array Query results
* @throws Cake\Error\MissingModelException
* @throws Cake\Error\NotFoundException
*/
public function paginate($object, $settings = array(), $whitelist = array()) {
public function paginate($object, array $settings = []) {
$alias = $object->alias();

$options = $this->mergeOptions($alias, $settings);
Expand All @@ -133,18 +146,12 @@ public function paginate($object, $settings = array(), $whitelist = array()) {
$options['conditions'] = [];
}

$type = 'all';

if (isset($options[0])) {
$type = $options[0];
unset($options[0]);
}

extract($options);
$extra = array_diff_key($options, compact(
'conditions', 'fields', 'order', 'limit', 'page'
));

$type = 'all';
if (!empty($extra['findType'])) {
$type = $extra['findType'];
}
Expand All @@ -158,7 +165,6 @@ public function paginate($object, $settings = array(), $whitelist = array()) {
$parameters = compact('conditions', 'fields', 'order', 'limit', 'page');
$query = $object->find($type, array_merge($parameters, $extra));

// TODO Validate sort and apply them here.
$results = $query->execute();
$numResults = count($results);

Expand Down Expand Up @@ -263,6 +269,8 @@ public function getDefaults($alias, $defaults) {
* You can use the whitelist parameter to control which columns/fields are available for sorting.
* This helps prevent users from ordering large result sets on un-indexed values.
*
* If you need to sort on associated columns or synthetic properties you will need to use a whitelist.
*
* Any columns listed in the sort whitelist will be implicitly trusted. You can use this to sort
* on synthetic columns, or columns added in custom find operations that may not exist in the schema.
*
Expand All @@ -271,7 +279,7 @@ public function getDefaults($alias, $defaults) {
* @param array $whitelist The list of columns that can be used for sorting. If empty all keys are allowed.
* @return array An array of options with sort + direction removed and replaced with order if possible.
*/
public function validateSort(Table $object, array $options, array $whitelist = array()) {
public function validateSort(Table $object, array $options) {
if (isset($options['sort'])) {
$direction = null;
if (isset($options['direction'])) {
Expand All @@ -291,9 +299,9 @@ public function validateSort(Table $object, array $options, array $whitelist = a
$options['order'] = (array)$options['order'];
}

if (!empty($whitelist)) {
if (!empty($options['sortWhitelist'])) {
$field = key($options['order']);
$inWhitelist = in_array($field, $whitelist, true);
$inWhitelist = in_array($field, $options['sortWhitelist'], true);
if (!$inWhitelist) {
$options['order'] = [];
}
Expand Down
23 changes: 17 additions & 6 deletions Cake/Test/TestCase/Controller/Component/PaginatorComponentTest.php
Expand Up @@ -437,8 +437,12 @@ public function testValidateSortWhitelistFailure() {
->will($this->returnValue('model'));
$model->expects($this->any())->method('hasField')->will($this->returnValue(true));

$options = array('sort' => 'body', 'direction' => 'asc');
$result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
$options = array(
'sort' => 'body',
'direction' => 'asc',
'sortWhitelist' => ['title', 'id']
);
$result = $this->Paginator->validateSort($model, $options);

$this->assertEquals([], $result['order']);
}
Expand All @@ -455,8 +459,12 @@ public function testValidateSortWhitelistTrusted() {
->will($this->returnValue('model'));
$model->expects($this->never())->method('hasField');

$options = array('sort' => 'body', 'direction' => 'asc');
$result = $this->Paginator->validateSort($model, $options, array('body'));
$options = array(
'sort' => 'body',
'direction' => 'asc',
'sortWhitelist' => ['body']
);
$result = $this->Paginator->validateSort($model, $options);

$expected = array('body' => 'asc');
$this->assertEquals($expected, $result['order']);
Expand Down Expand Up @@ -502,8 +510,11 @@ public function testValidateSortNoSort() {
$model->expects($this->any())->method('hasField')
->will($this->returnValue(true));

$options = array('direction' => 'asc');
$result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
$options = array(
'direction' => 'asc',
'sortWhitelist' => ['title', 'id'],
);
$result = $this->Paginator->validateSort($model, $options);
$this->assertEquals([], $result['order']);
}

Expand Down

0 comments on commit e85784d

Please sign in to comment.