CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 2.2 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.2
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Acl
        • Auth
    • Core
    • Error
    • Event
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
      • Validator
    • Network
      • Email
      • Http
    • Routing
      • Filter
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper

Classes

  • AclComponent
  • AuthComponent
  • CookieComponent
  • EmailComponent
  • PaginatorComponent
  • RequestHandlerComponent
  • SecurityComponent
  • SessionComponent
  1: <?php
  2: /**
  3:  * Paginator Component
  4:  *
  5:  * PHP 5
  6:  *
  7:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8:  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9:  *
 10:  * Licensed under The MIT License
 11:  * Redistributions of files must retain the above copyright notice.
 12:  *
 13:  * @copyright     Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
 14:  * @link          http://cakephp.org CakePHP(tm) Project
 15:  * @package       Cake.Controller.Component
 16:  * @since         CakePHP(tm) v 2.0
 17:  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 18:  */
 19: App::uses('Hash', 'Utility');
 20: 
 21: /**
 22:  * This component is used to handle automatic model data pagination.  The primary way to use this
 23:  * component is to call the paginate() method. There is a convenience wrapper on Controller as well.
 24:  *
 25:  * ### Configuring pagination
 26:  *
 27:  * You configure pagination using the PaginatorComponent::$settings.  This allows you to configure
 28:  * the default pagination behavior in general or for a specific model. General settings are used when there
 29:  * are no specific model configuration, or the model you are paginating does not have specific settings.
 30:  *
 31:  * {{{
 32:  *  $this->Paginator->settings = array(
 33:  *      'limit' => 20,
 34:  *      'maxLimit' => 100
 35:  *  );
 36:  * }}}
 37:  *
 38:  * The above settings will be used to paginate any model.  You can configure model specific settings by
 39:  * keying the settings with the model name.
 40:  *
 41:  * {{{
 42:  *  $this->Paginator->settings = array(
 43:  *      'Post' => array(
 44:  *          'limit' => 20,
 45:  *          'maxLimit' => 100
 46:  *      ),
 47:  *      'Comment' => array( ... )
 48:  *  );
 49:  * }}}
 50:  *
 51:  * This would allow you to have different pagination settings for `Comment` and `Post` models.
 52:  *
 53:  * @package       Cake.Controller.Component
 54:  * @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
 55:  */
 56: class PaginatorComponent extends Component {
 57: 
 58: /**
 59:  * Pagination settings.  These settings control pagination at a general level.
 60:  * You can also define sub arrays for pagination settings for specific models.
 61:  *
 62:  * - `maxLimit` The maximum limit users can choose to view. Defaults to 100
 63:  * - `limit` The initial number of items per page.  Defaults to 20.
 64:  * - `page` The starting page, defaults to 1.
 65:  * - `paramType` What type of parameters you want pagination to use?
 66:  *      - `named` Use named parameters / routed parameters.
 67:  *      - `querystring` Use query string parameters.
 68:  *
 69:  * @var array
 70:  */
 71:     public $settings = array(
 72:         'page' => 1,
 73:         'limit' => 20,
 74:         'maxLimit' => 100,
 75:         'paramType' => 'named'
 76:     );
 77: 
 78: /**
 79:  * A list of parameters users are allowed to set using request parameters.  Modifying
 80:  * this list will allow users to have more influence over pagination,
 81:  * be careful with what you permit.
 82:  *
 83:  * @var array
 84:  */
 85:     public $whitelist = array(
 86:         'limit', 'sort', 'page', 'direction'
 87:     );
 88: 
 89: /**
 90:  * Constructor
 91:  *
 92:  * @param ComponentCollection $collection A ComponentCollection this component can use to lazy load its components
 93:  * @param array $settings Array of configuration settings.
 94:  */
 95:     public function __construct(ComponentCollection $collection, $settings = array()) {
 96:         $settings = array_merge($this->settings, (array)$settings);
 97:         $this->Controller = $collection->getController();
 98:         parent::__construct($collection, $settings);
 99:     }
100: 
101: /**
102:  * Handles automatic pagination of model records.
103:  *
104:  * @param Model|string $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
105:  * @param string|array $scope Additional find conditions to use while paginating
106:  * @param array $whitelist List of allowed fields for ordering.  This allows you to prevent ordering
107:  *   on non-indexed, or undesirable columns.
108:  * @return array Model query results
109:  * @throws MissingModelException
110:  */
111:     public function paginate($object = null, $scope = array(), $whitelist = array()) {
112:         if (is_array($object)) {
113:             $whitelist = $scope;
114:             $scope = $object;
115:             $object = null;
116:         }
117: 
118:         $object = $this->_getObject($object);
119: 
120:         if (!is_object($object)) {
121:             throw new MissingModelException($object);
122:         }
123: 
124:         $options = $this->mergeOptions($object->alias);
125:         $options = $this->validateSort($object, $options, $whitelist);
126:         $options = $this->checkLimit($options);
127: 
128:         $conditions = $fields = $order = $limit = $page = $recursive = null;
129: 
130:         if (!isset($options['conditions'])) {
131:             $options['conditions'] = array();
132:         }
133: 
134:         $type = 'all';
135: 
136:         if (isset($options[0])) {
137:             $type = $options[0];
138:             unset($options[0]);
139:         }
140: 
141:         extract($options);
142: 
143:         if (is_array($scope) && !empty($scope)) {
144:             $conditions = array_merge($conditions, $scope);
145:         } elseif (is_string($scope)) {
146:             $conditions = array($conditions, $scope);
147:         }
148:         if ($recursive === null) {
149:             $recursive = $object->recursive;
150:         }
151: 
152:         $extra = array_diff_key($options, compact(
153:             'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
154:         ));
155:         if ($type !== 'all') {
156:             $extra['type'] = $type;
157:         }
158: 
159:         if (intval($page) < 1) {
160:             $page = 1;
161:         }
162:         $page = $options['page'] = (int)$page;
163: 
164:         if ($object->hasMethod('paginate')) {
165:             $results = $object->paginate(
166:                 $conditions, $fields, $order, $limit, $page, $recursive, $extra
167:             );
168:         } else {
169:             $parameters = compact('conditions', 'fields', 'order', 'limit', 'page');
170:             if ($recursive != $object->recursive) {
171:                 $parameters['recursive'] = $recursive;
172:             }
173:             $results = $object->find($type, array_merge($parameters, $extra));
174:         }
175:         $defaults = $this->getDefaults($object->alias);
176:         unset($defaults[0]);
177: 
178:         if ($object->hasMethod('paginateCount')) {
179:             $count = $object->paginateCount($conditions, $recursive, $extra);
180:         } else {
181:             $parameters = compact('conditions');
182:             if ($recursive != $object->recursive) {
183:                 $parameters['recursive'] = $recursive;
184:             }
185:             $count = $object->find('count', array_merge($parameters, $extra));
186:         }
187:         $pageCount = intval(ceil($count / $limit));
188:         $page = max(min($page, $pageCount), 1);
189: 
190:         $paging = array(
191:             'page' => $page,
192:             'current' => count($results),
193:             'count' => $count,
194:             'prevPage' => ($page > 1),
195:             'nextPage' => ($count > ($page * $limit)),
196:             'pageCount' => $pageCount,
197:             'order' => $order,
198:             'limit' => $limit,
199:             'options' => Hash::diff($options, $defaults),
200:             'paramType' => $options['paramType']
201:         );
202:         if (!isset($this->Controller->request['paging'])) {
203:             $this->Controller->request['paging'] = array();
204:         }
205:         $this->Controller->request['paging'] = array_merge(
206:             (array)$this->Controller->request['paging'],
207:             array($object->alias => $paging)
208:         );
209: 
210:         if (
211:             !in_array('Paginator', $this->Controller->helpers) &&
212:             !array_key_exists('Paginator', $this->Controller->helpers)
213:         ) {
214:             $this->Controller->helpers[] = 'Paginator';
215:         }
216:         return $results;
217:     }
218: 
219: /**
220:  * Get the object pagination will occur on.
221:  *
222:  * @param string|Model $object The object you are looking for.
223:  * @return mixed The model object to paginate on.
224:  */
225:     protected function _getObject($object) {
226:         if (is_string($object)) {
227:             $assoc = null;
228:             if (strpos($object, '.') !== false) {
229:                 list($object, $assoc) = pluginSplit($object);
230:             }
231: 
232:             if ($assoc && isset($this->Controller->{$object}->{$assoc})) {
233:                 $object = $this->Controller->{$object}->{$assoc};
234:             } elseif (
235:                 $assoc && isset($this->Controller->{$this->Controller->modelClass}) &&
236:                 isset($this->Controller->{$this->Controller->modelClass}->{$assoc}
237:             )) {
238:                 $object = $this->Controller->{$this->Controller->modelClass}->{$assoc};
239:             } elseif (isset($this->Controller->{$object})) {
240:                 $object = $this->Controller->{$object};
241:             } elseif (
242:                 isset($this->Controller->{$this->Controller->modelClass}) && isset($this->Controller->{$this->Controller->modelClass}->{$object}
243:             )) {
244:                 $object = $this->Controller->{$this->Controller->modelClass}->{$object};
245:             }
246:         } elseif (empty($object) || $object === null) {
247:             if (isset($this->Controller->{$this->Controller->modelClass})) {
248:                 $object = $this->Controller->{$this->Controller->modelClass};
249:             } else {
250:                 $className = null;
251:                 $name = $this->Controller->uses[0];
252:                 if (strpos($this->Controller->uses[0], '.') !== false) {
253:                     list($name, $className) = explode('.', $this->Controller->uses[0]);
254:                 }
255:                 if ($className) {
256:                     $object = $this->Controller->{$className};
257:                 } else {
258:                     $object = $this->Controller->{$name};
259:                 }
260:             }
261:         }
262:         return $object;
263:     }
264: 
265: /**
266:  * Merges the various options that Pagination uses.
267:  * Pulls settings together from the following places:
268:  *
269:  * - General pagination settings
270:  * - Model specific settings.
271:  * - Request parameters
272:  *
273:  * The result of this method is the aggregate of all the option sets combined together.  You can change
274:  * PaginatorComponent::$whitelist to modify which options/values can be set using request parameters.
275:  *
276:  * @param string $alias Model alias being paginated, if the general settings has a key with this value
277:  *   that key's settings will be used for pagination instead of the general ones.
278:  * @return array Array of merged options.
279:  */
280:     public function mergeOptions($alias) {
281:         $defaults = $this->getDefaults($alias);
282:         switch ($defaults['paramType']) {
283:             case 'named':
284:                 $request = $this->Controller->request->params['named'];
285:                 break;
286:             case 'querystring':
287:                 $request = $this->Controller->request->query;
288:                 break;
289:         }
290:         $request = array_intersect_key($request, array_flip($this->whitelist));
291:         return array_merge($defaults, $request);
292:     }
293: 
294: /**
295:  * Get the default settings for a $model.  If there are no settings for a specific model, the general settings
296:  * will be used.
297:  *
298:  * @param string $alias Model name to get default settings for.
299:  * @return array An array of pagination defaults for a model, or the general settings.
300:  */
301:     public function getDefaults($alias) {
302:         if (isset($this->settings[$alias])) {
303:             $defaults = $this->settings[$alias];
304:         } else {
305:             $defaults = $this->settings;
306:         }
307:         return array_merge(
308:             array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'),
309:             $defaults
310:         );
311:     }
312: 
313: /**
314:  * Validate that the desired sorting can be performed on the $object.  Only fields or
315:  * virtualFields can be sorted on.  The direction param will also be sanitized.  Lastly
316:  * sort + direction keys will be converted into the model friendly order key.
317:  *
318:  * You can use the whitelist parameter to control which columns/fields are available for sorting.
319:  * This helps prevent users from ordering large result sets on un-indexed values.
320:  *
321:  * @param Model $object The model being paginated.
322:  * @param array $options The pagination options being used for this request.
323:  * @param array $whitelist The list of columns that can be used for sorting.  If empty all keys are allowed.
324:  * @return array An array of options with sort + direction removed and replaced with order if possible.
325:  */
326:     public function validateSort($object, $options, $whitelist = array()) {
327:         if (isset($options['sort'])) {
328:             $direction = null;
329:             if (isset($options['direction'])) {
330:                 $direction = strtolower($options['direction']);
331:             }
332:             if ($direction != 'asc' && $direction != 'desc') {
333:                 $direction = 'asc';
334:             }
335:             $options['order'] = array($options['sort'] => $direction);
336:         }
337: 
338:         if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
339:             $field = key($options['order']);
340:             if (!in_array($field, $whitelist)) {
341:                 $options['order'] = null;
342:                 return $options;
343:             }
344:         }
345: 
346:         if (!empty($options['order']) && is_array($options['order'])) {
347:             $order = array();
348:             foreach ($options['order'] as $key => $value) {
349:                 $field = $key;
350:                 $alias = $object->alias;
351:                 if (strpos($key, '.') !== false) {
352:                     list($alias, $field) = explode('.', $key);
353:                 }
354: 
355:                 if ($object->hasField($field)) {
356:                     $order[$object->alias . '.' . $field] = $value;
357:                 } elseif ($object->hasField($key, true)) {
358:                     $order[$field] = $value;
359:                 } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
360:                     $order[$alias . '.' . $field] = $value;
361:                 }
362:             }
363:             $options['order'] = $order;
364:         }
365: 
366:         return $options;
367:     }
368: 
369: /**
370:  * Check the limit parameter and ensure its within the maxLimit bounds.
371:  *
372:  * @param array $options An array of options with a limit key to be checked.
373:  * @return array An array of options for pagination
374:  */
375:     public function checkLimit($options) {
376:         $options['limit'] = (int)$options['limit'];
377:         if (empty($options['limit']) || $options['limit'] < 1) {
378:             $options['limit'] = 1;
379:         }
380:         $options['limit'] = min($options['limit'], $options['maxLimit']);
381:         return $options;
382:     }
383: 
384: }
385: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs