From ed233e7167f2b693c90fa30fbba0d1ba58d3ec6d Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 18 Mar 2016 05:45:06 -0400 Subject: [PATCH] Implement mulitple paginators This change provides the initial support for multiple paginators on a given page. To use it, you can do something like the following in your controller layer: ```php $users = $this->paginate($this->Users->find(), ['prefix' => 'users']); $categories = $this->paginate($this->Categories->find(), ['prefix' => 'categories']); $this->set(compact('users', 'categories')); ``` The in your view layer, specify the model option whenever the `PaginatorHelper` allows you to set options. Closes #1731 --- .../Component/PaginatorComponent.php | 11 ++++-- src/Controller/Controller.php | 6 ++-- src/View/Helper/PaginatorHelper.php | 34 ++++++++++++++++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/Controller/Component/PaginatorComponent.php b/src/Controller/Component/PaginatorComponent.php index d1d24501939..8357d86a37c 100644 --- a/src/Controller/Component/PaginatorComponent.php +++ b/src/Controller/Component/PaginatorComponent.php @@ -18,6 +18,7 @@ use Cake\Datasource\QueryInterface; use Cake\Datasource\RepositoryInterface; use Cake\Network\Exception\NotFoundException; +use Cake\Utility\Hash; /** * This component is used to handle automatic model data pagination. The primary way to use this @@ -202,7 +203,8 @@ public function paginate($object, array $settings = []) 'direction' => current($order), 'limit' => $defaults['limit'] != $limit ? $limit : null, 'sortDefault' => $sortDefault, - 'directionDefault' => $directionDefault + 'directionDefault' => $directionDefault, + 'prefix' => Hash::get($options, 'prefix', null), ]; if (!isset($request['paging'])) { @@ -257,7 +259,12 @@ public function mergeOptions($alias, $settings) { $defaults = $this->getDefaults($alias, $settings); $request = $this->_registry->getController()->request; - $request = array_intersect_key($request->query, array_flip($this->_config['whitelist'])); + $prefix = Hash::get($settings, 'prefix', null); + $query = $request->query; + if ($prefix) { + $query = Hash::get($request->query, $prefix, []); + } + $request = array_intersect_key($query, array_flip($this->_config['whitelist'])); return array_merge($defaults, $request); } diff --git a/src/Controller/Controller.php b/src/Controller/Controller.php index 4a6d4ff792e..7b6a34b473e 100644 --- a/src/Controller/Controller.php +++ b/src/Controller/Controller.php @@ -671,11 +671,12 @@ public function referer($default = null, $local = false) * * @param \Cake\ORM\Table|string|\Cake\ORM\Query|null $object Table to paginate * (e.g: Table instance, 'TableName' or a Query object) + * @param array $settings The settings/configuration used for pagination. * @return \Cake\ORM\ResultSet Query results * @link http://book.cakephp.org/3.0/en/controllers.html#paginating-a-model * @throws \RuntimeException When no compatible table object can be found. */ - public function paginate($object = null) + public function paginate($object = null, array $settings = []) { if (is_object($object)) { $table = $object; @@ -696,7 +697,8 @@ public function paginate($object = null) if (empty($table)) { throw new RuntimeException('Unable to locate an object compatible with paginate.'); } - return $this->Paginator->paginate($table, $this->paginate); + $settings = $settings + $this->paginate; + return $this->Paginator->paginate($table, $settings); } /** diff --git a/src/View/Helper/PaginatorHelper.php b/src/View/Helper/PaginatorHelper.php index 48f441eba16..ee04fe73e0d 100644 --- a/src/View/Helper/PaginatorHelper.php +++ b/src/View/Helper/PaginatorHelper.php @@ -14,6 +14,7 @@ */ namespace Cake\View\Helper; +use Cake\Utility\Hash; use Cake\Utility\Inflector; use Cake\View\Helper; use Cake\View\StringTemplateTrait; @@ -165,6 +166,12 @@ public function options(array $options = []) unset($options[$model]); } $this->_config['options'] = array_filter($options + $this->_config['options']); + if (empty($this->_config['options']['url'])) { + $this->_config['options']['url'] = []; + } + if (!empty($this->_config['options']['model'])) { + $this->defaultModel($this->_config['options']['model']); + } } /** @@ -412,10 +419,16 @@ public function sort($key, $title = null, array $options = []) $sortKey = $this->sortKey($options['model']); $defaultModel = $this->defaultModel(); + $model = Hash::get($options, 'model', $defaultModel); + list($table, $field) = explode('.', $key . '.'); + if (!$field) { + $field = $table; + $table = $model; + } $isSorted = ( - $sortKey === $key || + $sortKey === $table . '.' . $field || $sortKey === $defaultModel . '.' . $key || - $key === $defaultModel . '.' . $sortKey + $table . '.' . $field === $defaultModel . '.' . $sortKey ); $template = 'sort'; @@ -465,7 +478,8 @@ public function generateUrl(array $options = [], $model = null, $full = false) ]; if (!empty($this->_config['options']['url'])) { - $url = array_merge($url, $this->_config['options']['url']); + $key = implode('.', array_filter(['options.url', Hash::get($paging, 'prefix', null)])); + $url = array_merge($url, Hash::get($this->_config, $key, [])); } $url = array_filter($url, function ($value) { @@ -482,6 +496,12 @@ public function generateUrl(array $options = [], $model = null, $full = false) ) { $url['sort'] = $url['direction'] = null; } + if (!empty($paging['prefix'])) { + $url = [$paging['prefix'] => $url] + $this->_config['options']['url']; + if (empty($url[$paging['prefix']]['page'])) { + unset($url[$paging['prefix']]['page']); + } + } return $this->Url->build($url, $full); } @@ -544,12 +564,16 @@ protected function _hasPage($model, $page) } /** - * Gets the default model of the paged sets + * Gets or sets the default model of the paged sets * + * @param string|null $model Model name to set * @return string|null Model name or null if the pagination isn't initialized. */ - public function defaultModel() + public function defaultModel($model = null) { + if ($model !== null) { + $this->_defaultModel = $model; + } if ($this->_defaultModel) { return $this->_defaultModel; }