Browse Source

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
Jose Diaz-Gonzalez 10 years ago
parent
commit
ed233e7167

+ 9 - 2
src/Controller/Component/PaginatorComponent.php

@@ -18,6 +18,7 @@ use Cake\Controller\Component;
 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 @@ class PaginatorComponent extends Component
             '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 @@ class PaginatorComponent extends Component
     {
         $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);
     }
 

+ 4 - 2
src/Controller/Controller.php

@@ -671,11 +671,12 @@ class Controller implements EventListenerInterface, EventDispatcherInterface
      *
      * @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 @@ class Controller implements EventListenerInterface, EventDispatcherInterface
         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);
     }
 
     /**

+ 29 - 5
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 @@ class PaginatorHelper extends Helper
             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 @@ class PaginatorHelper extends Helper
 
         $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 @@ class PaginatorHelper extends Helper
         ];
 
         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 @@ class PaginatorHelper extends Helper
         ) {
             $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 @@ class PaginatorHelper extends Helper
     }
 
     /**
-     * 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;
         }