Skip to content

Commit

Permalink
Paginator now supports ordering by multiple fields.
Browse files Browse the repository at this point in the history
  • Loading branch information
Code-Working authored and markstory committed Sep 15, 2017
1 parent 5564feb commit b0ec150
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
10 changes: 7 additions & 3 deletions src/Datasource/Paginator.php
Expand Up @@ -215,6 +215,7 @@ public function paginate($object, array $params = [], array $settings = [])
'sortDefault' => $sortDefault,
'directionDefault' => $directionDefault,
'scope' => $options['scope'],
'completeSort' => $order,
];

$this->_pagingParams = [$alias => $paging];
Expand Down Expand Up @@ -323,7 +324,7 @@ public function getDefaults($alias, $settings)
* the model friendly order key.
*
* You can use the whitelist parameter to control which columns/fields are
* available for sorting. This helps prevent users from ordering large
* available for sorting via URL parameters. 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
Expand All @@ -333,6 +334,9 @@ public function getDefaults($alias, $settings)
* You can use this to sort on synthetic columns, or columns added in custom
* find operations that may not exist in the schema.
*
* The default order options provided to paginate() will be merged with the user's
* requested sorting field/direction.
*
* @param \Cake\Datasource\RepositoryInterface $object Repository object.
* @param array $options The pagination options being used for this request.
* @return array An array of options with sort + direction removed and
Expand All @@ -348,7 +352,8 @@ public function validateSort(RepositoryInterface $object, array $options)
if (!in_array($direction, ['asc', 'desc'])) {
$direction = 'asc';
}
$options['order'] = [$options['sort'] => $direction];
$order = (isset($options['order']) && is_array($options['order'])) ? $options['order'] : [];
$options['order'] = [$options['sort'] => $direction] + $order;
}
unset($options['sort'], $options['direction']);

Expand All @@ -369,7 +374,6 @@ public function validateSort(RepositoryInterface $object, array $options)
return $options;
}
}

$options['order'] = $this->_prefix($object, $options['order'], $inWhitelist);

return $options;
Expand Down
64 changes: 64 additions & 0 deletions tests/TestCase/Controller/Component/PaginatorComponentTest.php
Expand Up @@ -934,13 +934,77 @@ public function testValidateSortMultiple()
]
];
$result = $this->Paginator->validateSort($model, $options);

$expected = [
'model.author_id' => 'asc',
'model.title' => 'asc'
];

$this->assertEquals($expected, $result['order']);
}

/**
* test that multiple sort works in combination with query.
*
* @return void
*/
public function testValidateSortMultipleWithQuery()
{
$this->loadFixtures('Posts');
$table = TableRegistry::get('PaginatorPosts');

$titleExtractor = function ($result) {
$ids = [];
foreach ($result as $record) {
$ids[] = $record->title;
}
return $ids;
};

// Define two columns as default sort order
$settings = [
'order' => [
'author_id' => 'asc',
'title' => 'asc'
]
];

// Test with empty query
$this->request->query = [];
$result = $this->Paginator->paginate($table, $settings);
$this->assertCount(3, $result, '3 rows should come back');
$this->assertEquals(['First Post', 'Third Post', 'Second Post'], $titleExtractor($result));
$this->assertEquals(
['PaginatorPosts.author_id' => 'asc', 'PaginatorPosts.title' => 'asc'],
$this->request->params['paging']['PaginatorPosts']['totalOrder']
);

// Test overwriting a sort field defined in the settings
$this->request->query = [
'sort' => 'author_id',
'direction' => 'desc'
];
$result = $this->Paginator->paginate($table, $settings);
$this->assertCount(3, $result, '3 rows should come back');
$this->assertEquals(['Second Post', 'First Post', 'Third Post'], $titleExtractor($result));
$this->assertEquals(
['PaginatorPosts.author_id' => 'desc', 'PaginatorPosts.title' => 'asc'],
$this->request->params['paging']['PaginatorPosts']['totalOrder']
);

// Test sorting by a field not defined in the settings
$this->request->query = [
'sort' => 'id',
'direction' => 'asc'
];
$result = $this->Paginator->paginate($table, $settings);
$this->assertCount(3, $result, '3 rows should come back');
$this->assertEquals(['First Post', 'Second Post', 'Third Post'], $titleExtractor($result));
$this->assertEquals(
['PaginatorPosts.id' => 'asc', 'PaginatorPosts.author_id' => 'asc', 'PaginatorPosts.title' => 'asc'],
$this->request->params['paging']['PaginatorPosts']['totalOrder']
);
}

/**
* Tests that order strings can used by Paginator
Expand Down

0 comments on commit b0ec150

Please sign in to comment.