Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • Net
  • None
  • PHP
  • system
    • base
    • caching
      • dependencies
    • collections
    • console
    • db
      • ar
      • schema
        • cubrid
        • mssql
        • mysql
        • oci
        • pgsql
        • sqlite
    • i18n
      • gettext
    • logging
    • test
    • utils
    • validators
    • web
      • actions
      • auth
      • filters
      • form
      • helpers
      • renderers
      • services
      • widgets
        • captcha
        • pagers
  • Text
    • Highlighter
  • zii
    • behaviors
    • widgets
      • grid
      • jui

Classes

  • ActionFormModelBase
  • CActiveDataProvider
  • CalendarEventFormModel
  • CallFormModel
  • CArrayDataProvider
  • CAssetManager
  • CBaseController
  • CBaseUrlRule
  • CCacheHttpSession
  • CClientScript
  • CController
  • CCookieCollection
  • CDataProvider
  • CDataProviderIterator
  • CDbHttpSession
  • CExtController
  • CFormModel
  • CHttpCookie
  • CHttpRequest
  • CHttpSession
  • CHttpSessionIterator
  • COutputEvent
  • CPagination
  • CreatePageFormModel
  • CSort
  • CSqlDataProvider
  • CTheme
  • CThemeManager
  • CUploadedFile
  • CUrlManager
  • CUrlRule
  • CWebApplication
  • CWebModule
  • CWidgetFactory
  • EditMobileFormsFormModel
  • EventCommentPublisherFormModel
  • EventFormModel
  • EventPublisherFormModel
  • FileSystemObjectDataProvider
  • MassActionFormModel
  • MobilePagination
  • NoteFormModel
  • NotificationsController
  • TimeFormModel
  • UploadLogoFormModel
  • X2FormModel
  • X2HttpRequest

Interfaces

  • IDataProvider
  • IWidgetFactory
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * CController class file.
   4:  *
   5:  * @author Qiang Xue <qiang.xue@gmail.com>
   6:  * @link http://www.yiiframework.com/
   7:  * @copyright 2008-2013 Yii Software LLC
   8:  * @license http://www.yiiframework.com/license/
   9:  */
  10: 
  11: 
  12: /**
  13:  * CController manages a set of actions which deal with the corresponding user requests.
  14:  *
  15:  * Through the actions, CController coordinates the data flow between models and views.
  16:  *
  17:  * When a user requests an action 'XYZ', CController will do one of the following:
  18:  * 1. Method-based action: call method 'actionXYZ' if it exists;
  19:  * 2. Class-based action: create an instance of class 'XYZ' if the class is found in the action class map
  20:  *    (specified via {@link actions()}, and execute the action;
  21:  * 3. Call {@link missingAction()}, which by default will raise a 404 HTTP exception.
  22:  *
  23:  * If the user does not specify an action, CController will run the action specified by
  24:  * {@link defaultAction}, instead.
  25:  *
  26:  * CController may be configured to execute filters before and after running actions.
  27:  * Filters preprocess/postprocess the user request/response and may quit executing actions
  28:  * if needed. They are executed in the order they are specified. If during the execution,
  29:  * any of the filters returns true, the rest filters and the action will no longer get executed.
  30:  *
  31:  * Filters can be individual objects, or methods defined in the controller class.
  32:  * They are specified by overriding {@link filters()} method. The following is an example
  33:  * of the filter specification:
  34:  * <pre>
  35:  * array(
  36:  *     'accessControl - login',
  37:  *     'ajaxOnly + search',
  38:  *     array(
  39:  *         'COutputCache + list',
  40:  *         'duration'=>300,
  41:  *     ),
  42:  * )
  43:  * </pre>
  44:  * The above example declares three filters: accessControl, ajaxOnly, COutputCache. The first two
  45:  * are method-based filters (defined in CController), which refer to filtering methods in the controller class;
  46:  * while the last refers to an object-based filter whose class is 'system.web.widgets.COutputCache' and
  47:  * the 'duration' property is initialized as 300 (s).
  48:  *
  49:  * For method-based filters, a method named 'filterXYZ($filterChain)' in the controller class
  50:  * will be executed, where 'XYZ' stands for the filter name as specified in {@link filters()}.
  51:  * Note, inside the filter method, you must call <code>$filterChain->run()</code> if the action should
  52:  * be executed. Otherwise, the filtering process would stop at this filter.
  53:  *
  54:  * Filters can be specified so that they are executed only when running certain actions.
  55:  * For method-based filters, this is done by using '+' and '-' operators in the filter specification.
  56:  * The '+' operator means the filter runs only when the specified actions are requested;
  57:  * while the '-' operator means the filter runs only when the requested action is not among those actions.
  58:  * For object-based filters, the '+' and '-' operators are following the class name.
  59:  *
  60:  * @property array $actionParams The request parameters to be used for action parameter binding.
  61:  * @property CAction $action The action currently being executed, null if no active action.
  62:  * @property string $id ID of the controller.
  63:  * @property string $uniqueId The controller ID that is prefixed with the module ID (if any).
  64:  * @property string $route The route (module ID, controller ID and action ID) of the current request.
  65:  * @property CWebModule $module The module that this controller belongs to. It returns null
  66:  * if the controller does not belong to any module.
  67:  * @property string $viewPath The directory containing the view files for this controller. Defaults to 'protected/views/ControllerID'.
  68:  * @property CMap $clips The list of clips.
  69:  * @property string $pageTitle The page title. Defaults to the controller name and the action name.
  70:  * @property CStack $cachingStack Stack of {@link COutputCache} objects.
  71:  *
  72:  * @author Qiang Xue <qiang.xue@gmail.com>
  73:  * @package system.web
  74:  * @since 1.0
  75:  */
  76: class CController extends CBaseController
  77: {
  78:     /**
  79:      * Name of the hidden field storing persistent page states.
  80:      */
  81:     const STATE_INPUT_NAME='YII_PAGE_STATE';
  82: 
  83:     /**
  84:      * @var mixed the name of the layout to be applied to this controller's views.
  85:      * Defaults to null, meaning the {@link CWebApplication::layout application layout}
  86:      * is used. If it is false, no layout will be applied.
  87:      * The {@link CWebModule::layout module layout} will be used
  88:      * if the controller belongs to a module and this layout property is null.
  89:      */
  90:     public $layout;
  91:     /**
  92:      * @var string the name of the default action. Defaults to 'index'.
  93:      */
  94:     public $defaultAction='index';
  95: 
  96:     private $_id;
  97:     private $_action;
  98:     private $_pageTitle;
  99:     private $_cachingStack;
 100:     private $_clips;
 101:     private $_dynamicOutput;
 102:     private $_pageStates;
 103:     private $_module;
 104: 
 105: 
 106:     /**
 107:      * @param string $id id of this controller
 108:      * @param CWebModule $module the module that this controller belongs to.
 109:      */
 110:     public function __construct($id,$module=null)
 111:     {
 112:         $this->_id=$id;
 113:         $this->_module=$module;
 114:         $this->attachBehaviors($this->behaviors());
 115:     }
 116: 
 117:     /**
 118:      * Initializes the controller.
 119:      * This method is called by the application before the controller starts to execute.
 120:      * You may override this method to perform the needed initialization for the controller.
 121:      */
 122:     public function init()
 123:     {
 124:     }
 125: 
 126:     /**
 127:      * Returns the filter configurations.
 128:      *
 129:      * By overriding this method, child classes can specify filters to be applied to actions.
 130:      *
 131:      * This method returns an array of filter specifications. Each array element specify a single filter.
 132:      *
 133:      * For a method-based filter (called inline filter), it is specified as 'FilterName[ +|- Action1, Action2, ...]',
 134:      * where the '+' ('-') operators describe which actions should be (should not be) applied with the filter.
 135:      *
 136:      * For a class-based filter, it is specified as an array like the following:
 137:      * <pre>
 138:      * array(
 139:      *     'FilterClass[ +|- Action1, Action2, ...]',
 140:      *     'name1'=>'value1',
 141:      *     'name2'=>'value2',
 142:      *     ...
 143:      * )
 144:      * </pre>
 145:      * where the name-value pairs will be used to initialize the properties of the filter.
 146:      *
 147:      * Note, in order to inherit filters defined in the parent class, a child class needs to
 148:      * merge the parent filters with child filters using functions like array_merge().
 149:      *
 150:      * @return array a list of filter configurations.
 151:      * @see CFilter
 152:      */
 153:     public function filters()
 154:     {
 155:         return array();
 156:     }
 157: 
 158:     /**
 159:      * Returns a list of external action classes.
 160:      * Array keys are action IDs, and array values are the corresponding
 161:      * action class in dot syntax (e.g. 'edit'=>'application.controllers.article.EditArticle')
 162:      * or arrays representing the configuration of the actions, such as the following,
 163:      * <pre>
 164:      * return array(
 165:      *     'action1'=>'path.to.Action1Class',
 166:      *     'action2'=>array(
 167:      *         'class'=>'path.to.Action2Class',
 168:      *         'property1'=>'value1',
 169:      *         'property2'=>'value2',
 170:      *     ),
 171:      * );
 172:      * </pre>
 173:      * Derived classes may override this method to declare external actions.
 174:      *
 175:      * Note, in order to inherit actions defined in the parent class, a child class needs to
 176:      * merge the parent actions with child actions using functions like array_merge().
 177:      *
 178:      * You may import actions from an action provider
 179:      * (such as a widget, see {@link CWidget::actions}), like the following:
 180:      * <pre>
 181:      * return array(
 182:      *     ...other actions...
 183:      *     // import actions declared in ProviderClass::actions()
 184:      *     // the action IDs will be prefixed with 'pro.'
 185:      *     'pro.'=>'path.to.ProviderClass',
 186:      *     // similar as above except that the imported actions are
 187:      *     // configured with the specified initial property values
 188:      *     'pro2.'=>array(
 189:      *         'class'=>'path.to.ProviderClass',
 190:      *         'action1'=>array(
 191:      *             'property1'=>'value1',
 192:      *         ),
 193:      *         'action2'=>array(
 194:      *             'property2'=>'value2',
 195:      *         ),
 196:      *     ),
 197:      * )
 198:      * </pre>
 199:      *
 200:      * In the above, we differentiate action providers from other action
 201:      * declarations by the array keys. For action providers, the array keys
 202:      * must contain a dot. As a result, an action ID 'pro2.action1' will
 203:      * be resolved as the 'action1' action declared in the 'ProviderClass'.
 204:      *
 205:      * @return array list of external action classes
 206:      * @see createAction
 207:      */
 208:     public function actions()
 209:     {
 210:         return array();
 211:     }
 212: 
 213:     /**
 214:      * Returns a list of behaviors that this controller should behave as.
 215:      * The return value should be an array of behavior configurations indexed by
 216:      * behavior names. Each behavior configuration can be either a string specifying
 217:      * the behavior class or an array of the following structure:
 218:      * <pre>
 219:      * 'behaviorName'=>array(
 220:      *     'class'=>'path.to.BehaviorClass',
 221:      *     'property1'=>'value1',
 222:      *     'property2'=>'value2',
 223:      * )
 224:      * </pre>
 225:      *
 226:      * Note, the behavior classes must implement {@link IBehavior} or extend from
 227:      * {@link CBehavior}. Behaviors declared in this method will be attached
 228:      * to the controller when it is instantiated.
 229:      *
 230:      * For more details about behaviors, see {@link CComponent}.
 231:      * @return array the behavior configurations (behavior name=>behavior configuration)
 232:      */
 233:     public function behaviors()
 234:     {
 235:         return array();
 236:     }
 237: 
 238:     /**
 239:      * Returns the access rules for this controller.
 240:      * Override this method if you use the {@link filterAccessControl accessControl} filter.
 241:      * @return array list of access rules. See {@link CAccessControlFilter} for details about rule specification.
 242:      */
 243:     public function accessRules()
 244:     {
 245:         return array();
 246:     }
 247: 
 248:     /**
 249:      * Runs the named action.
 250:      * Filters specified via {@link filters()} will be applied.
 251:      * @param string $actionID action ID
 252:      * @throws CHttpException if the action does not exist or the action name is not proper.
 253:      * @see filters
 254:      * @see createAction
 255:      * @see runAction
 256:      */
 257:     public function run($actionID)
 258:     {
 259:         if(($action=$this->createAction($actionID))!==null)
 260:         {
 261:             if(($parent=$this->getModule())===null)
 262:                 $parent=Yii::app();
 263:             if($parent->beforeControllerAction($this,$action))
 264:             {
 265:                 $this->runActionWithFilters($action,$this->filters());
 266:                 $parent->afterControllerAction($this,$action);
 267:             }
 268:         }
 269:         else
 270:             $this->missingAction($actionID);
 271:     }
 272: 
 273:     /**
 274:      * Runs an action with the specified filters.
 275:      * A filter chain will be created based on the specified filters
 276:      * and the action will be executed then.
 277:      * @param CAction $action the action to be executed.
 278:      * @param array $filters list of filters to be applied to the action.
 279:      * @see filters
 280:      * @see createAction
 281:      * @see runAction
 282:      */
 283:     public function runActionWithFilters($action,$filters)
 284:     {
 285:         if(empty($filters))
 286:             $this->runAction($action);
 287:         else
 288:         {
 289:             $priorAction=$this->_action;
 290:             $this->_action=$action;
 291:             CFilterChain::create($this,$action,$filters)->run();
 292:             $this->_action=$priorAction;
 293:         }
 294:     }
 295: 
 296:     /**
 297:      * Runs the action after passing through all filters.
 298:      * This method is invoked by {@link runActionWithFilters} after all possible filters have been executed
 299:      * and the action starts to run.
 300:      * @param CAction $action action to run
 301:      */
 302:     public function runAction($action)
 303:     {
 304:         $priorAction=$this->_action;
 305:         $this->_action=$action;
 306:         if($this->beforeAction($action))
 307:         {
 308:             if($action->runWithParams($this->getActionParams())===false)
 309:                 $this->invalidActionParams($action);
 310:             else
 311:                 $this->afterAction($action);
 312:         }
 313:         $this->_action=$priorAction;
 314:     }
 315: 
 316:     /**
 317:      * Returns the request parameters that will be used for action parameter binding.
 318:      * By default, this method will return $_GET. You may override this method if you
 319:      * want to use other request parameters (e.g. $_GET+$_POST).
 320:      * @return array the request parameters to be used for action parameter binding
 321:      * @since 1.1.7
 322:      */
 323:     public function getActionParams()
 324:     {
 325:         return $_GET;
 326:     }
 327: 
 328:     /**
 329:      * This method is invoked when the request parameters do not satisfy the requirement of the specified action.
 330:      * The default implementation will throw a 400 HTTP exception.
 331:      * @param CAction $action the action being executed
 332:      * @since 1.1.7
 333:      */
 334:     public function invalidActionParams($action)
 335:     {
 336:         throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
 337:     }
 338: 
 339:     /**
 340:      * Postprocesses the output generated by {@link render()}.
 341:      * This method is invoked at the end of {@link render()} and {@link renderText()}.
 342:      * If there are registered client scripts, this method will insert them into the output
 343:      * at appropriate places. If there are dynamic contents, they will also be inserted.
 344:      * This method may also save the persistent page states in hidden fields of
 345:      * stateful forms in the page.
 346:      * @param string $output the output generated by the current action
 347:      * @return string the output that has been processed.
 348:      */
 349:     public function processOutput($output)
 350:     {
 351:         Yii::app()->getClientScript()->render($output);
 352: 
 353:         // if using page caching, we should delay dynamic output replacement
 354:         if($this->_dynamicOutput!==null && $this->isCachingStackEmpty())
 355:         {
 356:             $output=$this->processDynamicOutput($output);
 357:             $this->_dynamicOutput=null;
 358:         }
 359: 
 360:         if($this->_pageStates===null)
 361:             $this->_pageStates=$this->loadPageStates();
 362:         if(!empty($this->_pageStates))
 363:             $this->savePageStates($this->_pageStates,$output);
 364: 
 365:         return $output;
 366:     }
 367: 
 368:     /**
 369:      * Postprocesses the dynamic output.
 370:      * This method is internally used. Do not call this method directly.
 371:      * @param string $output output to be processed
 372:      * @return string the processed output
 373:      */
 374:     public function processDynamicOutput($output)
 375:     {
 376:         if($this->_dynamicOutput)
 377:         {
 378:             $output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output);
 379:         }
 380:         return $output;
 381:     }
 382: 
 383:     /**
 384:      * Replaces the dynamic content placeholders with actual content.
 385:      * This is a callback function used internally.
 386:      * @param array $matches matches
 387:      * @return string the replacement
 388:      * @see processOutput
 389:      */
 390:     protected function replaceDynamicOutput($matches)
 391:     {
 392:         $content=$matches[0];
 393:         if(isset($this->_dynamicOutput[$matches[1]]))
 394:         {
 395:             $content=$this->_dynamicOutput[$matches[1]];
 396:             $this->_dynamicOutput[$matches[1]]=null;
 397:         }
 398:         return $content;
 399:     }
 400: 
 401:     /**
 402:      * Creates the action instance based on the action name.
 403:      * The action can be either an inline action or an object.
 404:      * The latter is created by looking up the action map specified in {@link actions}.
 405:      * @param string $actionID ID of the action. If empty, the {@link defaultAction default action} will be used.
 406:      * @return CAction the action instance, null if the action does not exist.
 407:      * @see actions
 408:      */
 409:     public function createAction($actionID)
 410:     {
 411:         if($actionID==='')
 412:             $actionID=$this->defaultAction;
 413:         if(method_exists($this,'action'.$actionID) && strcasecmp($actionID,'s')) // we have actions method
 414:             return new CInlineAction($this,$actionID);
 415:         else
 416:         {
 417:             $action=$this->createActionFromMap($this->actions(),$actionID,$actionID);
 418:             if($action!==null && !method_exists($action,'run'))
 419:                 throw new CException(Yii::t('yii', 'Action class {class} must implement the "run" method.', array('{class}'=>get_class($action))));
 420:             return $action;
 421:         }
 422:     }
 423: 
 424:     /**
 425:      * Creates the action instance based on the action map.
 426:      * This method will check to see if the action ID appears in the given
 427:      * action map. If so, the corresponding configuration will be used to
 428:      * create the action instance.
 429:      * @param array $actionMap the action map
 430:      * @param string $actionID the action ID that has its prefix stripped off
 431:      * @param string $requestActionID the originally requested action ID
 432:      * @param array $config the action configuration that should be applied on top of the configuration specified in the map
 433:      * @return CAction the action instance, null if the action does not exist.
 434:      */
 435:     protected function createActionFromMap($actionMap,$actionID,$requestActionID,$config=array())
 436:     {
 437:         if(($pos=strpos($actionID,'.'))===false && isset($actionMap[$actionID]))
 438:         {
 439:             $baseConfig=is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class'=>$actionMap[$actionID]);
 440:             return Yii::createComponent(empty($config)?$baseConfig:array_merge($baseConfig,$config),$this,$requestActionID);
 441:         }
 442:         elseif($pos===false)
 443:             return null;
 444: 
 445:         // the action is defined in a provider
 446:         $prefix=substr($actionID,0,$pos+1);
 447:         if(!isset($actionMap[$prefix]))
 448:             return null;
 449:         $actionID=(string)substr($actionID,$pos+1);
 450: 
 451:         $provider=$actionMap[$prefix];
 452:         if(is_string($provider))
 453:             $providerType=$provider;
 454:         elseif(is_array($provider) && isset($provider['class']))
 455:         {
 456:             $providerType=$provider['class'];
 457:             if(isset($provider[$actionID]))
 458:             {
 459:                 if(is_string($provider[$actionID]))
 460:                     $config=array_merge(array('class'=>$provider[$actionID]),$config);
 461:                 else
 462:                     $config=array_merge($provider[$actionID],$config);
 463:             }
 464:         }
 465:         else
 466:             throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
 467: 
 468:         $class=Yii::import($providerType,true);
 469:         $map=call_user_func(array($class,'actions'));
 470: 
 471:         return $this->createActionFromMap($map,$actionID,$requestActionID,$config);
 472:     }
 473: 
 474:     /**
 475:      * Handles the request whose action is not recognized.
 476:      * This method is invoked when the controller cannot find the requested action.
 477:      * The default implementation simply throws an exception.
 478:      * @param string $actionID the missing action name
 479:      * @throws CHttpException whenever this method is invoked
 480:      */
 481:     public function missingAction($actionID)
 482:     {
 483:         throw new CHttpException(404,Yii::t('yii','The system is unable to find the requested action "{action}".',
 484:             array('{action}'=>$actionID==''?$this->defaultAction:$actionID)));
 485:     }
 486: 
 487:     /**
 488:      * @return CAction the action currently being executed, null if no active action.
 489:      */
 490:     public function getAction()
 491:     {
 492:         return $this->_action;
 493:     }
 494: 
 495:     /**
 496:      * @param CAction $value the action currently being executed.
 497:      */
 498:     public function setAction($value)
 499:     {
 500:         $this->_action=$value;
 501:     }
 502: 
 503:     /**
 504:      * @return string ID of the controller
 505:      */
 506:     public function getId()
 507:     {
 508:         return $this->_id;
 509:     }
 510: 
 511:     /**
 512:      * @return string the controller ID that is prefixed with the module ID (if any).
 513:      */
 514:     public function getUniqueId()
 515:     {
 516:         return $this->_module ? $this->_module->getId().'/'.$this->_id : $this->_id;
 517:     }
 518: 
 519:     /**
 520:      * @return string the route (module ID, controller ID and action ID) of the current request.
 521:      * @since 1.1.0
 522:      */
 523:     public function getRoute()
 524:     {
 525:         if(($action=$this->getAction())!==null)
 526:             return $this->getUniqueId().'/'.$action->getId();
 527:         else
 528:             return $this->getUniqueId();
 529:     }
 530: 
 531:     /**
 532:      * @return CWebModule the module that this controller belongs to. It returns null
 533:      * if the controller does not belong to any module
 534:      */
 535:     public function getModule()
 536:     {
 537:         return $this->_module;
 538:     }
 539: 
 540:     /**
 541:      * Returns the directory containing view files for this controller.
 542:      * The default implementation returns 'protected/views/ControllerID'.
 543:      * Child classes may override this method to use customized view path.
 544:      * If the controller belongs to a module, the default view path
 545:      * is the {@link CWebModule::getViewPath module view path} appended with the controller ID.
 546:      * @return string the directory containing the view files for this controller. Defaults to 'protected/views/ControllerID'.
 547:      */
 548:     public function getViewPath()
 549:     {
 550:         if(($module=$this->getModule())===null)
 551:             $module=Yii::app();
 552:         return $module->getViewPath().DIRECTORY_SEPARATOR.$this->getId();
 553:     }
 554: 
 555:     /**
 556:      * Looks for the view file according to the given view name.
 557:      *
 558:      * When a theme is currently active, this method will call {@link CTheme::getViewFile} to determine
 559:      * which view file should be returned.
 560:      *
 561:      * Otherwise, this method will return the corresponding view file based on the following criteria:
 562:      * <ul>
 563:      * <li>absolute view within a module: the view name starts with a single slash '/'.
 564:      * In this case, the view will be searched for under the currently active module's view path.
 565:      * If there is no active module, the view will be searched for under the application's view path.</li>
 566:      * <li>absolute view within the application: the view name starts with double slashes '//'.
 567:      * In this case, the view will be searched for under the application's view path.
 568:      * This syntax has been available since version 1.1.3.</li>
 569:      * <li>aliased view: the view name contains dots and refers to a path alias.
 570:      * The view file is determined by calling {@link YiiBase::getPathOfAlias()}. Note that aliased views
 571:      * cannot be themed because they can refer to a view file located at arbitrary places.</li>
 572:      * <li>relative view: otherwise. Relative views will be searched for under the currently active
 573:      * controller's view path.</li>
 574:      * </ul>
 575:      *
 576:      * After the view file is identified, this method may further call {@link CApplication::findLocalizedFile}
 577:      * to find its localized version if internationalization is needed.
 578:      *
 579:      * @param string $viewName view name
 580:      * @return string the view file path, false if the view file does not exist
 581:      * @see resolveViewFile
 582:      * @see CApplication::findLocalizedFile
 583:      */
 584:     public function getViewFile($viewName)
 585:     {
 586:         if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false)
 587:             return $viewFile;
 588:         $moduleViewPath=$basePath=Yii::app()->getViewPath();
 589:         if(($module=$this->getModule())!==null)
 590:             $moduleViewPath=$module->getViewPath();
 591:         return $this->resolveViewFile($viewName,$this->getViewPath(),$basePath,$moduleViewPath);
 592:     }
 593: 
 594:     /**
 595:      * Looks for the layout view script based on the layout name.
 596:      *
 597:      * The layout name can be specified in one of the following ways:
 598:      *
 599:      * <ul>
 600:      * <li>layout is false: returns false, meaning no layout.</li>
 601:      * <li>layout is null: the currently active module's layout will be used. If there is no active module,
 602:      * the application's layout will be used.</li>
 603:      * <li>a regular view name.</li>
 604:      * </ul>
 605:      *
 606:      * The resolution of the view file based on the layout view is similar to that in {@link getViewFile}.
 607:      * In particular, the following rules are followed:
 608:      *
 609:      * Otherwise, this method will return the corresponding view file based on the following criteria:
 610:      * <ul>
 611:      * <li>When a theme is currently active, this method will call {@link CTheme::getLayoutFile} to determine
 612:      * which view file should be returned.</li>
 613:      * <li>absolute view within a module: the view name starts with a single slash '/'.
 614:      * In this case, the view will be searched for under the currently active module's view path.
 615:      * If there is no active module, the view will be searched for under the application's view path.</li>
 616:      * <li>absolute view within the application: the view name starts with double slashes '//'.
 617:      * In this case, the view will be searched for under the application's view path.
 618:      * This syntax has been available since version 1.1.3.</li>
 619:      * <li>aliased view: the view name contains dots and refers to a path alias.
 620:      * The view file is determined by calling {@link YiiBase::getPathOfAlias()}. Note that aliased views
 621:      * cannot be themed because they can refer to a view file located at arbitrary places.</li>
 622:      * <li>relative view: otherwise. Relative views will be searched for under the currently active
 623:      * module's layout path. In case when there is no active module, the view will be searched for
 624:      * under the application's layout path.</li>
 625:      * </ul>
 626:      *
 627:      * After the view file is identified, this method may further call {@link CApplication::findLocalizedFile}
 628:      * to find its localized version if internationalization is needed.
 629:      *
 630:      * @param mixed $layoutName layout name
 631:      * @return string the view file for the layout. False if the view file cannot be found
 632:      */
 633:     public function getLayoutFile($layoutName)
 634:     {
 635:         if($layoutName===false)
 636:             return false;
 637:         if(($theme=Yii::app()->getTheme())!==null && ($layoutFile=$theme->getLayoutFile($this,$layoutName))!==false)
 638:             return $layoutFile;
 639: 
 640:         if(empty($layoutName))
 641:         {
 642:             $module=$this->getModule();
 643:             while($module!==null)
 644:             {
 645:                 if($module->layout===false)
 646:                     return false;
 647:                 if(!empty($module->layout))
 648:                     break;
 649:                 $module=$module->getParentModule();
 650:             }
 651:             if($module===null)
 652:                 $module=Yii::app();
 653:             $layoutName=$module->layout;
 654:         }
 655:         elseif(($module=$this->getModule())===null)
 656:             $module=Yii::app();
 657: 
 658:         return $this->resolveViewFile($layoutName,$module->getLayoutPath(),Yii::app()->getViewPath(),$module->getViewPath());
 659:     }
 660: 
 661:     /**
 662:      * Finds a view file based on its name.
 663:      * The view name can be in one of the following formats:
 664:      * <ul>
 665:      * <li>absolute view within a module: the view name starts with a single slash '/'.
 666:      * In this case, the view will be searched for under the currently active module's view path.
 667:      * If there is no active module, the view will be searched for under the application's view path.</li>
 668:      * <li>absolute view within the application: the view name starts with double slashes '//'.
 669:      * In this case, the view will be searched for under the application's view path.
 670:      * This syntax has been available since version 1.1.3.</li>
 671:      * <li>aliased view: the view name contains dots and refers to a path alias.
 672:      * The view file is determined by calling {@link YiiBase::getPathOfAlias()}. Note that aliased views
 673:      * cannot be themed because they can refer to a view file located at arbitrary places.</li>
 674:      * <li>relative view: otherwise. Relative views will be searched for under the currently active
 675:      * controller's view path.</li>
 676:      * </ul>
 677:      * For absolute view and relative view, the corresponding view file is a PHP file
 678:      * whose name is the same as the view name. The file is located under a specified directory.
 679:      * This method will call {@link CApplication::findLocalizedFile} to search for a localized file, if any.
 680:      * @param string $viewName the view name
 681:      * @param string $viewPath the directory that is used to search for a relative view name
 682:      * @param string $basePath the directory that is used to search for an absolute view name under the application
 683:      * @param string $moduleViewPath the directory that is used to search for an absolute view name under the current module.
 684:      * If this is not set, the application base view path will be used.
 685:      * @return mixed the view file path. False if the view file does not exist.
 686:      */
 687:     public function resolveViewFile($viewName,$viewPath,$basePath,$moduleViewPath=null)
 688:     {
 689:         if(empty($viewName))
 690:             return false;
 691: 
 692:         if($moduleViewPath===null)
 693:             $moduleViewPath=$basePath;
 694: 
 695:         if(($renderer=Yii::app()->getViewRenderer())!==null)
 696:             $extension=$renderer->fileExtension;
 697:         else
 698:             $extension='.php';
 699:         if($viewName[0]==='/')
 700:         {
 701:             if(strncmp($viewName,'//',2)===0)
 702:                 $viewFile=$basePath.$viewName;
 703:             else
 704:                 $viewFile=$moduleViewPath.$viewName;
 705:         }
 706:         elseif(strpos($viewName,'.'))
 707:             $viewFile=Yii::getPathOfAlias($viewName);
 708:         else
 709:             $viewFile=$viewPath.DIRECTORY_SEPARATOR.$viewName;
 710: 
 711:         if(is_file($viewFile.$extension))
 712:             return Yii::app()->findLocalizedFile($viewFile.$extension);
 713:         elseif($extension!=='.php' && is_file($viewFile.'.php'))
 714:             return Yii::app()->findLocalizedFile($viewFile.'.php');
 715:         else
 716:             return false;
 717:     }
 718: 
 719:     /**
 720:      * Returns the list of clips.
 721:      * A clip is a named piece of rendering result that can be
 722:      * inserted at different places.
 723:      * @return CMap the list of clips
 724:      * @see CClipWidget
 725:      */
 726:     public function getClips()
 727:     {
 728:         if($this->_clips!==null)
 729:             return $this->_clips;
 730:         else
 731:             return $this->_clips=new CMap;
 732:     }
 733: 
 734:     /**
 735:      * Processes the request using another controller action.
 736:      * This is like {@link redirect}, but the user browser's URL remains unchanged.
 737:      * In most cases, you should call {@link redirect} instead of this method.
 738:      * @param string $route the route of the new controller action. This can be an action ID, or a complete route
 739:      * with module ID (optional in the current module), controller ID and action ID. If the former, the action is assumed
 740:      * to be located within the current controller.
 741:      * @param boolean $exit whether to end the application after this call. Defaults to true.
 742:      * @since 1.1.0
 743:      */
 744:     public function forward($route,$exit=true)
 745:     {
 746:         if(strpos($route,'/')===false)
 747:             $this->run($route);
 748:         else
 749:         {
 750:             if($route[0]!=='/' && ($module=$this->getModule())!==null)
 751:                 $route=$module->getId().'/'.$route;
 752:             Yii::app()->runController($route);
 753:         }
 754:         if($exit)
 755:             Yii::app()->end();
 756:     }
 757: 
 758:     /**
 759:      * Renders a view with a layout.
 760:      *
 761:      * This method first calls {@link renderPartial} to render the view (called content view).
 762:      * It then renders the layout view which may embed the content view at appropriate place.
 763:      * In the layout view, the content view rendering result can be accessed via variable
 764:      * <code>$content</code>. At the end, it calls {@link processOutput} to insert scripts
 765:      * and dynamic contents if they are available.
 766:      *
 767:      * By default, the layout view script is "protected/views/layouts/main.php".
 768:      * This may be customized by changing {@link layout}.
 769:      *
 770:      * @param string $view name of the view to be rendered. See {@link getViewFile} for details
 771:      * about how the view script is resolved.
 772:      * @param array $data data to be extracted into PHP variables and made available to the view script
 773:      * @param boolean $return whether the rendering result should be returned instead of being displayed to end users.
 774:      * @return string the rendering result. Null if the rendering result is not required.
 775:      * @see renderPartial
 776:      * @see getLayoutFile
 777:      */
 778:     public function render($view,$data=null,$return=false)
 779:     {
 780:         if($this->beforeRender($view))
 781:         {
 782:             $output=$this->renderPartial($view,$data,true);
 783:             if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
 784:                 $output=$this->renderFile($layoutFile,array('content'=>$output),true);
 785: 
 786:             $this->afterRender($view,$output);
 787: 
 788:             $output=$this->processOutput($output);
 789: 
 790:             if($return)
 791:                 return $output;
 792:             else
 793:                 echo $output;
 794:         }
 795:     }
 796: 
 797:     /**
 798:      * This method is invoked at the beginning of {@link render()}.
 799:      * You may override this method to do some preprocessing when rendering a view.
 800:      * @param string $view the view to be rendered
 801:      * @return boolean whether the view should be rendered.
 802:      * @since 1.1.5
 803:      */
 804:     protected function beforeRender($view)
 805:     {
 806:         return true;
 807:     }
 808: 
 809:     /**
 810:      * This method is invoked after the specified view is rendered by calling {@link render()}.
 811:      * Note that this method is invoked BEFORE {@link processOutput()}.
 812:      * You may override this method to do some postprocessing for the view rendering.
 813:      * @param string $view the view that has been rendered
 814:      * @param string $output the rendering result of the view. Note that this parameter is passed
 815:      * as a reference. That means you can modify it within this method.
 816:      * @since 1.1.5
 817:      */
 818:     protected function afterRender($view, &$output)
 819:     {
 820:     }
 821: 
 822:     /**
 823:      * Renders a static text string.
 824:      * The string will be inserted in the current controller layout and returned back.
 825:      * @param string $text the static text string
 826:      * @param boolean $return whether the rendering result should be returned instead of being displayed to end users.
 827:      * @return string the rendering result. Null if the rendering result is not required.
 828:      * @see getLayoutFile
 829:      */
 830:     public function renderText($text,$return=false)
 831:     {
 832:         if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
 833:             $text=$this->renderFile($layoutFile,array('content'=>$text),true);
 834: 
 835:         $text=$this->processOutput($text);
 836: 
 837:         if($return)
 838:             return $text;
 839:         else
 840:             echo $text;
 841:     }
 842: 
 843:     /**
 844:      * Renders a view.
 845:      *
 846:      * The named view refers to a PHP script (resolved via {@link getViewFile})
 847:      * that is included by this method. If $data is an associative array,
 848:      * it will be extracted as PHP variables and made available to the script.
 849:      *
 850:      * This method differs from {@link render()} in that it does not
 851:      * apply a layout to the rendered result. It is thus mostly used
 852:      * in rendering a partial view, or an AJAX response.
 853:      *
 854:      * @param string $view name of the view to be rendered. See {@link getViewFile} for details
 855:      * about how the view script is resolved.
 856:      * @param array $data data to be extracted into PHP variables and made available to the view script
 857:      * @param boolean $return whether the rendering result should be returned instead of being displayed to end users
 858:      * @param boolean $processOutput whether the rendering result should be postprocessed using {@link processOutput}.
 859:      * @return string the rendering result. Null if the rendering result is not required.
 860:      * @throws CException if the view does not exist
 861:      * @see getViewFile
 862:      * @see processOutput
 863:      * @see render
 864:      */
 865:     public function renderPartial($view,$data=null,$return=false,$processOutput=false)
 866:     {
 867:         if(($viewFile=$this->getViewFile($view))!==false)
 868:         {
 869:             $output=$this->renderFile($viewFile,$data,true);
 870:             if($processOutput)
 871:                 $output=$this->processOutput($output);
 872:             if($return)
 873:                 return $output;
 874:             else
 875:                 echo $output;
 876:         }
 877:         else
 878:             throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
 879:                 array('{controller}'=>get_class($this), '{view}'=>$view)));
 880:     }
 881: 
 882:     /**
 883:      * Renders a named clip with the supplied parameters.
 884:      * This is similar to directly accessing the {@link clips} property.
 885:      * The main difference is that it can take an array of named parameters
 886:      * which will replace the corresponding placeholders in the clip.
 887:      * @param string $name the name of the clip
 888:      * @param array $params an array of named parameters (name=>value) that should replace
 889:      * their corresponding placeholders in the clip
 890:      * @param boolean $return whether to return the clip content or echo it.
 891:      * @return mixed either the clip content or null
 892:      * @since 1.1.8
 893:      */
 894:     public function renderClip($name,$params=array(),$return=false)
 895:     {
 896:         $text=isset($this->clips[$name]) ? strtr($this->clips[$name], $params) : '';
 897: 
 898:         if($return)
 899:             return $text;
 900:         else
 901:             echo $text;
 902:     }
 903: 
 904:     /**
 905:      * Renders dynamic content returned by the specified callback.
 906:      * This method is used together with {@link COutputCache}. Dynamic contents
 907:      * will always show as their latest state even if the content surrounding them is being cached.
 908:      * This is especially useful when caching pages that are mostly static but contain some small
 909:      * dynamic regions, such as username or current time.
 910:      * We can use this method to render these dynamic regions to ensure they are always up-to-date.
 911:      *
 912:      * The first parameter to this method should be a valid PHP callback, while the rest parameters
 913:      * will be passed to the callback.
 914:      *
 915:      * Note, the callback and its parameter values will be serialized and saved in cache.
 916:      * Make sure they are serializable.
 917:      *
 918:      * @param callback $callback a PHP callback which returns the needed dynamic content.
 919:      * When the callback is specified as a string, it will be first assumed to be a method of the current
 920:      * controller class. If the method does not exist, it is assumed to be a global PHP function.
 921:      * Note, the callback should return the dynamic content instead of echoing it.
 922:      */
 923:     public function renderDynamic($callback)
 924:     {
 925:         $n=count($this->_dynamicOutput);
 926:         echo "<###dynamic-$n###>";
 927:         $params=func_get_args();
 928:         array_shift($params);
 929:         $this->renderDynamicInternal($callback,$params);
 930:     }
 931: 
 932:     /**
 933:      * This method is internally used.
 934:      * @param callback $callback a PHP callback which returns the needed dynamic content.
 935:      * @param array $params parameters passed to the PHP callback
 936:      * @see renderDynamic
 937:      */
 938:     public function renderDynamicInternal($callback,$params)
 939:     {
 940:         $this->recordCachingAction('','renderDynamicInternal',array($callback,$params));
 941:         if(is_string($callback) && method_exists($this,$callback))
 942:             $callback=array($this,$callback);
 943:         $this->_dynamicOutput[]=call_user_func_array($callback,$params);
 944:     }
 945: 
 946:     /**
 947:      * Creates a relative URL for the specified action defined in this controller.
 948:      * @param string $route the URL route. This should be in the format of 'ControllerID/ActionID'.
 949:      * If the ControllerID is not present, the current controller ID will be prefixed to the route.
 950:      * If the route is empty, it is assumed to be the current action.
 951:      * If the controller belongs to a module, the {@link CWebModule::getId module ID}
 952:      * will be prefixed to the route. (If you do not want the module ID prefix, the route should start with a slash '/'.)
 953:      * @param array $params additional GET parameters (name=>value). Both the name and value will be URL-encoded.
 954:      * If the name is '#', the corresponding value will be treated as an anchor
 955:      * and will be appended at the end of the URL.
 956:      * @param string $ampersand the token separating name-value pairs in the URL.
 957:      * @return string the constructed URL
 958:      */
 959:     public function createUrl($route,$params=array(),$ampersand='&')
 960:     {
 961:         if($route==='')
 962:             $route=$this->getId().'/'.$this->getAction()->getId();
 963:         elseif(strpos($route,'/')===false)
 964:             $route=$this->getId().'/'.$route;
 965:         if($route[0]!=='/' && ($module=$this->getModule())!==null)
 966:             $route=$module->getId().'/'.$route;
 967:         return Yii::app()->createUrl(trim($route,'/'),$params,$ampersand);
 968:     }
 969: 
 970:     /**
 971:      * Creates an absolute URL for the specified action defined in this controller.
 972:      * @param string $route the URL route. This should be in the format of 'ControllerID/ActionID'.
 973:      * If the ControllerPath is not present, the current controller ID will be prefixed to the route.
 974:      * If the route is empty, it is assumed to be the current action.
 975:      * @param array $params additional GET parameters (name=>value). Both the name and value will be URL-encoded.
 976:      * @param string $schema schema to use (e.g. http, https). If empty, the schema used for the current request will be used.
 977:      * @param string $ampersand the token separating name-value pairs in the URL.
 978:      * @return string the constructed URL
 979:      */
 980:     public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
 981:     {
 982:         $url=$this->createUrl($route,$params,$ampersand);
 983:         if(strpos($url,'http')===0)
 984:             return $url;
 985:         else
 986:             return Yii::app()->getRequest()->getHostInfo($schema).$url;
 987:     }
 988: 
 989:     /**
 990:      * @return string the page title. Defaults to the controller name and the action name.
 991:      */
 992:     public function getPageTitle()
 993:     {
 994:         if($this->_pageTitle!==null)
 995:             return $this->_pageTitle;
 996:         else
 997:         {
 998:             $name=ucfirst(basename($this->getId()));
 999:             if($this->getAction()!==null && strcasecmp($this->getAction()->getId(),$this->defaultAction))
1000:                 return $this->_pageTitle=Yii::app()->name.' - '.ucfirst($this->getAction()->getId()).' '.$name;
1001:             else
1002:                 return $this->_pageTitle=Yii::app()->name.' - '.$name;
1003:         }
1004:     }
1005: 
1006:     /**
1007:      * @param string $value the page title.
1008:      */
1009:     public function setPageTitle($value)
1010:     {
1011:         $this->_pageTitle=$value;
1012:     }
1013: 
1014:     /**
1015:      * Redirects the browser to the specified URL or route (controller/action).
1016:      * @param mixed $url the URL to be redirected to. If the parameter is an array,
1017:      * the first element must be a route to a controller action and the rest
1018:      * are GET parameters in name-value pairs.
1019:      * @param boolean $terminate whether to terminate the current application after calling this method. Defaults to true.
1020:      * @param integer $statusCode the HTTP status code. Defaults to 302. See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html}
1021:      * for details about HTTP status code.
1022:      */
1023:     public function redirect($url,$terminate=true,$statusCode=302)
1024:     {
1025:         if(is_array($url))
1026:         {
1027:             $route=isset($url[0]) ? $url[0] : '';
1028:             $url=$this->createUrl($route,array_splice($url,1));
1029:         }
1030:         Yii::app()->getRequest()->redirect($url,$terminate,$statusCode);
1031:     }
1032: 
1033:     /**
1034:      * Refreshes the current page.
1035:      * The effect of this method call is the same as user pressing the
1036:      * refresh button on the browser (without post data).
1037:      * @param boolean $terminate whether to terminate the current application after calling this method
1038:      * @param string $anchor the anchor that should be appended to the redirection URL.
1039:      * Defaults to empty. Make sure the anchor starts with '#' if you want to specify it.
1040:      */
1041:     public function refresh($terminate=true,$anchor='')
1042:     {
1043:         $this->redirect(Yii::app()->getRequest()->getUrl().$anchor,$terminate);
1044:     }
1045: 
1046:     /**
1047:      * Records a method call when an output cache is in effect.
1048:      * When the content is served from the output cache, the recorded
1049:      * method will be re-invoked.
1050:      * @param string $context a property name of the controller. It refers to an object
1051:      * whose method is being called. If empty it means the controller itself.
1052:      * @param string $method the method name
1053:      * @param array $params parameters passed to the method
1054:      * @see COutputCache
1055:      */
1056:     public function recordCachingAction($context,$method,$params)
1057:     {
1058:         if($this->_cachingStack) // record only when there is an active output cache
1059:         {
1060:             foreach($this->_cachingStack as $cache)
1061:                 $cache->recordAction($context,$method,$params);
1062:         }
1063:     }
1064: 
1065:     /**
1066:      * @param boolean $createIfNull whether to create a stack if it does not exist yet. Defaults to true.
1067:      * @return CStack stack of {@link COutputCache} objects
1068:      */
1069:     public function getCachingStack($createIfNull=true)
1070:     {
1071:         if(!$this->_cachingStack)
1072:             $this->_cachingStack=new CStack;
1073:         return $this->_cachingStack;
1074:     }
1075: 
1076:     /**
1077:      * Returns whether the caching stack is empty.
1078:      * @return boolean whether the caching stack is empty. If not empty, it means currently there are
1079:      * some output cache in effect. Note, the return result of this method may change when it is
1080:      * called in different output regions, depending on the partition of output caches.
1081:      */
1082:     public function isCachingStackEmpty()
1083:     {
1084:         return $this->_cachingStack===null || !$this->_cachingStack->getCount();
1085:     }
1086: 
1087:     /**
1088:      * This method is invoked right before an action is to be executed (after all possible filters.)
1089:      * You may override this method to do last-minute preparation for the action.
1090:      * @param CAction $action the action to be executed.
1091:      * @return boolean whether the action should be executed.
1092:      */
1093:     protected function beforeAction($action)
1094:     {
1095:         return true;
1096:     }
1097: 
1098:     /**
1099:      * This method is invoked right after an action is executed.
1100:      * You may override this method to do some postprocessing for the action.
1101:      * @param CAction $action the action just executed.
1102:      */
1103:     protected function afterAction($action)
1104:     {
1105:     }
1106: 
1107:     /**
1108:      * The filter method for 'postOnly' filter.
1109:      * This filter throws an exception (CHttpException with code 400) if the applied action is receiving a non-POST request.
1110:      * @param CFilterChain $filterChain the filter chain that the filter is on.
1111:      * @throws CHttpException if the current request is not a POST request
1112:      */
1113:     public function filterPostOnly($filterChain)
1114:     {
1115:         if(Yii::app()->getRequest()->getIsPostRequest())
1116:             $filterChain->run();
1117:         else
1118:             throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
1119:     }
1120: 
1121:     /**
1122:      * The filter method for 'ajaxOnly' filter.
1123:      * This filter throws an exception (CHttpException with code 400) if the applied action is receiving a non-AJAX request.
1124:      * @param CFilterChain $filterChain the filter chain that the filter is on.
1125:      * @throws CHttpException if the current request is not an AJAX request.
1126:      */
1127:     public function filterAjaxOnly($filterChain)
1128:     {
1129:         if(Yii::app()->getRequest()->getIsAjaxRequest())
1130:             $filterChain->run();
1131:         else
1132:             throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
1133:     }
1134: 
1135:     /**
1136:      * The filter method for 'accessControl' filter.
1137:      * This filter is a wrapper of {@link CAccessControlFilter}.
1138:      * To use this filter, you must override {@link accessRules} method.
1139:      * @param CFilterChain $filterChain the filter chain that the filter is on.
1140:      */
1141:     public function filterAccessControl($filterChain)
1142:     {
1143:         $filter=new CAccessControlFilter;
1144:         $filter->setRules($this->accessRules());
1145:         $filter->filter($filterChain);
1146:     }
1147: 
1148:     /**
1149:      * Returns a persistent page state value.
1150:      * A page state is a variable that is persistent across POST requests of the same page.
1151:      * In order to use persistent page states, the form(s) must be stateful
1152:      * which are generated using {@link CHtml::statefulForm}.
1153:      * @param string $name the state name
1154:      * @param mixed $defaultValue the value to be returned if the named state is not found
1155:      * @return mixed the page state value
1156:      * @see setPageState
1157:      * @see CHtml::statefulForm
1158:      */
1159:     public function getPageState($name,$defaultValue=null)
1160:     {
1161:         if($this->_pageStates===null)
1162:             $this->_pageStates=$this->loadPageStates();
1163:         return isset($this->_pageStates[$name])?$this->_pageStates[$name]:$defaultValue;
1164:     }
1165: 
1166:     /**
1167:      * Saves a persistent page state value.
1168:      * A page state is a variable that is persistent across POST requests of the same page.
1169:      * In order to use persistent page states, the form(s) must be stateful
1170:      * which are generated using {@link CHtml::statefulForm}.
1171:      * @param string $name the state name
1172:      * @param mixed $value the page state value
1173:      * @param mixed $defaultValue the default page state value. If this is the same as
1174:      * the given value, the state will be removed from persistent storage.
1175:      * @see getPageState
1176:      * @see CHtml::statefulForm
1177:      */
1178:     public function setPageState($name,$value,$defaultValue=null)
1179:     {
1180:         if($this->_pageStates===null)
1181:             $this->_pageStates=$this->loadPageStates();
1182:         if($value===$defaultValue)
1183:             unset($this->_pageStates[$name]);
1184:         else
1185:             $this->_pageStates[$name]=$value;
1186: 
1187:         $params=func_get_args();
1188:         $this->recordCachingAction('','setPageState',$params);
1189:     }
1190: 
1191:     /**
1192:      * Removes all page states.
1193:      */
1194:     public function clearPageStates()
1195:     {
1196:         $this->_pageStates=array();
1197:     }
1198: 
1199:     /**
1200:      * Loads page states from a hidden input.
1201:      * @return array the loaded page states
1202:      */
1203:     protected function loadPageStates()
1204:     {
1205:         if(!empty($_POST[self::STATE_INPUT_NAME]))
1206:         {
1207:             if(($data=base64_decode($_POST[self::STATE_INPUT_NAME]))!==false)
1208:             {
1209:                 if(extension_loaded('zlib'))
1210:                     $data=@gzuncompress($data);
1211:                 if(($data=Yii::app()->getSecurityManager()->validateData($data))!==false)
1212:                     return unserialize($data);
1213:             }
1214:         }
1215:         return array();
1216:     }
1217: 
1218:     /**
1219:      * Saves page states as a base64 string.
1220:      * @param array $states the states to be saved.
1221:      * @param string $output the output to be modified. Note, this is passed by reference.
1222:      */
1223:     protected function savePageStates($states,&$output)
1224:     {
1225:         $data=Yii::app()->getSecurityManager()->hashData(serialize($states));
1226:         if(extension_loaded('zlib'))
1227:             $data=gzcompress($data);
1228:         $value=base64_encode($data);
1229:         $output=str_replace(CHtml::pageStateField(''),CHtml::pageStateField($value),$output);
1230:     }
1231: }
1232: 
API documentation generated by ApiGen 2.8.0