1 | <?php |
---|
2 | /** |
---|
3 | * Base controller class. |
---|
4 | * |
---|
5 | * PHP versions 4 and 5 |
---|
6 | * |
---|
7 | * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) |
---|
8 | * Copyright 2005-2011, 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-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) |
---|
14 | * @link http://cakephp.org CakePHP(tm) Project |
---|
15 | * @package cake |
---|
16 | * @subpackage cake.cake.libs.controller |
---|
17 | * @since CakePHP(tm) v 0.2.9 |
---|
18 | * @license MIT License (http://www.opensource.org/licenses/mit-license.php) |
---|
19 | */ |
---|
20 | |
---|
21 | /** |
---|
22 | * Include files |
---|
23 | */ |
---|
24 | App::import('Controller', 'Component', false); |
---|
25 | App::import('View', 'View', false); |
---|
26 | /** |
---|
27 | * Controller |
---|
28 | * |
---|
29 | * Application controller class for organization of business logic. |
---|
30 | * Provides basic functionality, such as rendering views inside layouts, |
---|
31 | * automatic model availability, redirection, callbacks, and more. |
---|
32 | * |
---|
33 | * @package cake |
---|
34 | * @subpackage cake.cake.libs.controller |
---|
35 | * @link http://book.cakephp.org/view/956/Introduction |
---|
36 | */ |
---|
37 | class Controller extends Object { |
---|
38 | |
---|
39 | /** |
---|
40 | * The name of this controller. Controller names are plural, named after the model they manipulate. |
---|
41 | * |
---|
42 | * @var string |
---|
43 | * @access public |
---|
44 | * @link http://book.cakephp.org/view/959/Controller-Attributes |
---|
45 | */ |
---|
46 | var $name = null; |
---|
47 | |
---|
48 | /** |
---|
49 | * Stores the current URL, relative to the webroot of the application. |
---|
50 | * |
---|
51 | * @var string |
---|
52 | * @access public |
---|
53 | */ |
---|
54 | var $here = null; |
---|
55 | |
---|
56 | /** |
---|
57 | * The webroot of the application. |
---|
58 | * |
---|
59 | * @var string |
---|
60 | * @access public |
---|
61 | */ |
---|
62 | var $webroot = null; |
---|
63 | |
---|
64 | /** |
---|
65 | * The name of the currently requested controller action. |
---|
66 | * |
---|
67 | * @var string |
---|
68 | * @access public |
---|
69 | */ |
---|
70 | var $action = null; |
---|
71 | |
---|
72 | /** |
---|
73 | * An array containing the class names of models this controller uses. |
---|
74 | * |
---|
75 | * Example: `var $uses = array('Product', 'Post', 'Comment');` |
---|
76 | * |
---|
77 | * Can be set to array() to use no models. Can be set to false to |
---|
78 | * use no models and prevent the merging of $uses with AppController |
---|
79 | * |
---|
80 | * @var mixed A single name as a string or a list of names as an array. |
---|
81 | * @access protected |
---|
82 | * @link http://book.cakephp.org/view/961/components-helpers-and-uses |
---|
83 | */ |
---|
84 | var $uses = false; |
---|
85 | |
---|
86 | /** |
---|
87 | * An array containing the names of helpers this controller uses. The array elements should |
---|
88 | * not contain the "Helper" part of the classname. |
---|
89 | * |
---|
90 | * Example: `var $helpers = array('Html', 'Javascript', 'Time', 'Ajax');` |
---|
91 | * |
---|
92 | * @var mixed A single name as a string or a list of names as an array. |
---|
93 | * @access protected |
---|
94 | * @link http://book.cakephp.org/view/961/components-helpers-and-uses |
---|
95 | */ |
---|
96 | var $helpers = array('Session', 'Html', 'Form'); |
---|
97 | |
---|
98 | /** |
---|
99 | * Parameters received in the current request: GET and POST data, information |
---|
100 | * about the request, etc. |
---|
101 | * |
---|
102 | * @var array |
---|
103 | * @access public |
---|
104 | * @link http://book.cakephp.org/view/963/The-Parameters-Attribute-params |
---|
105 | */ |
---|
106 | var $params = array(); |
---|
107 | |
---|
108 | /** |
---|
109 | * Data POSTed to the controller using the HtmlHelper. Data here is accessible |
---|
110 | * using the `$this->data['ModelName']['fieldName']` pattern. |
---|
111 | * |
---|
112 | * @var array |
---|
113 | * @access public |
---|
114 | */ |
---|
115 | var $data = array(); |
---|
116 | |
---|
117 | /** |
---|
118 | * Holds pagination defaults for controller actions. The keys that can be included |
---|
119 | * in this array are: 'conditions', 'fields', 'order', 'limit', 'page', and 'recursive', |
---|
120 | * similar to the keys in the second parameter of Model::find(). |
---|
121 | * |
---|
122 | * Pagination defaults can also be supplied in a model-by-model basis by using |
---|
123 | * the name of the model as a key for a pagination array: |
---|
124 | * |
---|
125 | * {{{ |
---|
126 | * var $paginate = array( |
---|
127 | * 'Post' => array(...), |
---|
128 | * 'Comment' => array(...) |
---|
129 | * ); |
---|
130 | * }}} |
---|
131 | * |
---|
132 | * @var array |
---|
133 | * @access public |
---|
134 | * @link http://book.cakephp.org/view/1231/Pagination |
---|
135 | */ |
---|
136 | var $paginate = array('limit' => 20, 'page' => 1); |
---|
137 | |
---|
138 | /** |
---|
139 | * The name of the views subfolder containing views for this controller. |
---|
140 | * |
---|
141 | * @var string |
---|
142 | * @access public |
---|
143 | */ |
---|
144 | var $viewPath = null; |
---|
145 | |
---|
146 | /** |
---|
147 | * The name of the layouts subfolder containing layouts for this controller. |
---|
148 | * |
---|
149 | * @var string |
---|
150 | * @access public |
---|
151 | */ |
---|
152 | var $layoutPath = null; |
---|
153 | |
---|
154 | /** |
---|
155 | * Contains variables to be handed to the view. |
---|
156 | * |
---|
157 | * @var array |
---|
158 | * @access public |
---|
159 | */ |
---|
160 | var $viewVars = array(); |
---|
161 | |
---|
162 | /** |
---|
163 | * An array containing the class names of the models this controller uses. |
---|
164 | * |
---|
165 | * @var array Array of model objects. |
---|
166 | * @access public |
---|
167 | */ |
---|
168 | var $modelNames = array(); |
---|
169 | |
---|
170 | /** |
---|
171 | * Base URL path. |
---|
172 | * |
---|
173 | * @var string |
---|
174 | * @access public |
---|
175 | */ |
---|
176 | var $base = null; |
---|
177 | |
---|
178 | /** |
---|
179 | * The name of the layout file to render the view inside of. The name specified |
---|
180 | * is the filename of the layout in /app/views/layouts without the .ctp |
---|
181 | * extension. |
---|
182 | * |
---|
183 | * @var string |
---|
184 | * @access public |
---|
185 | * @link http://book.cakephp.org/view/962/Page-related-Attributes-layout-and-pageTitle |
---|
186 | */ |
---|
187 | var $layout = 'default'; |
---|
188 | |
---|
189 | /** |
---|
190 | * Set to true to automatically render the view |
---|
191 | * after action logic. |
---|
192 | * |
---|
193 | * @var boolean |
---|
194 | * @access public |
---|
195 | */ |
---|
196 | var $autoRender = true; |
---|
197 | |
---|
198 | /** |
---|
199 | * Set to true to automatically render the layout around views. |
---|
200 | * |
---|
201 | * @var boolean |
---|
202 | * @access public |
---|
203 | */ |
---|
204 | var $autoLayout = true; |
---|
205 | |
---|
206 | /** |
---|
207 | * Instance of Component used to handle callbacks. |
---|
208 | * |
---|
209 | * @var string |
---|
210 | * @access public |
---|
211 | */ |
---|
212 | var $Component = null; |
---|
213 | |
---|
214 | /** |
---|
215 | * Array containing the names of components this controller uses. Component names |
---|
216 | * should not contain the "Component" portion of the classname. |
---|
217 | * |
---|
218 | * Example: `var $components = array('Session', 'RequestHandler', 'Acl');` |
---|
219 | * |
---|
220 | * @var array |
---|
221 | * @access public |
---|
222 | * @link http://book.cakephp.org/view/961/components-helpers-and-uses |
---|
223 | */ |
---|
224 | var $components = array('Session'); |
---|
225 | |
---|
226 | /** |
---|
227 | * The name of the View class this controller sends output to. |
---|
228 | * |
---|
229 | * @var string |
---|
230 | * @access public |
---|
231 | */ |
---|
232 | var $view = 'View'; |
---|
233 | |
---|
234 | /** |
---|
235 | * File extension for view templates. Defaults to Cake's conventional ".ctp". |
---|
236 | * |
---|
237 | * @var string |
---|
238 | * @access public |
---|
239 | */ |
---|
240 | var $ext = '.ctp'; |
---|
241 | |
---|
242 | /** |
---|
243 | * The output of the requested action. Contains either a variable |
---|
244 | * returned from the action, or the data of the rendered view; |
---|
245 | * You can use this var in child controllers' afterFilter() callbacks to alter output. |
---|
246 | * |
---|
247 | * @var string |
---|
248 | * @access public |
---|
249 | */ |
---|
250 | var $output = null; |
---|
251 | |
---|
252 | /** |
---|
253 | * Automatically set to the name of a plugin. |
---|
254 | * |
---|
255 | * @var string |
---|
256 | * @access public |
---|
257 | */ |
---|
258 | var $plugin = null; |
---|
259 | |
---|
260 | /** |
---|
261 | * Used to define methods a controller that will be cached. To cache a |
---|
262 | * single action, the value is set to an array containing keys that match |
---|
263 | * action names and values that denote cache expiration times (in seconds). |
---|
264 | * |
---|
265 | * Example: |
---|
266 | * |
---|
267 | * {{{ |
---|
268 | * var $cacheAction = array( |
---|
269 | * 'view/23/' => 21600, |
---|
270 | * 'recalled/' => 86400 |
---|
271 | * ); |
---|
272 | * }}} |
---|
273 | * |
---|
274 | * $cacheAction can also be set to a strtotime() compatible string. This |
---|
275 | * marks all the actions in the controller for view caching. |
---|
276 | * |
---|
277 | * @var mixed |
---|
278 | * @access public |
---|
279 | * @link http://book.cakephp.org/view/1380/Caching-in-the-Controller |
---|
280 | */ |
---|
281 | var $cacheAction = false; |
---|
282 | |
---|
283 | /** |
---|
284 | * Used to create cached instances of models a controller uses. |
---|
285 | * When set to true, all models related to the controller will be cached. |
---|
286 | * This can increase performance in many cases. |
---|
287 | * |
---|
288 | * @var boolean |
---|
289 | * @access public |
---|
290 | */ |
---|
291 | var $persistModel = false; |
---|
292 | |
---|
293 | /** |
---|
294 | * Holds all params passed and named. |
---|
295 | * |
---|
296 | * @var mixed |
---|
297 | * @access public |
---|
298 | */ |
---|
299 | var $passedArgs = array(); |
---|
300 | |
---|
301 | /** |
---|
302 | * Triggers Scaffolding |
---|
303 | * |
---|
304 | * @var mixed |
---|
305 | * @access public |
---|
306 | * @link http://book.cakephp.org/view/1103/Scaffolding |
---|
307 | */ |
---|
308 | var $scaffold = false; |
---|
309 | |
---|
310 | /** |
---|
311 | * Holds current methods of the controller |
---|
312 | * |
---|
313 | * @var array |
---|
314 | * @access public |
---|
315 | * @link |
---|
316 | */ |
---|
317 | var $methods = array(); |
---|
318 | |
---|
319 | /** |
---|
320 | * This controller's primary model class name, the Inflector::classify()'ed version of |
---|
321 | * the controller's $name property. |
---|
322 | * |
---|
323 | * Example: For a controller named 'Comments', the modelClass would be 'Comment' |
---|
324 | * |
---|
325 | * @var string |
---|
326 | * @access public |
---|
327 | */ |
---|
328 | var $modelClass = null; |
---|
329 | |
---|
330 | /** |
---|
331 | * This controller's model key name, an underscored version of the controller's $modelClass property. |
---|
332 | * |
---|
333 | * Example: For a controller named 'ArticleComments', the modelKey would be 'article_comment' |
---|
334 | * |
---|
335 | * @var string |
---|
336 | * @access public |
---|
337 | */ |
---|
338 | var $modelKey = null; |
---|
339 | |
---|
340 | /** |
---|
341 | * Holds any validation errors produced by the last call of the validateErrors() method/ |
---|
342 | * |
---|
343 | * @var array Validation errors, or false if none |
---|
344 | * @access public |
---|
345 | */ |
---|
346 | var $validationErrors = null; |
---|
347 | |
---|
348 | /** |
---|
349 | * Contains a list of the HTTP codes that CakePHP recognizes. These may be |
---|
350 | * queried and/or modified through Controller::httpCodes(), which is also |
---|
351 | * tasked with their lazy-loading. |
---|
352 | * |
---|
353 | * @var array Associative array of HTTP codes and their associated messages. |
---|
354 | * @access private |
---|
355 | */ |
---|
356 | var $__httpCodes = null; |
---|
357 | |
---|
358 | /** |
---|
359 | * Constructor. |
---|
360 | * |
---|
361 | */ |
---|
362 | function __construct() { |
---|
363 | if ($this->name === null) { |
---|
364 | $r = null; |
---|
365 | if (!preg_match('/(.*)Controller/i', get_class($this), $r)) { |
---|
366 | __("Controller::__construct() : Can not get or parse my own class name, exiting."); |
---|
367 | $this->_stop(); |
---|
368 | } |
---|
369 | $this->name = $r[1]; |
---|
370 | } |
---|
371 | |
---|
372 | if ($this->viewPath == null) { |
---|
373 | $this->viewPath = Inflector::underscore($this->name); |
---|
374 | } |
---|
375 | $this->modelClass = Inflector::classify($this->name); |
---|
376 | $this->modelKey = Inflector::underscore($this->modelClass); |
---|
377 | $this->Component =& new Component(); |
---|
378 | |
---|
379 | $childMethods = get_class_methods($this); |
---|
380 | $parentMethods = get_class_methods('Controller'); |
---|
381 | |
---|
382 | foreach ($childMethods as $key => $value) { |
---|
383 | $childMethods[$key] = strtolower($value); |
---|
384 | } |
---|
385 | |
---|
386 | foreach ($parentMethods as $key => $value) { |
---|
387 | $parentMethods[$key] = strtolower($value); |
---|
388 | } |
---|
389 | $this->methods = array_diff($childMethods, $parentMethods); |
---|
390 | parent::__construct(); |
---|
391 | } |
---|
392 | |
---|
393 | /** |
---|
394 | * Merge components, helpers, and uses vars from AppController and PluginAppController. |
---|
395 | * |
---|
396 | * @return void |
---|
397 | * @access protected |
---|
398 | */ |
---|
399 | function __mergeVars() { |
---|
400 | $pluginName = Inflector::camelize($this->plugin); |
---|
401 | $pluginController = $pluginName . 'AppController'; |
---|
402 | |
---|
403 | if (is_subclass_of($this, 'AppController') || is_subclass_of($this, $pluginController)) { |
---|
404 | $appVars = get_class_vars('AppController'); |
---|
405 | $uses = $appVars['uses']; |
---|
406 | $merge = array('components', 'helpers'); |
---|
407 | $plugin = null; |
---|
408 | |
---|
409 | if (!empty($this->plugin)) { |
---|
410 | $plugin = $pluginName . '.'; |
---|
411 | if (!is_subclass_of($this, $pluginController)) { |
---|
412 | $pluginController = null; |
---|
413 | } |
---|
414 | } else { |
---|
415 | $pluginController = null; |
---|
416 | } |
---|
417 | |
---|
418 | if ($uses == $this->uses && !empty($this->uses)) { |
---|
419 | if (!in_array($plugin . $this->modelClass, $this->uses)) { |
---|
420 | array_unshift($this->uses, $plugin . $this->modelClass); |
---|
421 | } elseif ($this->uses[0] !== $plugin . $this->modelClass) { |
---|
422 | $this->uses = array_flip($this->uses); |
---|
423 | unset($this->uses[$plugin . $this->modelClass]); |
---|
424 | $this->uses = array_flip($this->uses); |
---|
425 | array_unshift($this->uses, $plugin . $this->modelClass); |
---|
426 | } |
---|
427 | } else { |
---|
428 | $merge[] = 'uses'; |
---|
429 | } |
---|
430 | |
---|
431 | foreach ($merge as $var) { |
---|
432 | if (!empty($appVars[$var]) && is_array($this->{$var})) { |
---|
433 | if ($var !== 'uses') { |
---|
434 | $normal = Set::normalize($this->{$var}); |
---|
435 | $app = Set::normalize($appVars[$var]); |
---|
436 | if ($app !== $normal) { |
---|
437 | $this->{$var} = Set::merge($app, $normal); |
---|
438 | } |
---|
439 | } else { |
---|
440 | $this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var})); |
---|
441 | } |
---|
442 | } |
---|
443 | } |
---|
444 | } |
---|
445 | |
---|
446 | if ($pluginController && $pluginName != null) { |
---|
447 | $appVars = get_class_vars($pluginController); |
---|
448 | $uses = $appVars['uses']; |
---|
449 | $merge = array('components', 'helpers'); |
---|
450 | |
---|
451 | if ($this->uses !== null && $this->uses !== false) { |
---|
452 | $merge[] = 'uses'; |
---|
453 | } |
---|
454 | |
---|
455 | foreach ($merge as $var) { |
---|
456 | if (isset($appVars[$var]) && !empty($appVars[$var]) && is_array($this->{$var})) { |
---|
457 | if ($var !== 'uses') { |
---|
458 | $normal = Set::normalize($this->{$var}); |
---|
459 | $app = Set::normalize($appVars[$var]); |
---|
460 | if ($app !== $normal) { |
---|
461 | $this->{$var} = Set::merge($app, $normal); |
---|
462 | } |
---|
463 | } else { |
---|
464 | $this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var})); |
---|
465 | } |
---|
466 | } |
---|
467 | } |
---|
468 | } |
---|
469 | } |
---|
470 | |
---|
471 | /** |
---|
472 | * Loads Model classes based on the uses property |
---|
473 | * see Controller::loadModel(); for more info. |
---|
474 | * Loads Components and prepares them for initialization. |
---|
475 | * |
---|
476 | * @return mixed true if models found and instance created, or cakeError if models not found. |
---|
477 | * @access public |
---|
478 | * @see Controller::loadModel() |
---|
479 | * @link http://book.cakephp.org/view/977/Controller-Methods#constructClasses-986 |
---|
480 | */ |
---|
481 | function constructClasses() { |
---|
482 | $this->__mergeVars(); |
---|
483 | $this->Component->init($this); |
---|
484 | |
---|
485 | if ($this->uses !== null || ($this->uses !== array())) { |
---|
486 | if (empty($this->passedArgs) || !isset($this->passedArgs['0'])) { |
---|
487 | $id = false; |
---|
488 | } else { |
---|
489 | $id = $this->passedArgs['0']; |
---|
490 | } |
---|
491 | |
---|
492 | if ($this->uses === false) { |
---|
493 | $this->loadModel($this->modelClass, $id); |
---|
494 | } elseif ($this->uses) { |
---|
495 | $uses = is_array($this->uses) ? $this->uses : array($this->uses); |
---|
496 | $modelClassName = $uses[0]; |
---|
497 | if (strpos($uses[0], '.') !== false) { |
---|
498 | list($plugin, $modelClassName) = explode('.', $uses[0]); |
---|
499 | } |
---|
500 | $this->modelClass = $modelClassName; |
---|
501 | foreach ($uses as $modelClass) { |
---|
502 | $this->loadModel($modelClass); |
---|
503 | } |
---|
504 | } |
---|
505 | } |
---|
506 | return true; |
---|
507 | } |
---|
508 | |
---|
509 | /** |
---|
510 | * Perform the startup process for this controller. |
---|
511 | * Fire the Component and Controller callbacks in the correct order. |
---|
512 | * |
---|
513 | * - Initializes components, which fires their `initialize` callback |
---|
514 | * - Calls the controller `beforeFilter`. |
---|
515 | * - triggers Component `startup` methods. |
---|
516 | * |
---|
517 | * @return void |
---|
518 | * @access public |
---|
519 | */ |
---|
520 | function startupProcess() { |
---|
521 | $this->Component->initialize($this); |
---|
522 | $this->beforeFilter(); |
---|
523 | $this->Component->triggerCallback('startup', $this); |
---|
524 | } |
---|
525 | |
---|
526 | /** |
---|
527 | * Perform the various shutdown processes for this controller. |
---|
528 | * Fire the Component and Controller callbacks in the correct order. |
---|
529 | * |
---|
530 | * - triggers the component `shutdown` callback. |
---|
531 | * - calls the Controller's `afterFilter` method. |
---|
532 | * |
---|
533 | * @return void |
---|
534 | * @access public |
---|
535 | */ |
---|
536 | function shutdownProcess() { |
---|
537 | $this->Component->triggerCallback('shutdown', $this); |
---|
538 | $this->afterFilter(); |
---|
539 | } |
---|
540 | |
---|
541 | /** |
---|
542 | * Queries & sets valid HTTP response codes & messages. |
---|
543 | * |
---|
544 | * @param mixed $code If $code is an integer, then the corresponding code/message is |
---|
545 | * returned if it exists, null if it does not exist. If $code is an array, |
---|
546 | * then the 'code' and 'message' keys of each nested array are added to the default |
---|
547 | * HTTP codes. Example: |
---|
548 | * |
---|
549 | * httpCodes(404); // returns array(404 => 'Not Found') |
---|
550 | * |
---|
551 | * httpCodes(array( |
---|
552 | * 701 => 'Unicorn Moved', |
---|
553 | * 800 => 'Unexpected Minotaur' |
---|
554 | * )); // sets these new values, and returns true |
---|
555 | * |
---|
556 | * @return mixed Associative array of the HTTP codes as keys, and the message |
---|
557 | * strings as values, or null of the given $code does not exist. |
---|
558 | */ |
---|
559 | function httpCodes($code = null) { |
---|
560 | if (empty($this->__httpCodes)) { |
---|
561 | $this->__httpCodes = array( |
---|
562 | 100 => 'Continue', 101 => 'Switching Protocols', |
---|
563 | 200 => 'OK', 201 => 'Created', 202 => 'Accepted', |
---|
564 | 203 => 'Non-Authoritative Information', 204 => 'No Content', |
---|
565 | 205 => 'Reset Content', 206 => 'Partial Content', |
---|
566 | 300 => 'Multiple Choices', 301 => 'Moved Permanently', |
---|
567 | 302 => 'Found', 303 => 'See Other', |
---|
568 | 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', |
---|
569 | 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', |
---|
570 | 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', |
---|
571 | 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', |
---|
572 | 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', |
---|
573 | 411 => 'Length Required', 412 => 'Precondition Failed', |
---|
574 | 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', |
---|
575 | 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', |
---|
576 | 417 => 'Expectation Failed', 500 => 'Internal Server Error', |
---|
577 | 501 => 'Not Implemented', 502 => 'Bad Gateway', |
---|
578 | 503 => 'Service Unavailable', 504 => 'Gateway Time-out' |
---|
579 | ); |
---|
580 | } |
---|
581 | |
---|
582 | if (empty($code)) { |
---|
583 | return $this->__httpCodes; |
---|
584 | } |
---|
585 | |
---|
586 | if (is_array($code)) { |
---|
587 | $this->__httpCodes = $code + $this->__httpCodes; |
---|
588 | return true; |
---|
589 | } |
---|
590 | |
---|
591 | if (!isset($this->__httpCodes[$code])) { |
---|
592 | return null; |
---|
593 | } |
---|
594 | return array($code => $this->__httpCodes[$code]); |
---|
595 | } |
---|
596 | |
---|
597 | /** |
---|
598 | * Loads and instantiates models required by this controller. |
---|
599 | * If Controller::$persistModel; is true, controller will cache model instances on first request, |
---|
600 | * additional request will used cached models. |
---|
601 | * If the model is non existent, it will throw a missing database table error, as Cake generates |
---|
602 | * dynamic models for the time being. |
---|
603 | * |
---|
604 | * @param string $modelClass Name of model class to load |
---|
605 | * @param mixed $id Initial ID the instanced model class should have |
---|
606 | * @return mixed true when single model found and instance created, error returned if model not found. |
---|
607 | * @access public |
---|
608 | */ |
---|
609 | function loadModel($modelClass = null, $id = null) { |
---|
610 | if ($modelClass === null) { |
---|
611 | $modelClass = $this->modelClass; |
---|
612 | } |
---|
613 | $cached = false; |
---|
614 | $object = null; |
---|
615 | $plugin = null; |
---|
616 | if ($this->uses === false) { |
---|
617 | if ($this->plugin) { |
---|
618 | $plugin = $this->plugin . '.'; |
---|
619 | } |
---|
620 | } |
---|
621 | list($plugin, $modelClass) = pluginSplit($modelClass, true, $plugin); |
---|
622 | |
---|
623 | if ($this->persistModel === true) { |
---|
624 | $cached = $this->_persist($modelClass, null, $object); |
---|
625 | } |
---|
626 | |
---|
627 | if (($cached === false)) { |
---|
628 | $this->modelNames[] = $modelClass; |
---|
629 | |
---|
630 | if (!PHP5) { |
---|
631 | $this->{$modelClass} =& ClassRegistry::init(array( |
---|
632 | 'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id |
---|
633 | )); |
---|
634 | } else { |
---|
635 | $this->{$modelClass} = ClassRegistry::init(array( |
---|
636 | 'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id |
---|
637 | )); |
---|
638 | } |
---|
639 | |
---|
640 | if (!$this->{$modelClass}) { |
---|
641 | return $this->cakeError('missingModel', array(array( |
---|
642 | 'className' => $modelClass, 'webroot' => '', 'base' => $this->base |
---|
643 | ))); |
---|
644 | } |
---|
645 | |
---|
646 | if ($this->persistModel === true) { |
---|
647 | $this->_persist($modelClass, true, $this->{$modelClass}); |
---|
648 | $registry =& ClassRegistry::getInstance(); |
---|
649 | $this->_persist($modelClass . 'registry', true, $registry->__objects, 'registry'); |
---|
650 | } |
---|
651 | } else { |
---|
652 | $this->_persist($modelClass . 'registry', true, $object, 'registry'); |
---|
653 | $this->_persist($modelClass, true, $object); |
---|
654 | $this->modelNames[] = $modelClass; |
---|
655 | } |
---|
656 | |
---|
657 | return true; |
---|
658 | } |
---|
659 | |
---|
660 | /** |
---|
661 | * Redirects to given $url, after turning off $this->autoRender. |
---|
662 | * Script execution is halted after the redirect. |
---|
663 | * |
---|
664 | * @param mixed $url A string or array-based URL pointing to another location within the app, |
---|
665 | * or an absolute URL |
---|
666 | * @param integer $status Optional HTTP status code (eg: 404) |
---|
667 | * @param boolean $exit If true, exit() will be called after the redirect |
---|
668 | * @return mixed void if $exit = false. Terminates script if $exit = true |
---|
669 | * @access public |
---|
670 | * @link http://book.cakephp.org/view/982/redirect |
---|
671 | */ |
---|
672 | function redirect($url, $status = null, $exit = true) { |
---|
673 | $this->autoRender = false; |
---|
674 | |
---|
675 | if (is_array($status)) { |
---|
676 | extract($status, EXTR_OVERWRITE); |
---|
677 | } |
---|
678 | $response = $this->Component->beforeRedirect($this, $url, $status, $exit); |
---|
679 | |
---|
680 | if ($response === false) { |
---|
681 | return; |
---|
682 | } |
---|
683 | if (is_array($response)) { |
---|
684 | foreach ($response as $resp) { |
---|
685 | if (is_array($resp) && isset($resp['url'])) { |
---|
686 | extract($resp, EXTR_OVERWRITE); |
---|
687 | } elseif ($resp !== null) { |
---|
688 | $url = $resp; |
---|
689 | } |
---|
690 | } |
---|
691 | } |
---|
692 | |
---|
693 | if (function_exists('session_write_close')) { |
---|
694 | session_write_close(); |
---|
695 | } |
---|
696 | |
---|
697 | if (!empty($status)) { |
---|
698 | $codes = $this->httpCodes(); |
---|
699 | |
---|
700 | if (is_string($status)) { |
---|
701 | $codes = array_flip($codes); |
---|
702 | } |
---|
703 | |
---|
704 | if (isset($codes[$status])) { |
---|
705 | $code = $msg = $codes[$status]; |
---|
706 | if (is_numeric($status)) { |
---|
707 | $code = $status; |
---|
708 | } |
---|
709 | if (is_string($status)) { |
---|
710 | $msg = $status; |
---|
711 | } |
---|
712 | $status = "HTTP/1.1 {$code} {$msg}"; |
---|
713 | |
---|
714 | } else { |
---|
715 | $status = null; |
---|
716 | } |
---|
717 | $this->header($status); |
---|
718 | } |
---|
719 | |
---|
720 | if ($url !== null) { |
---|
721 | $this->header('Location: ' . Router::url($url, true)); |
---|
722 | } |
---|
723 | |
---|
724 | if (!empty($status) && ($status >= 300 && $status < 400)) { |
---|
725 | $this->header($status); |
---|
726 | } |
---|
727 | |
---|
728 | if ($exit) { |
---|
729 | $this->_stop(); |
---|
730 | } |
---|
731 | } |
---|
732 | |
---|
733 | /** |
---|
734 | * Convenience and object wrapper method for header(). Useful when doing tests and |
---|
735 | * asserting that particular headers have been set. |
---|
736 | * |
---|
737 | * @param string $status The header message that is being set. |
---|
738 | * @return void |
---|
739 | * @access public |
---|
740 | */ |
---|
741 | function header($status) { |
---|
742 | header($status); |
---|
743 | } |
---|
744 | |
---|
745 | /** |
---|
746 | * Saves a variable for use inside a view template. |
---|
747 | * |
---|
748 | * @param mixed $one A string or an array of data. |
---|
749 | * @param mixed $two Value in case $one is a string (which then works as the key). |
---|
750 | * Unused if $one is an associative array, otherwise serves as the values to $one's keys. |
---|
751 | * @return void |
---|
752 | * @access public |
---|
753 | * @link http://book.cakephp.org/view/979/set |
---|
754 | */ |
---|
755 | function set($one, $two = null) { |
---|
756 | $data = array(); |
---|
757 | |
---|
758 | if (is_array($one)) { |
---|
759 | if (is_array($two)) { |
---|
760 | $data = array_combine($one, $two); |
---|
761 | } else { |
---|
762 | $data = $one; |
---|
763 | } |
---|
764 | } else { |
---|
765 | $data = array($one => $two); |
---|
766 | } |
---|
767 | $this->viewVars = $data + $this->viewVars; |
---|
768 | } |
---|
769 | |
---|
770 | /** |
---|
771 | * Internally redirects one action to another. Does not perform another HTTP request unlike Controller::redirect() |
---|
772 | * |
---|
773 | * Examples: |
---|
774 | * |
---|
775 | * {{{ |
---|
776 | * setAction('another_action'); |
---|
777 | * setAction('action_with_parameters', $parameter1); |
---|
778 | * }}} |
---|
779 | * |
---|
780 | * @param string $action The new action to be 'redirected' to |
---|
781 | * @param mixed Any other parameters passed to this method will be passed as |
---|
782 | * parameters to the new action. |
---|
783 | * @return mixed Returns the return value of the called action |
---|
784 | * @access public |
---|
785 | */ |
---|
786 | function setAction($action) { |
---|
787 | $this->action = $action; |
---|
788 | $args = func_get_args(); |
---|
789 | unset($args[0]); |
---|
790 | return call_user_func_array(array(&$this, $action), $args); |
---|
791 | } |
---|
792 | |
---|
793 | /** |
---|
794 | * Controller callback to tie into Auth component. |
---|
795 | * Only called when AuthComponent::$authorize is set to 'controller'. |
---|
796 | * |
---|
797 | * @return bool true if authorized, false otherwise |
---|
798 | * @access public |
---|
799 | * @link http://book.cakephp.org/view/1275/authorize |
---|
800 | */ |
---|
801 | function isAuthorized() { |
---|
802 | trigger_error(sprintf( |
---|
803 | __('%sController::isAuthorized() is not defined.', true), $this->name |
---|
804 | ), E_USER_WARNING); |
---|
805 | return false; |
---|
806 | } |
---|
807 | |
---|
808 | /** |
---|
809 | * Returns number of errors in a submitted FORM. |
---|
810 | * |
---|
811 | * @return integer Number of errors |
---|
812 | * @access public |
---|
813 | */ |
---|
814 | function validate() { |
---|
815 | $args = func_get_args(); |
---|
816 | $errors = call_user_func_array(array(&$this, 'validateErrors'), $args); |
---|
817 | |
---|
818 | if ($errors === false) { |
---|
819 | return 0; |
---|
820 | } |
---|
821 | return count($errors); |
---|
822 | } |
---|
823 | |
---|
824 | /** |
---|
825 | * Validates models passed by parameters. Example: |
---|
826 | * |
---|
827 | * `$errors = $this->validateErrors($this->Article, $this->User);` |
---|
828 | * |
---|
829 | * @param mixed A list of models as a variable argument |
---|
830 | * @return array Validation errors, or false if none |
---|
831 | * @access public |
---|
832 | */ |
---|
833 | function validateErrors() { |
---|
834 | $objects = func_get_args(); |
---|
835 | |
---|
836 | if (empty($objects)) { |
---|
837 | return false; |
---|
838 | } |
---|
839 | |
---|
840 | $errors = array(); |
---|
841 | foreach ($objects as $object) { |
---|
842 | if (isset($this->{$object->alias})) { |
---|
843 | $object =& $this->{$object->alias}; |
---|
844 | } |
---|
845 | $object->set($object->data); |
---|
846 | $errors = array_merge($errors, (array)$object->invalidFields()); |
---|
847 | } |
---|
848 | |
---|
849 | return $this->validationErrors = (!empty($errors) ? $errors : false); |
---|
850 | } |
---|
851 | |
---|
852 | /** |
---|
853 | * Instantiates the correct view class, hands it its data, and uses it to render the view output. |
---|
854 | * |
---|
855 | * @param string $action Action name to render |
---|
856 | * @param string $layout Layout to use |
---|
857 | * @param string $file File to use for rendering |
---|
858 | * @return string Full output string of view contents |
---|
859 | * @access public |
---|
860 | * @link http://book.cakephp.org/view/980/render |
---|
861 | */ |
---|
862 | function render($action = null, $layout = null, $file = null) { |
---|
863 | $this->beforeRender(); |
---|
864 | $this->Component->triggerCallback('beforeRender', $this); |
---|
865 | |
---|
866 | $viewClass = $this->view; |
---|
867 | if ($this->view != 'View') { |
---|
868 | list($plugin, $viewClass) = pluginSplit($viewClass); |
---|
869 | $viewClass = $viewClass . 'View'; |
---|
870 | App::import('View', $this->view); |
---|
871 | } |
---|
872 | |
---|
873 | $this->params['models'] = $this->modelNames; |
---|
874 | |
---|
875 | if (Configure::read() > 2) { |
---|
876 | $this->set('cakeDebug', $this); |
---|
877 | } |
---|
878 | |
---|
879 | $View =& new $viewClass($this); |
---|
880 | |
---|
881 | if (!empty($this->modelNames)) { |
---|
882 | $models = array(); |
---|
883 | foreach ($this->modelNames as $currentModel) { |
---|
884 | if (isset($this->$currentModel) && is_a($this->$currentModel, 'Model')) { |
---|
885 | $models[] = Inflector::underscore($currentModel); |
---|
886 | } |
---|
887 | $isValidModel = ( |
---|
888 | isset($this->$currentModel) && is_a($this->$currentModel, 'Model') && |
---|
889 | !empty($this->$currentModel->validationErrors) |
---|
890 | ); |
---|
891 | if ($isValidModel) { |
---|
892 | $View->validationErrors[Inflector::camelize($currentModel)] =& |
---|
893 | $this->$currentModel->validationErrors; |
---|
894 | } |
---|
895 | } |
---|
896 | $models = array_diff(ClassRegistry::keys(), $models); |
---|
897 | foreach ($models as $currentModel) { |
---|
898 | if (ClassRegistry::isKeySet($currentModel)) { |
---|
899 | $currentObject =& ClassRegistry::getObject($currentModel); |
---|
900 | if (is_a($currentObject, 'Model') && !empty($currentObject->validationErrors)) { |
---|
901 | $View->validationErrors[Inflector::camelize($currentModel)] =& |
---|
902 | $currentObject->validationErrors; |
---|
903 | } |
---|
904 | } |
---|
905 | } |
---|
906 | } |
---|
907 | |
---|
908 | $this->autoRender = false; |
---|
909 | $this->output .= $View->render($action, $layout, $file); |
---|
910 | |
---|
911 | return $this->output; |
---|
912 | } |
---|
913 | |
---|
914 | /** |
---|
915 | * Returns the referring URL for this request. |
---|
916 | * |
---|
917 | * @param string $default Default URL to use if HTTP_REFERER cannot be read from headers |
---|
918 | * @param boolean $local If true, restrict referring URLs to local server |
---|
919 | * @return string Referring URL |
---|
920 | * @access public |
---|
921 | * @link http://book.cakephp.org/view/987/referer |
---|
922 | */ |
---|
923 | function referer($default = null, $local = false) { |
---|
924 | $ref = env('HTTP_REFERER'); |
---|
925 | if (!empty($ref) && defined('FULL_BASE_URL')) { |
---|
926 | $base = FULL_BASE_URL . $this->webroot; |
---|
927 | if (strpos($ref, $base) === 0) { |
---|
928 | $return = substr($ref, strlen($base)); |
---|
929 | if ($return[0] != '/') { |
---|
930 | $return = '/'.$return; |
---|
931 | } |
---|
932 | return $return; |
---|
933 | } elseif (!$local) { |
---|
934 | return $ref; |
---|
935 | } |
---|
936 | } |
---|
937 | |
---|
938 | if ($default != null) { |
---|
939 | $url = Router::url($default, true); |
---|
940 | return $url; |
---|
941 | } |
---|
942 | return '/'; |
---|
943 | } |
---|
944 | |
---|
945 | /** |
---|
946 | * Forces the user's browser not to cache the results of the current request. |
---|
947 | * |
---|
948 | * @return void |
---|
949 | * @access public |
---|
950 | * @link http://book.cakephp.org/view/988/disableCache |
---|
951 | */ |
---|
952 | function disableCache() { |
---|
953 | header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); |
---|
954 | header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); |
---|
955 | header("Cache-Control: no-store, no-cache, must-revalidate"); |
---|
956 | header("Cache-Control: post-check=0, pre-check=0", false); |
---|
957 | header("Pragma: no-cache"); |
---|
958 | } |
---|
959 | |
---|
960 | /** |
---|
961 | * Shows a message to the user for $pause seconds, then redirects to $url. |
---|
962 | * Uses flash.ctp as the default layout for the message. |
---|
963 | * Does not work if the current debug level is higher than 0. |
---|
964 | * |
---|
965 | * @param string $message Message to display to the user |
---|
966 | * @param mixed $url Relative string or array-based URL to redirect to after the time expires |
---|
967 | * @param integer $pause Time to show the message |
---|
968 | * @param string $layout Layout you want to use, defaults to 'flash' |
---|
969 | * @return void Renders flash layout |
---|
970 | * @access public |
---|
971 | * @link http://book.cakephp.org/view/983/flash |
---|
972 | */ |
---|
973 | function flash($message, $url, $pause = 1, $layout = 'flash') { |
---|
974 | $this->autoRender = false; |
---|
975 | $this->set('url', Router::url($url)); |
---|
976 | $this->set('message', $message); |
---|
977 | $this->set('pause', $pause); |
---|
978 | $this->set('page_title', $message); |
---|
979 | $this->render(false, $layout); |
---|
980 | } |
---|
981 | |
---|
982 | /** |
---|
983 | * Converts POST'ed form data to a model conditions array, suitable for use in a Model::find() call. |
---|
984 | * |
---|
985 | * @param array $data POST'ed data organized by model and field |
---|
986 | * @param mixed $op A string containing an SQL comparison operator, or an array matching operators |
---|
987 | * to fields |
---|
988 | * @param string $bool SQL boolean operator: AND, OR, XOR, etc. |
---|
989 | * @param boolean $exclusive If true, and $op is an array, fields not included in $op will not be |
---|
990 | * included in the returned conditions |
---|
991 | * @return array An array of model conditions |
---|
992 | * @access public |
---|
993 | * @link http://book.cakephp.org/view/989/postConditions |
---|
994 | */ |
---|
995 | function postConditions($data = array(), $op = null, $bool = 'AND', $exclusive = false) { |
---|
996 | if (!is_array($data) || empty($data)) { |
---|
997 | if (!empty($this->data)) { |
---|
998 | $data = $this->data; |
---|
999 | } else { |
---|
1000 | return null; |
---|
1001 | } |
---|
1002 | } |
---|
1003 | $cond = array(); |
---|
1004 | |
---|
1005 | if ($op === null) { |
---|
1006 | $op = ''; |
---|
1007 | } |
---|
1008 | |
---|
1009 | $arrayOp = is_array($op); |
---|
1010 | foreach ($data as $model => $fields) { |
---|
1011 | foreach ($fields as $field => $value) { |
---|
1012 | $key = $model.'.'.$field; |
---|
1013 | $fieldOp = $op; |
---|
1014 | if ($arrayOp) { |
---|
1015 | if (array_key_exists($key, $op)) { |
---|
1016 | $fieldOp = $op[$key]; |
---|
1017 | } elseif (array_key_exists($field, $op)) { |
---|
1018 | $fieldOp = $op[$field]; |
---|
1019 | } else { |
---|
1020 | $fieldOp = false; |
---|
1021 | } |
---|
1022 | } |
---|
1023 | if ($exclusive && $fieldOp === false) { |
---|
1024 | continue; |
---|
1025 | } |
---|
1026 | $fieldOp = strtoupper(trim($fieldOp)); |
---|
1027 | if ($fieldOp === 'LIKE') { |
---|
1028 | $key = $key.' LIKE'; |
---|
1029 | $value = '%'.$value.'%'; |
---|
1030 | } elseif ($fieldOp && $fieldOp != '=') { |
---|
1031 | $key = $key.' '.$fieldOp; |
---|
1032 | } |
---|
1033 | $cond[$key] = $value; |
---|
1034 | } |
---|
1035 | } |
---|
1036 | if ($bool != null && strtoupper($bool) != 'AND') { |
---|
1037 | $cond = array($bool => $cond); |
---|
1038 | } |
---|
1039 | return $cond; |
---|
1040 | } |
---|
1041 | |
---|
1042 | /** |
---|
1043 | * Handles automatic pagination of model records. |
---|
1044 | * |
---|
1045 | * @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel') |
---|
1046 | * @param mixed $scope Conditions to use while paginating |
---|
1047 | * @param array $whitelist List of allowed options for paging |
---|
1048 | * @return array Model query results |
---|
1049 | * @access public |
---|
1050 | * @link http://book.cakephp.org/view/1232/Controller-Setup |
---|
1051 | */ |
---|
1052 | function paginate($object = null, $scope = array(), $whitelist = array()) { |
---|
1053 | if (is_array($object)) { |
---|
1054 | $whitelist = $scope; |
---|
1055 | $scope = $object; |
---|
1056 | $object = null; |
---|
1057 | } |
---|
1058 | $assoc = null; |
---|
1059 | |
---|
1060 | if (is_string($object)) { |
---|
1061 | $assoc = null; |
---|
1062 | if (strpos($object, '.') !== false) { |
---|
1063 | list($object, $assoc) = pluginSplit($object); |
---|
1064 | } |
---|
1065 | |
---|
1066 | if ($assoc && isset($this->{$object}->{$assoc})) { |
---|
1067 | $object =& $this->{$object}->{$assoc}; |
---|
1068 | } elseif ( |
---|
1069 | $assoc && isset($this->{$this->modelClass}) && |
---|
1070 | isset($this->{$this->modelClass}->{$assoc} |
---|
1071 | )) { |
---|
1072 | $object =& $this->{$this->modelClass}->{$assoc}; |
---|
1073 | } elseif (isset($this->{$object})) { |
---|
1074 | $object =& $this->{$object}; |
---|
1075 | } elseif ( |
---|
1076 | isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$object} |
---|
1077 | )) { |
---|
1078 | $object =& $this->{$this->modelClass}->{$object}; |
---|
1079 | } |
---|
1080 | } elseif (empty($object) || $object === null) { |
---|
1081 | if (isset($this->{$this->modelClass})) { |
---|
1082 | $object =& $this->{$this->modelClass}; |
---|
1083 | } else { |
---|
1084 | $className = null; |
---|
1085 | $name = $this->uses[0]; |
---|
1086 | if (strpos($this->uses[0], '.') !== false) { |
---|
1087 | list($name, $className) = explode('.', $this->uses[0]); |
---|
1088 | } |
---|
1089 | if ($className) { |
---|
1090 | $object =& $this->{$className}; |
---|
1091 | } else { |
---|
1092 | $object =& $this->{$name}; |
---|
1093 | } |
---|
1094 | } |
---|
1095 | } |
---|
1096 | |
---|
1097 | if (!is_object($object)) { |
---|
1098 | trigger_error(sprintf( |
---|
1099 | __('Controller::paginate() - can\'t find model %1$s in controller %2$sController', |
---|
1100 | true |
---|
1101 | ), $object, $this->name |
---|
1102 | ), E_USER_WARNING); |
---|
1103 | return array(); |
---|
1104 | } |
---|
1105 | $options = array_merge($this->params, $this->params['url'], $this->passedArgs); |
---|
1106 | |
---|
1107 | if (isset($this->paginate[$object->alias])) { |
---|
1108 | $defaults = $this->paginate[$object->alias]; |
---|
1109 | } else { |
---|
1110 | $defaults = $this->paginate; |
---|
1111 | } |
---|
1112 | |
---|
1113 | if (isset($options['show'])) { |
---|
1114 | $options['limit'] = $options['show']; |
---|
1115 | } |
---|
1116 | |
---|
1117 | if (isset($options['sort'])) { |
---|
1118 | $direction = null; |
---|
1119 | if (isset($options['direction'])) { |
---|
1120 | $direction = strtolower($options['direction']); |
---|
1121 | } |
---|
1122 | if ($direction != 'asc' && $direction != 'desc') { |
---|
1123 | $direction = 'asc'; |
---|
1124 | } |
---|
1125 | $options['order'] = array($options['sort'] => $direction); |
---|
1126 | } |
---|
1127 | |
---|
1128 | if (!empty($options['order']) && is_array($options['order'])) { |
---|
1129 | $alias = $object->alias ; |
---|
1130 | $key = $field = key($options['order']); |
---|
1131 | |
---|
1132 | if (strpos($key, '.') !== false) { |
---|
1133 | list($alias, $field) = explode('.', $key); |
---|
1134 | } |
---|
1135 | $value = $options['order'][$key]; |
---|
1136 | unset($options['order'][$key]); |
---|
1137 | |
---|
1138 | if ($object->hasField($field)) { |
---|
1139 | $options['order'][$alias . '.' . $field] = $value; |
---|
1140 | } elseif ($object->hasField($field, true)) { |
---|
1141 | $options['order'][$field] = $value; |
---|
1142 | } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field)) { |
---|
1143 | $options['order'][$alias . '.' . $field] = $value; |
---|
1144 | } |
---|
1145 | } |
---|
1146 | $vars = array('fields', 'order', 'limit', 'page', 'recursive'); |
---|
1147 | $keys = array_keys($options); |
---|
1148 | $count = count($keys); |
---|
1149 | |
---|
1150 | for ($i = 0; $i < $count; $i++) { |
---|
1151 | if (!in_array($keys[$i], $vars, true)) { |
---|
1152 | unset($options[$keys[$i]]); |
---|
1153 | } |
---|
1154 | if (empty($whitelist) && ($keys[$i] === 'fields' || $keys[$i] === 'recursive')) { |
---|
1155 | unset($options[$keys[$i]]); |
---|
1156 | } elseif (!empty($whitelist) && !in_array($keys[$i], $whitelist)) { |
---|
1157 | unset($options[$keys[$i]]); |
---|
1158 | } |
---|
1159 | } |
---|
1160 | $conditions = $fields = $order = $limit = $page = $recursive = null; |
---|
1161 | |
---|
1162 | if (!isset($defaults['conditions'])) { |
---|
1163 | $defaults['conditions'] = array(); |
---|
1164 | } |
---|
1165 | |
---|
1166 | $type = 'all'; |
---|
1167 | |
---|
1168 | if (isset($defaults[0])) { |
---|
1169 | $type = $defaults[0]; |
---|
1170 | unset($defaults[0]); |
---|
1171 | } |
---|
1172 | |
---|
1173 | $options = array_merge(array('page' => 1, 'limit' => 20), $defaults, $options); |
---|
1174 | $options['limit'] = (int) $options['limit']; |
---|
1175 | if (empty($options['limit']) || $options['limit'] < 1) { |
---|
1176 | $options['limit'] = 1; |
---|
1177 | } |
---|
1178 | |
---|
1179 | extract($options); |
---|
1180 | |
---|
1181 | if (is_array($scope) && !empty($scope)) { |
---|
1182 | $conditions = array_merge($conditions, $scope); |
---|
1183 | } elseif (is_string($scope)) { |
---|
1184 | $conditions = array($conditions, $scope); |
---|
1185 | } |
---|
1186 | if ($recursive === null) { |
---|
1187 | $recursive = $object->recursive; |
---|
1188 | } |
---|
1189 | |
---|
1190 | $extra = array_diff_key($defaults, compact( |
---|
1191 | 'conditions', 'fields', 'order', 'limit', 'page', 'recursive' |
---|
1192 | )); |
---|
1193 | if ($type !== 'all') { |
---|
1194 | $extra['type'] = $type; |
---|
1195 | } |
---|
1196 | |
---|
1197 | if (method_exists($object, 'paginateCount')) { |
---|
1198 | $count = $object->paginateCount($conditions, $recursive, $extra); |
---|
1199 | } else { |
---|
1200 | $parameters = compact('conditions'); |
---|
1201 | if ($recursive != $object->recursive) { |
---|
1202 | $parameters['recursive'] = $recursive; |
---|
1203 | } |
---|
1204 | $count = $object->find('count', array_merge($parameters, $extra)); |
---|
1205 | } |
---|
1206 | $pageCount = intval(ceil($count / $limit)); |
---|
1207 | |
---|
1208 | if ($page === 'last' || $page >= $pageCount) { |
---|
1209 | $options['page'] = $page = $pageCount; |
---|
1210 | } elseif (intval($page) < 1) { |
---|
1211 | $options['page'] = $page = 1; |
---|
1212 | } |
---|
1213 | $page = $options['page'] = (integer)$page; |
---|
1214 | |
---|
1215 | if (method_exists($object, 'paginate')) { |
---|
1216 | $results = $object->paginate( |
---|
1217 | $conditions, $fields, $order, $limit, $page, $recursive, $extra |
---|
1218 | ); |
---|
1219 | } else { |
---|
1220 | $parameters = compact('conditions', 'fields', 'order', 'limit', 'page'); |
---|
1221 | if ($recursive != $object->recursive) { |
---|
1222 | $parameters['recursive'] = $recursive; |
---|
1223 | } |
---|
1224 | $results = $object->find($type, array_merge($parameters, $extra)); |
---|
1225 | } |
---|
1226 | $paging = array( |
---|
1227 | 'page' => $page, |
---|
1228 | 'current' => count($results), |
---|
1229 | 'count' => $count, |
---|
1230 | 'prevPage' => ($page > 1), |
---|
1231 | 'nextPage' => ($count > ($page * $limit)), |
---|
1232 | 'pageCount' => $pageCount, |
---|
1233 | 'defaults' => array_merge(array('limit' => 20, 'step' => 1), $defaults), |
---|
1234 | 'options' => $options |
---|
1235 | ); |
---|
1236 | $this->params['paging'][$object->alias] = $paging; |
---|
1237 | |
---|
1238 | if (!in_array('Paginator', $this->helpers) && !array_key_exists('Paginator', $this->helpers)) { |
---|
1239 | $this->helpers[] = 'Paginator'; |
---|
1240 | } |
---|
1241 | return $results; |
---|
1242 | } |
---|
1243 | |
---|
1244 | /** |
---|
1245 | * Called before the controller action. |
---|
1246 | * |
---|
1247 | * @access public |
---|
1248 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1249 | */ |
---|
1250 | function beforeFilter() { |
---|
1251 | } |
---|
1252 | |
---|
1253 | /** |
---|
1254 | * Called after the controller action is run, but before the view is rendered. |
---|
1255 | * |
---|
1256 | * @access public |
---|
1257 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1258 | */ |
---|
1259 | function beforeRender() { |
---|
1260 | } |
---|
1261 | |
---|
1262 | /** |
---|
1263 | * Called after the controller action is run and rendered. |
---|
1264 | * |
---|
1265 | * @access public |
---|
1266 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1267 | */ |
---|
1268 | function afterFilter() { |
---|
1269 | } |
---|
1270 | |
---|
1271 | /** |
---|
1272 | * This method should be overridden in child classes. |
---|
1273 | * |
---|
1274 | * @param string $method name of method called example index, edit, etc. |
---|
1275 | * @return boolean Success |
---|
1276 | * @access protected |
---|
1277 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1278 | */ |
---|
1279 | function _beforeScaffold($method) { |
---|
1280 | return true; |
---|
1281 | } |
---|
1282 | |
---|
1283 | /** |
---|
1284 | * This method should be overridden in child classes. |
---|
1285 | * |
---|
1286 | * @param string $method name of method called either edit or update. |
---|
1287 | * @return boolean Success |
---|
1288 | * @access protected |
---|
1289 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1290 | */ |
---|
1291 | function _afterScaffoldSave($method) { |
---|
1292 | return true; |
---|
1293 | } |
---|
1294 | |
---|
1295 | /** |
---|
1296 | * This method should be overridden in child classes. |
---|
1297 | * |
---|
1298 | * @param string $method name of method called either edit or update. |
---|
1299 | * @return boolean Success |
---|
1300 | * @access protected |
---|
1301 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1302 | */ |
---|
1303 | function _afterScaffoldSaveError($method) { |
---|
1304 | return true; |
---|
1305 | } |
---|
1306 | |
---|
1307 | /** |
---|
1308 | * This method should be overridden in child classes. |
---|
1309 | * If not it will render a scaffold error. |
---|
1310 | * Method MUST return true in child classes |
---|
1311 | * |
---|
1312 | * @param string $method name of method called example index, edit, etc. |
---|
1313 | * @return boolean Success |
---|
1314 | * @access protected |
---|
1315 | * @link http://book.cakephp.org/view/984/Callbacks |
---|
1316 | */ |
---|
1317 | function _scaffoldError($method) { |
---|
1318 | return false; |
---|
1319 | } |
---|
1320 | } |
---|