controller.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: controller.php 8277 2009-08-03 17:55:16Z mark_story $ */
00003 /**
00004  * Base controller class.
00005  *
00006  * PHP versions 4 and 5
00007  *
00008  * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
00009  * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00010  *
00011  * Licensed under The MIT License
00012  * Redistributions of files must retain the above copyright notice.
00013  *
00014  * @filesource
00015  * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00016  * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00017  * @package       cake
00018  * @subpackage    cake.cake.libs.controller
00019  * @since         CakePHP(tm) v 0.2.9
00020  * @version       $Revision: 8277 $
00021  * @modifiedby    $LastChangedBy: mark_story $
00022  * @lastmodified  $Date: 2009-08-03 13:55:16 -0400 (Mon, 03 Aug 2009) $
00023  * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
00024  */
00025 /**
00026  * Include files
00027  */
00028 App::import('Core', array('Component', 'View'));
00029 /**
00030  * Controller
00031  *
00032  * Application controller class for organization of business logic.
00033  * Provides basic functionality, such as rendering views inside layouts,
00034  * automatic model availability, redirection, callbacks, and more.
00035  *
00036  * @package       cake
00037  * @subpackage    cake.cake.libs.controller
00038  * @link          http://book.cakephp.org/view/49/Controllers
00039  *
00040  */
00041 class Controller extends Object {
00042 /**
00043  * The name of this controller. Controller names are plural, named after the model they manipulate.
00044  *
00045  * @var string
00046  * @access public
00047  * @link http://book.cakephp.org/view/52/name
00048  */
00049     var $name = null;
00050 /**
00051  * Stores the current URL, relative to the webroot of the application.
00052  *
00053  * @var string
00054  * @access public
00055  */
00056     var $here = null;
00057 /**
00058  * The webroot of the application. Helpful if your application is placed in a folder under the current domain name.
00059  *
00060  * @var string
00061  * @access public
00062  */
00063     var $webroot = null;
00064 /**
00065  * The name of the currently requested controller action.
00066  *
00067  * @var string
00068  * @access public
00069  */
00070     var $action = null;
00071 /**
00072  * An array containing the class names of models this controller uses.
00073  *
00074  * Example: var $uses = array('Product', 'Post', 'Comment');
00075  *
00076  * @var mixed A single name as a string or a list of names as an array.
00077  * @access protected
00078  * @link http://book.cakephp.org/view/53/components-helpers-and-uses
00079  */
00080     var $uses = false;
00081 /**
00082  * An array containing the names of helpers this controller uses. The array elements should
00083  * not contain the "Helper" part of the classname.
00084  *
00085  * Example: var $helpers = array('Html', 'Javascript', 'Time', 'Ajax');
00086  *
00087  * @var mixed A single name as a string or a list of names as an array.
00088  * @access protected
00089  * @link http://book.cakephp.org/view/53/components-helpers-and-uses
00090  */
00091     var $helpers = array('Html', 'Form');
00092 /**
00093  * Parameters received in the current request: GET and POST data, information
00094  * about the request, etc.
00095  *
00096  * @var array
00097  * @access public
00098  * @link http://book.cakephp.org/view/55/The-Parameters-Attribute-params
00099  */
00100     var $params = array();
00101 /**
00102  * Data POSTed to the controller using the HtmlHelper. Data here is accessible
00103  * using the $this->data['ModelName']['fieldName'] pattern.
00104  *
00105  * @var array
00106  * @access public
00107  */
00108     var $data = array();
00109 /**
00110  * Holds pagination defaults for controller actions. The keys that can be included
00111  * in this array are: 'conditions', 'fields', 'order', 'limit', 'page', and 'recursive',
00112  * similar to the keys in the second parameter of Model::find().
00113  *
00114  * Pagination defaults can also be supplied in a model-by-model basis by using
00115  * the name of the model as a key for a pagination array:
00116  *
00117  * var $paginate = array(
00118  *      'Post' => array(...),
00119  *      'Comment' => array(...)
00120  *  );
00121  *
00122  * @var array
00123  * @access public
00124  * @link http://book.cakephp.org/view/164/Pagination
00125  */
00126     var $paginate = array('limit' => 20, 'page' => 1);
00127 /**
00128  * The name of the views subfolder containing views for this controller.
00129  *
00130  * @var string
00131  * @access public
00132  */
00133     var $viewPath = null;
00134 /**
00135  * The name of the layouts subfolder containing layouts for this controller.
00136  *
00137  * @var string
00138  * @access public
00139  */
00140     var $layoutPath = null;
00141 /**
00142  * Contains variables to be handed to the view.
00143  *
00144  * @var array
00145  * @access public
00146  */
00147     var $viewVars = array();
00148 /**
00149  * Text to be used for the $title_for_layout layout variable (usually
00150  * placed inside <title> tags.)
00151  *
00152  * @var boolean
00153  * @access public
00154  * @link http://book.cakephp.org/view/54/Page-related-Attributes-layout-and-pageTitle
00155  */
00156     var $pageTitle = false;
00157 /**
00158  * An array containing the class names of the models this controller uses.
00159  *
00160  * @var array Array of model objects.
00161  * @access public
00162  */
00163     var $modelNames = array();
00164 /**
00165  * Base URL path.
00166  *
00167  * @var string
00168  * @access public
00169  */
00170     var $base = null;
00171 /**
00172  * The name of the layout file to render the view inside of. The name specified
00173  * is the filename of the layout in /app/views/layouts without the .ctp
00174  * extension.
00175  *
00176  * @var string
00177  * @access public
00178  * @link http://book.cakephp.org/view/54/Page-related-Attributes-layout-and-pageTitle
00179  */
00180     var $layout = 'default';
00181 /**
00182  * Set to true to automatically render the view
00183  * after action logic.
00184  *
00185  * @var boolean
00186  * @access public
00187  */
00188     var $autoRender = true;
00189 /**
00190  * Set to true to automatically render the layout around views.
00191  *
00192  * @var boolean
00193  * @access public
00194  */
00195     var $autoLayout = true;
00196 /**
00197  * Instance of Component used to handle callbacks.
00198  *
00199  * @var string
00200  * @access public
00201  */
00202     var $Component = null;
00203 /**
00204  * Array containing the names of components this controller uses. Component names
00205  * should not contain the "Component" portion of the classname.
00206  *
00207  * Example: var $components = array('Session', 'RequestHandler', 'Acl');
00208  *
00209  * @var array
00210  * @access public
00211  * @link http://book.cakephp.org/view/53/components-helpers-and-uses
00212  */
00213     var $components = array();
00214 /**
00215  * The name of the View class this controller sends output to.
00216  *
00217  * @var string
00218  * @access public
00219  */
00220     var $view = 'View';
00221 /**
00222  * File extension for view templates. Defaults to Cake's conventional ".ctp".
00223  *
00224  * @var string
00225  * @access public
00226  */
00227     var $ext = '.ctp';
00228 /**
00229  * The output of the requested action.  Contains either a variable
00230  * returned from the action, or the data of the rendered view;
00231  * You can use this var in child controllers' afterFilter() callbacks to alter output.
00232  *
00233  * @var string
00234  * @access public
00235  */
00236     var $output = null;
00237 /**
00238  * Automatically set to the name of a plugin.
00239  *
00240  * @var string
00241  * @access public
00242  */
00243     var $plugin = null;
00244 /**
00245  * Used to define methods a controller that will be cached. To cache a
00246  * single action, the value is set to an array containing keys that match
00247  * action names and values that denote cache expiration times (in seconds).
00248  *
00249  * Example: var $cacheAction = array(
00250  *      'view/23/' => 21600,
00251  *      'recalled/' => 86400
00252  *  );
00253  *
00254  * $cacheAction can also be set to a strtotime() compatible string. This
00255  * marks all the actions in the controller for view caching.
00256  *
00257  * @var mixed
00258  * @access public
00259  * @link http://book.cakephp.org/view/346/Caching-in-the-Controller
00260  */
00261     var $cacheAction = false;
00262 /**
00263  * Used to create cached instances of models a controller uses.
00264  * When set to true, all models related to the controller will be cached.
00265  * This can increase performance in many cases.
00266  *
00267  * @var boolean
00268  * @access public
00269  */
00270     var $persistModel = false;
00271 /**
00272  * Holds all params passed and named.
00273  *
00274  * @var mixed
00275  * @access public
00276  */
00277     var $passedArgs = array();
00278 /**
00279  * Triggers Scaffolding
00280  *
00281  * @var mixed
00282  * @access public
00283  * @link http://book.cakephp.org/view/105/Scaffolding
00284  */
00285     var $scaffold = false;
00286 /**
00287  * Holds current methods of the controller
00288  *
00289  * @var array
00290  * @access public
00291  * @link
00292  */
00293     var $methods = array();
00294 /**
00295  * This controller's primary model class name, the Inflector::classify()'ed version of 
00296  * the controller's $name property.
00297  *
00298  * Example: For a controller named 'Comments', the modelClass would be 'Comment'
00299  *
00300  * @var string
00301  * @access public
00302  */
00303     var $modelClass = null;
00304 /**
00305  * This controller's model key name, an underscored version of the controller's $modelClass property.
00306  *
00307  * Example: For a controller named 'ArticleComments', the modelKey would be 'article_comment'
00308  *
00309  * @var string
00310  * @access public
00311  */
00312     var $modelKey = null;
00313 /**
00314  * Holds any validation errors produced by the last call of the validateErrors() method/
00315  *
00316  * @var array Validation errors, or false if none
00317  * @access public
00318  */
00319     var $validationErrors = null;
00320 /**
00321  * Constructor.
00322  *
00323  */
00324     function __construct() {
00325         if ($this->name === null) {
00326             $r = null;
00327             if (!preg_match('/(.*)Controller/i', get_class($this), $r)) {
00328                 die (__("Controller::__construct() : Can not get or parse my own class name, exiting."));
00329             }
00330             $this->name = $r[1];
00331         }
00332 
00333         if ($this->viewPath == null) {
00334             $this->viewPath = Inflector::underscore($this->name);
00335         }
00336         $this->modelClass = Inflector::classify($this->name);
00337         $this->modelKey = Inflector::underscore($this->modelClass);
00338         $this->Component =& new Component();
00339 
00340         $childMethods = get_class_methods($this);
00341         $parentMethods = get_class_methods('Controller');
00342 
00343         foreach ($childMethods as $key => $value) {
00344             $childMethods[$key] = strtolower($value);
00345         }
00346 
00347         foreach ($parentMethods as $key => $value) {
00348             $parentMethods[$key] = strtolower($value);
00349         }
00350         $this->methods = array_diff($childMethods, $parentMethods);
00351         parent::__construct();
00352     }
00353 /**
00354  * Merge components, helpers, and uses vars from AppController and PluginAppController.
00355  *
00356  * @return void
00357  * @access protected
00358  */
00359     function __mergeVars() {
00360         $pluginName = Inflector::camelize($this->plugin);
00361         $pluginController = $pluginName . 'AppController';
00362 
00363         if (is_subclass_of($this, 'AppController') || is_subclass_of($this, $pluginController)) {
00364             $appVars = get_class_vars('AppController');
00365             $uses = $appVars['uses'];
00366             $merge = array('components', 'helpers');
00367             $plugin = null;
00368 
00369             if (!empty($this->plugin)) {
00370                 $plugin = $pluginName . '.';
00371                 if (!is_subclass_of($this, $pluginController)) {
00372                     $pluginController = null;
00373                 }
00374             } else {
00375                 $pluginController = null;
00376             }
00377 
00378             if ($uses == $this->uses && !empty($this->uses)) {
00379                 if (!in_array($plugin . $this->modelClass, $this->uses)) {
00380                     array_unshift($this->uses, $plugin . $this->modelClass);
00381                 } elseif ($this->uses[0] !== $plugin . $this->modelClass) {
00382                     $this->uses = array_flip($this->uses);
00383                     unset($this->uses[$plugin . $this->modelClass]);
00384                     $this->uses = array_flip($this->uses);
00385                     array_unshift($this->uses, $plugin . $this->modelClass);
00386                 }
00387             } elseif ($this->uses !== null || $this->uses !== false) {
00388                 $merge[] = 'uses';
00389             }
00390 
00391             foreach ($merge as $var) {
00392                 if (!empty($appVars[$var]) && is_array($this->{$var})) {
00393                     if ($var === 'components') {
00394                         $normal = Set::normalize($this->{$var});
00395                         $app = Set::normalize($appVars[$var]);
00396                         if ($app !== $normal) {
00397                             $this->{$var} = Set::merge($app, $normal);
00398                         }
00399                     } else {
00400                         $this->{$var} = Set::merge($this->{$var}, array_diff($appVars[$var], $this->{$var}));
00401                     }
00402                 }
00403             }
00404         }
00405 
00406         if ($pluginController && $pluginName != null) {
00407             $appVars = get_class_vars($pluginController);
00408             $uses = $appVars['uses'];
00409             $merge = array('components', 'helpers');
00410 
00411             if ($this->uses !== null || $this->uses !== false) {
00412                 $merge[] = 'uses';
00413             }
00414 
00415             foreach ($merge as $var) {
00416                 if (isset($appVars[$var]) && !empty($appVars[$var]) && is_array($this->{$var})) {
00417                     if ($var === 'components') {
00418                         $normal = Set::normalize($this->{$var});
00419                         $app = Set::normalize($appVars[$var]);
00420                         if ($app !== $normal) {
00421                             $this->{$var} = Set::merge($app, $normal);
00422                         }
00423                     } else {
00424                         $this->{$var} = Set::merge($this->{$var}, array_diff($appVars[$var], $this->{$var}));
00425                     }
00426                 }
00427             }
00428         }
00429     }
00430 /**
00431  * Loads Model classes based on the the uses property
00432  * see Controller::loadModel(); for more info.
00433  * Loads Components and prepares them for initialization.
00434  *
00435  * @return mixed true if models found and instance created, or cakeError if models not found.
00436  * @access public
00437  * @see Controller::loadModel()
00438  * @link http://book.cakephp.org/view/429/constructClasses
00439  */
00440     function constructClasses() {
00441         $this->__mergeVars();
00442         $this->Component->init($this);
00443 
00444         if ($this->uses !== null || ($this->uses !== array())) {
00445             if (empty($this->passedArgs) || !isset($this->passedArgs['0'])) {
00446                 $id = false;
00447             } else {
00448                 $id = $this->passedArgs['0'];
00449             }
00450 
00451             if ($this->uses === false) {
00452                 $this->loadModel($this->modelClass, $id);
00453             } elseif ($this->uses) {
00454                 $uses = is_array($this->uses) ? $this->uses : array($this->uses);
00455                 $modelClassName = $uses[0];
00456                 if (strpos($uses[0], '.') !== false) {
00457                     list($plugin, $modelClassName) = explode('.', $uses[0]);
00458                 }
00459                 $this->modelClass = $modelClassName;
00460                 foreach ($uses as $modelClass) {
00461                     $this->loadModel($modelClass);
00462                 }
00463             }
00464         }
00465         return true;
00466     }
00467 /**
00468  * Loads and instantiates models required by this controller.
00469  * If Controller::persistModel; is true, controller will create cached model instances on first request,
00470  * additional request will used cached models.
00471  * If the model is non existent, it will throw a missing database table error, as Cake generates
00472  * dynamic models for the time being.
00473  *
00474  * @param string $modelClass Name of model class to load
00475  * @param mixed $id Initial ID the instanced model class should have
00476  * @return mixed true when single model found and instance created error returned if models not found.
00477  * @access public
00478  */
00479     function loadModel($modelClass = null, $id = null) {
00480         if ($modelClass === null) {
00481             $modelClass = $this->modelClass;
00482         }
00483         $cached = false;
00484         $object = null;
00485         $plugin = null;
00486         if ($this->uses === false) {
00487             if ($this->plugin) {
00488                 $plugin = $this->plugin . '.';
00489             }
00490         }
00491 
00492         if (strpos($modelClass, '.') !== false) {
00493             list($plugin, $modelClass) = explode('.', $modelClass);
00494             $plugin = $plugin . '.';
00495         }
00496 
00497         if ($this->persistModel === true) {
00498             $cached = $this->_persist($modelClass, null, $object);
00499         }
00500 
00501         if (($cached === false)) {
00502             $this->modelNames[] = $modelClass;
00503 
00504             if (!PHP5) {
00505                 $this->{$modelClass} =& ClassRegistry::init(array('class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id));
00506             } else {
00507                 $this->{$modelClass} = ClassRegistry::init(array('class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id));
00508             }
00509 
00510             if (!$this->{$modelClass}) {
00511                 return $this->cakeError('missingModel', array(array('className' => $modelClass, 'webroot' => '', 'base' => $this->base)));
00512             }
00513 
00514             if ($this->persistModel === true) {
00515                 $this->_persist($modelClass, true, $this->{$modelClass});
00516                 $registry = ClassRegistry::getInstance();
00517                 $this->_persist($modelClass . 'registry', true, $registry->__objects, 'registry');
00518             }
00519         } else {
00520             $this->_persist($modelClass . 'registry', true, $object, 'registry');
00521             $this->_persist($modelClass, true, $object);
00522             $this->modelNames[] = $modelClass;
00523         }
00524     }
00525 /**
00526  * Redirects to given $url, after turning off $this->autoRender.
00527  * Script execution is halted after the redirect.
00528  *
00529  * @param mixed $url A string or array-based URL pointing to another location within the app, or an absolute URL
00530  * @param integer $status Optional HTTP status code (eg: 404)
00531  * @param boolean $exit If true, exit() will be called after the redirect
00532  * @return mixed void if $exit = false. Terminates script if $exit = true
00533  * @access public
00534  * @link http://book.cakephp.org/view/425/redirect
00535  */
00536     function redirect($url, $status = null, $exit = true) {
00537         $this->autoRender = false;
00538 
00539         if (is_array($status)) {
00540             extract($status, EXTR_OVERWRITE);
00541         }
00542         $response = $this->Component->beforeRedirect($this, $url, $status, $exit);
00543 
00544         if ($response === false) {
00545             return;
00546         }
00547         if (is_array($response)) {
00548             foreach ($response as $resp) {
00549                 if (is_array($resp) && isset($resp['url'])) {
00550                     extract($resp, EXTR_OVERWRITE);
00551                 } elseif ($resp !== null) {
00552                     $url = $resp;
00553                 }
00554             }
00555         }
00556 
00557         if (function_exists('session_write_close')) {
00558             session_write_close();
00559         }
00560 
00561         if (!empty($status)) {
00562             $codes = array(
00563                 100 => 'Continue',
00564                 101 => 'Switching Protocols',
00565                 200 => 'OK',
00566                 201 => 'Created',
00567                 202 => 'Accepted',
00568                 203 => 'Non-Authoritative Information',
00569                 204 => 'No Content',
00570                 205 => 'Reset Content',
00571                 206 => 'Partial Content',
00572                 300 => 'Multiple Choices',
00573                 301 => 'Moved Permanently',
00574                 302 => 'Found',
00575                 303 => 'See Other',
00576                 304 => 'Not Modified',
00577                 305 => 'Use Proxy',
00578                 307 => 'Temporary Redirect',
00579                 400 => 'Bad Request',
00580                 401 => 'Unauthorized',
00581                 402 => 'Payment Required',
00582                 403 => 'Forbidden',
00583                 404 => 'Not Found',
00584                 405 => 'Method Not Allowed',
00585                 406 => 'Not Acceptable',
00586                 407 => 'Proxy Authentication Required',
00587                 408 => 'Request Time-out',
00588                 409 => 'Conflict',
00589                 410 => 'Gone',
00590                 411 => 'Length Required',
00591                 412 => 'Precondition Failed',
00592                 413 => 'Request Entity Too Large',
00593                 414 => 'Request-URI Too Large',
00594                 415 => 'Unsupported Media Type',
00595                 416 => 'Requested range not satisfiable',
00596                 417 => 'Expectation Failed',
00597                 500 => 'Internal Server Error',
00598                 501 => 'Not Implemented',
00599                 502 => 'Bad Gateway',
00600                 503 => 'Service Unavailable',
00601                 504 => 'Gateway Time-out'
00602             );
00603             if (is_string($status)) {
00604                 $codes = array_combine(array_values($codes), array_keys($codes));
00605             }
00606 
00607             if (isset($codes[$status])) {
00608                 $code = $msg = $codes[$status];
00609                 if (is_numeric($status)) {
00610                     $code = $status;
00611                 }
00612                 if (is_string($status)) {
00613                     $msg = $status;
00614                 }
00615                 $status = "HTTP/1.1 {$code} {$msg}";
00616             } else {
00617                 $status = null;
00618             }
00619         }
00620 
00621         if (!empty($status)) {
00622             $this->header($status);
00623         }
00624         if ($url !== null) {
00625             $this->header('Location: ' . Router::url($url, true));
00626         }
00627 
00628         if (!empty($status) && ($status >= 300 && $status < 400)) {
00629             $this->header($status);
00630         }
00631 
00632         if ($exit) {
00633             $this->_stop();
00634         }
00635     }
00636 /**
00637  * Convenience method for header()
00638  *
00639  * @param string $status
00640  * @return void
00641  * @access public
00642  */
00643     function header($status) {
00644         header($status);
00645     }
00646 /**
00647  * Saves a variable for use inside a view template.
00648  *
00649  * @param mixed $one A string or an array of data.
00650  * @param mixed $two Value in case $one is a string (which then works as the key).
00651  *   Unused if $one is an associative array, otherwise serves as the values to $one's keys.
00652  * @return void
00653  * @access public
00654  * @link http://book.cakephp.org/view/427/set
00655  */
00656     function set($one, $two = null) {
00657         $data = array();
00658 
00659         if (is_array($one)) {
00660             if (is_array($two)) {
00661                 $data = array_combine($one, $two);
00662             } else {
00663                 $data = $one;
00664             }
00665         } else {
00666             $data = array($one => $two);
00667         }
00668 
00669         foreach ($data as $name => $value) {
00670             if ($name === 'title') {
00671                 $this->pageTitle = $value;
00672             } else {
00673                 if ($two === null && is_array($one)) {
00674                     $this->viewVars[Inflector::variable($name)] = $value;
00675                 } else {
00676                     $this->viewVars[$name] = $value;
00677                 }
00678             }
00679         }
00680     }
00681 /**
00682  * Internally redirects one action to another. Examples:
00683  *
00684  * setAction('another_action');
00685  * setAction('action_with_parameters', $parameter1);
00686  *
00687  * @param string $action The new action to be redirected to
00688  * @param mixed  Any other parameters passed to this method will be passed as
00689  *               parameters to the new action.
00690  * @return mixed Returns the return value of the called action
00691  * @access public
00692  */
00693     function setAction($action) {
00694         $this->action = $action;
00695         $args = func_get_args();
00696         unset($args[0]);
00697         return call_user_func_array(array(&$this, $action), $args);
00698     }
00699 /**
00700  * Controller callback to tie into Auth component. Only called when AuthComponent::authorize is set to 'controller'.
00701  *
00702  * @return bool true if authorized, false otherwise
00703  * @access public
00704  * @link http://book.cakephp.org/view/396/authorize
00705  */
00706     function isAuthorized() {
00707         trigger_error(sprintf(__('%s::isAuthorized() is not defined.', true), $this->name), E_USER_WARNING);
00708         return false;
00709     }
00710 /**
00711  * Returns number of errors in a submitted FORM.
00712  *
00713  * @return integer Number of errors
00714  * @access public
00715  */
00716     function validate() {
00717         $args = func_get_args();
00718         $errors = call_user_func_array(array(&$this, 'validateErrors'), $args);
00719 
00720         if ($errors === false) {
00721             return 0;
00722         }
00723         return count($errors);
00724     }
00725 /**
00726  * Validates models passed by parameters. Example:
00727  *
00728  * $errors = $this->validateErrors($this->Article, $this->User);
00729  *
00730  * @param mixed A list of models as a variable argument
00731  * @return array Validation errors, or false if none
00732  * @access public
00733  */
00734     function validateErrors() {
00735         $objects = func_get_args();
00736 
00737         if (!count($objects)) {
00738             return false;
00739         }
00740 
00741         $errors = array();
00742         foreach ($objects as $object) {
00743             $this->{$object->alias}->set($object->data);
00744             $errors = array_merge($errors, $this->{$object->alias}->invalidFields());
00745         }
00746 
00747         return $this->validationErrors = (count($errors) ? $errors : false);
00748     }
00749 /**
00750  * Instantiates the correct view class, hands it its data, and uses it to render the view output.
00751  *
00752  * @param string $action Action name to render
00753  * @param string $layout Layout to use
00754  * @param string $file File to use for rendering
00755  * @return string Full output string of view contents
00756  * @access public
00757  * @link http://book.cakephp.org/view/428/render
00758  */
00759     function render($action = null, $layout = null, $file = null) {
00760         $this->beforeRender();
00761 
00762         $viewClass = $this->view;
00763         if ($this->view != 'View') {
00764             if (strpos($viewClass, '.') !== false) {
00765                 list($plugin, $viewClass) = explode('.', $viewClass);
00766             }
00767             $viewClass = $viewClass . 'View';
00768             App::import('View', $this->view);
00769         }
00770 
00771         $this->Component->beforeRender($this);
00772 
00773         $this->params['models'] = $this->modelNames;
00774 
00775         if (Configure::read() > 2) {
00776             $this->set('cakeDebug', $this);
00777         }
00778 
00779         $View =& new $viewClass($this);
00780 
00781         if (!empty($this->modelNames)) {
00782             $models = array();
00783             foreach ($this->modelNames as $currentModel) {
00784                 if (isset($this->$currentModel) && is_a($this->$currentModel, 'Model')) {
00785                     $models[] = Inflector::underscore($currentModel);
00786                 }
00787                 if (isset($this->$currentModel) && is_a($this->$currentModel, 'Model') && !empty($this->$currentModel->validationErrors)) {
00788                     $View->validationErrors[Inflector::camelize($currentModel)] =& $this->$currentModel->validationErrors;
00789                 }
00790             }
00791             $models = array_diff(ClassRegistry::keys(), $models);
00792             foreach ($models as $currentModel) {
00793                 if (ClassRegistry::isKeySet($currentModel)) {
00794                     $currentObject =& ClassRegistry::getObject($currentModel);
00795                     if (is_a($currentObject, 'Model') && !empty($currentObject->validationErrors)) {
00796                         $View->validationErrors[Inflector::camelize($currentModel)] =& $currentObject->validationErrors;
00797                     }
00798                 }
00799             }
00800         }
00801 
00802         $this->autoRender = false;
00803         $this->output .= $View->render($action, $layout, $file);
00804 
00805         return $this->output;
00806     }
00807 /**
00808  * Returns the referring URL for this request.
00809  *
00810  * @param string $default Default URL to use if HTTP_REFERER cannot be read from headers
00811  * @param boolean $local If true, restrict referring URLs to local server
00812  * @return string Referring URL
00813  * @access public
00814  * @link http://book.cakephp.org/view/430/referer
00815  */
00816     function referer($default = null, $local = false) {
00817         $ref = env('HTTP_REFERER');
00818         if (!empty($ref) && defined('FULL_BASE_URL')) {
00819             $base = FULL_BASE_URL . $this->webroot;
00820             if (strpos($ref, $base) === 0) {
00821                 $return =  substr($ref, strlen($base));
00822                 if ($return[0] != '/') {
00823                     $return = '/'.$return;
00824                 }
00825                 return $return;
00826             } elseif (!$local) {
00827                 return $ref;
00828             }
00829         }
00830 
00831         if ($default != null) {
00832             return $default;
00833         }
00834         return '/';
00835     }
00836 /**
00837  * Forces the user's browser not to cache the results of the current request.
00838  *
00839  * @return void
00840  * @access public
00841  * @link http://book.cakephp.org/view/431/disableCache
00842  */
00843     function disableCache() {
00844         header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
00845         header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
00846         header("Cache-Control: no-store, no-cache, must-revalidate");
00847         header("Cache-Control: post-check=0, pre-check=0", false);
00848         header("Pragma: no-cache");
00849     }
00850 /**
00851  * Shows a message to the user for $pause seconds, then redirects to $url.
00852  * Uses flash.ctp as the default layout for the message.
00853  * Does not work if the current debug level is higher than 0.
00854  *
00855  * @param string $message Message to display to the user
00856  * @param mixed $url Relative string or array-based URL to redirect to after the time expires
00857  * @param integer $pause Time to show the message
00858  * @return void Renders flash layout
00859  * @access public
00860  * @link http://book.cakephp.org/view/426/flash
00861  */
00862     function flash($message, $url, $pause = 1) {
00863         $this->autoRender = false;
00864         $this->set('url', Router::url($url));
00865         $this->set('message', $message);
00866         $this->set('pause', $pause);
00867         $this->set('page_title', $message);
00868         $this->render(false, 'flash');
00869     }
00870 /**
00871  * Converts POST'ed form data to a model conditions array, suitable for use in a Model::find() call.
00872  *
00873  * @param array $data POST'ed data organized by model and field
00874  * @param mixed $op A string containing an SQL comparison operator, or an array matching operators to fields
00875  * @param string $bool SQL boolean operator: AND, OR, XOR, etc.
00876  * @param boolean $exclusive If true, and $op is an array, fields not included in $op will not be included in the returned conditions
00877  * @return array An array of model conditions
00878  * @access public
00879  * @link http://book.cakephp.org/view/432/postConditions
00880  */
00881     function postConditions($data = array(), $op = null, $bool = 'AND', $exclusive = false) {
00882         if (!is_array($data) || empty($data)) {
00883             if (!empty($this->data)) {
00884                 $data = $this->data;
00885             } else {
00886                 return null;
00887             }
00888         }
00889         $cond = array();
00890 
00891         if ($op === null) {
00892             $op = '';
00893         }
00894 
00895         foreach ($data as $model => $fields) {
00896             foreach ($fields as $field => $value) {
00897                 $key = $model.'.'.$field;
00898                 $fieldOp = $op;
00899                 if (is_array($op) && array_key_exists($key, $op)) {
00900                     $fieldOp = $op[$key];
00901                 } elseif (is_array($op) && array_key_exists($field, $op)) {
00902                     $fieldOp = $op[$field];
00903                 } elseif (is_array($op)) {
00904                     $fieldOp = false;
00905                 }
00906                 if ($exclusive && $fieldOp === false) {
00907                     continue;
00908                 }
00909                 $fieldOp = strtoupper(trim($fieldOp));
00910                 if ($fieldOp === 'LIKE') {
00911                     $key = $key.' LIKE';
00912                     $value = '%'.$value.'%';
00913                 } elseif ($fieldOp && $fieldOp != '=') {
00914                     $key = $key.' '.$fieldOp;
00915                 }
00916                 $cond[$key] = $value;
00917             }
00918         }
00919         if ($bool != null && strtoupper($bool) != 'AND') {
00920             $cond = array($bool => $cond);
00921         }
00922         return $cond;
00923     }
00924 /**
00925  * Handles automatic pagination of model records.
00926  *
00927  * @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
00928  * @param mixed $scope Conditions to use while paginating
00929  * @param array $whitelist List of allowed options for paging
00930  * @return array Model query results
00931  * @access public
00932  * @link http://book.cakephp.org/view/165/Controller-Setup
00933  */
00934     function paginate($object = null, $scope = array(), $whitelist = array()) {
00935         if (is_array($object)) {
00936             $whitelist = $scope;
00937             $scope = $object;
00938             $object = null;
00939         }
00940         $assoc = null;
00941 
00942         if (is_string($object)) {
00943             $assoc = null;
00944 
00945             if (strpos($object, '.') !== false) {
00946                 list($object, $assoc) = explode('.', $object);
00947             }
00948 
00949             if ($assoc && isset($this->{$object}->{$assoc})) {
00950                 $object =& $this->{$object}->{$assoc};
00951             } elseif ($assoc && isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$assoc})) {
00952                 $object =& $this->{$this->modelClass}->{$assoc};
00953             } elseif (isset($this->{$object})) {
00954                 $object =& $this->{$object};
00955             } elseif (isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$object})) {
00956                 $object =& $this->{$this->modelClass}->{$object};
00957             }
00958         } elseif (empty($object) || $object === null) {
00959             if (isset($this->{$this->modelClass})) {
00960                 $object =& $this->{$this->modelClass};
00961             } else {
00962                 $className = null;
00963                 $name = $this->uses[0];
00964                 if (strpos($this->uses[0], '.') !== false) {
00965                     list($name, $className) = explode('.', $this->uses[0]);
00966                 }
00967                 if ($className) {
00968                     $object =& $this->{$className};
00969                 } else {
00970                     $object =& $this->{$name};
00971                 }
00972             }
00973         }
00974 
00975         if (!is_object($object)) {
00976             trigger_error(sprintf(__('Controller::paginate() - can\'t find model %1$s in controller %2$sController', true), $object, $this->name), E_USER_WARNING);
00977             return array();
00978         }
00979         $options = array_merge($this->params, $this->params['url'], $this->passedArgs);
00980 
00981         if (isset($this->paginate[$object->alias])) {
00982             $defaults = $this->paginate[$object->alias];
00983         } else {
00984             $defaults = $this->paginate;
00985         }
00986 
00987         if (isset($options['show'])) {
00988             $options['limit'] = $options['show'];
00989         }
00990 
00991         if (isset($options['sort'])) {
00992             $direction = null;
00993             if (isset($options['direction'])) {
00994                 $direction = strtolower($options['direction']);
00995             }
00996             if ($direction != 'asc' && $direction != 'desc') {
00997                 $direction = 'asc';
00998             }
00999             $options['order'] = array($options['sort'] => $direction);
01000         }
01001 
01002         if (!empty($options['order']) && is_array($options['order'])) {
01003             $alias = $object->alias ;
01004             $key = $field = key($options['order']);
01005 
01006             if (strpos($key, '.') !== false) {
01007                 list($alias, $field) = explode('.', $key);
01008             }
01009             $value = $options['order'][$key];
01010             unset($options['order'][$key]);
01011 
01012             if (isset($object->{$alias}) && $object->{$alias}->hasField($field)) {
01013                 $options['order'][$alias . '.' . $field] = $value;
01014             } elseif ($object->hasField($field)) {
01015                 $options['order'][$alias . '.' . $field] = $value;
01016             }
01017         }
01018         $vars = array('fields', 'order', 'limit', 'page', 'recursive');
01019         $keys = array_keys($options);
01020         $count = count($keys);
01021 
01022         for ($i = 0; $i < $count; $i++) {
01023             if (!in_array($keys[$i], $vars, true)) {
01024                 unset($options[$keys[$i]]);
01025             }
01026             if (empty($whitelist) && ($keys[$i] === 'fields' || $keys[$i] === 'recursive')) {
01027                 unset($options[$keys[$i]]);
01028             } elseif (!empty($whitelist) && !in_array($keys[$i], $whitelist)) {
01029                 unset($options[$keys[$i]]);
01030             }
01031         }
01032         $conditions = $fields = $order = $limit = $page = $recursive = null;
01033 
01034         if (!isset($defaults['conditions'])) {
01035             $defaults['conditions'] = array();
01036         }
01037 
01038         $type = 'all';
01039 
01040         if (isset($defaults[0])) {
01041             $type = $defaults[0];
01042             unset($defaults[0]);
01043         }
01044 
01045         extract($options = array_merge(array('page' => 1, 'limit' => 20), $defaults, $options));
01046 
01047         if (is_array($scope) && !empty($scope)) {
01048             $conditions = array_merge($conditions, $scope);
01049         } elseif (is_string($scope)) {
01050             $conditions = array($conditions, $scope);
01051         }
01052         if ($recursive === null) {
01053             $recursive = $object->recursive;
01054         }
01055 
01056         $extra = array_diff_key($defaults, compact(
01057             'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
01058         ));
01059         if ($type !== 'all') {
01060             $extra['type'] = $type;
01061         }
01062 
01063         if (method_exists($object, 'paginateCount')) {
01064             $count = $object->paginateCount($conditions, $recursive, $extra);
01065         } else {
01066             $parameters = compact('conditions');
01067             if ($recursive != $object->recursive) {
01068                 $parameters['recursive'] = $recursive;
01069             }
01070             $count = $object->find('count', array_merge($parameters, $extra));
01071         }
01072         $pageCount = intval(ceil($count / $limit));
01073 
01074         if ($page === 'last' || $page >= $pageCount) {
01075             $options['page'] = $page = $pageCount;
01076         } elseif (intval($page) < 1) {
01077             $options['page'] = $page = 1;
01078         }
01079         $page = $options['page'] = (integer)$page;
01080 
01081         if (method_exists($object, 'paginate')) {
01082             $results = $object->paginate($conditions, $fields, $order, $limit, $page, $recursive, $extra);
01083         } else {
01084             $parameters = compact('conditions', 'fields', 'order', 'limit', 'page');
01085             if ($recursive != $object->recursive) {
01086                 $parameters['recursive'] = $recursive;
01087             }
01088             $results = $object->find($type, array_merge($parameters, $extra));
01089         }
01090         $paging = array(
01091             'page'      => $page,
01092             'current'   => count($results),
01093             'count'     => $count,
01094             'prevPage'  => ($page > 1),
01095             'nextPage'  => ($count > ($page * $limit)),
01096             'pageCount' => $pageCount,
01097             'defaults'  => array_merge(array('limit' => 20, 'step' => 1), $defaults),
01098             'options'   => $options
01099         );
01100         $this->params['paging'][$object->alias] = $paging;
01101 
01102         if (!in_array('Paginator', $this->helpers) && !array_key_exists('Paginator', $this->helpers)) {
01103             $this->helpers[] = 'Paginator';
01104         }
01105         return $results;
01106     }
01107 /**
01108  * Called before the controller action.
01109  *
01110  * @access public
01111  * @link http://book.cakephp.org/view/60/Callbacks
01112  */
01113     function beforeFilter() {
01114     }
01115 /**
01116  * Called after the controller action is run, but before the view is rendered.
01117  *
01118  * @access public
01119  * @link http://book.cakephp.org/view/60/Callbacks
01120  */
01121     function beforeRender() {
01122     }
01123 /**
01124  * Called after the controller action is run and rendered.
01125  *
01126  * @access public
01127  * @link http://book.cakephp.org/view/60/Callbacks
01128  */
01129     function afterFilter() {
01130     }
01131 /**
01132  * This method should be overridden in child classes.
01133  *
01134  * @param string $method name of method called example index, edit, etc.
01135  * @return boolean Success
01136  * @access protected
01137  * @link http://book.cakephp.org/view/60/Callbacks
01138  */
01139     function _beforeScaffold($method) {
01140         return true;
01141     }
01142 /**
01143  * This method should be overridden in child classes.
01144  *
01145  * @param string $method name of method called either edit or update.
01146  * @return boolean Success
01147  * @access protected
01148  * @link http://book.cakephp.org/view/60/Callbacks
01149  */
01150     function _afterScaffoldSave($method) {
01151         return true;
01152     }
01153 /**
01154  * This method should be overridden in child classes.
01155  *
01156  * @param string $method name of method called either edit or update.
01157  * @return boolean Success
01158  * @access protected
01159  * @link http://book.cakephp.org/view/60/Callbacks
01160  */
01161     function _afterScaffoldSaveError($method) {
01162         return true;
01163     }
01164 /**
01165  * This method should be overridden in child classes.
01166  * If not it will render a scaffold error.
01167  * Method MUST return true in child classes
01168  *
01169  * @param string $method name of method called example index, edit, etc.
01170  * @return boolean Success
01171  * @access protected
01172  * @link http://book.cakephp.org/view/60/Callbacks
01173  */
01174     function _scaffoldError($method) {
01175         return false;
01176     }
01177 }
01178 ?>

Generated on Sun Nov 22 00:30:51 2009 for CakePHP 1.2.x.x (v1.2.4.8284) by doxygen 1.4.7