controller.php

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