1232 lines
45 KiB
PHP
1232 lines
45 KiB
PHP
<?php
|
|
/**
|
|
* CController class file.
|
|
*
|
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
|
* @link http://www.yiiframework.com/
|
|
* @copyright 2008-2013 Yii Software LLC
|
|
* @license http://www.yiiframework.com/license/
|
|
*/
|
|
|
|
|
|
/**
|
|
* CController manages a set of actions which deal with the corresponding user requests.
|
|
*
|
|
* Through the actions, CController coordinates the data flow between models and views.
|
|
*
|
|
* When a user requests an action 'XYZ', CController will do one of the following:
|
|
* 1. Method-based action: call method 'actionXYZ' if it exists;
|
|
* 2. Class-based action: create an instance of class 'XYZ' if the class is found in the action class map
|
|
* (specified via {@link actions()}, and execute the action;
|
|
* 3. Call {@link missingAction()}, which by default will raise a 404 HTTP exception.
|
|
*
|
|
* If the user does not specify an action, CController will run the action specified by
|
|
* {@link defaultAction}, instead.
|
|
*
|
|
* CController may be configured to execute filters before and after running actions.
|
|
* Filters preprocess/postprocess the user request/response and may quit executing actions
|
|
* if needed. They are executed in the order they are specified. If during the execution,
|
|
* any of the filters returns true, the rest filters and the action will no longer get executed.
|
|
*
|
|
* Filters can be individual objects, or methods defined in the controller class.
|
|
* They are specified by overriding {@link filters()} method. The following is an example
|
|
* of the filter specification:
|
|
* <pre>
|
|
* array(
|
|
* 'accessControl - login',
|
|
* 'ajaxOnly + search',
|
|
* array(
|
|
* 'COutputCache + list',
|
|
* 'duration'=>300,
|
|
* ),
|
|
* )
|
|
* </pre>
|
|
* The above example declares three filters: accessControl, ajaxOnly, COutputCache. The first two
|
|
* are method-based filters (defined in CController), which refer to filtering methods in the controller class;
|
|
* while the last refers to an object-based filter whose class is 'system.web.widgets.COutputCache' and
|
|
* the 'duration' property is initialized as 300 (s).
|
|
*
|
|
* For method-based filters, a method named 'filterXYZ($filterChain)' in the controller class
|
|
* will be executed, where 'XYZ' stands for the filter name as specified in {@link filters()}.
|
|
* Note, inside the filter method, you must call <code>$filterChain->run()</code> if the action should
|
|
* be executed. Otherwise, the filtering process would stop at this filter.
|
|
*
|
|
* Filters can be specified so that they are executed only when running certain actions.
|
|
* For method-based filters, this is done by using '+' and '-' operators in the filter specification.
|
|
* The '+' operator means the filter runs only when the specified actions are requested;
|
|
* while the '-' operator means the filter runs only when the requested action is not among those actions.
|
|
* For object-based filters, the '+' and '-' operators are following the class name.
|
|
*
|
|
* @property array $actionParams The request parameters to be used for action parameter binding.
|
|
* @property CAction $action The action currently being executed, null if no active action.
|
|
* @property string $id ID of the controller.
|
|
* @property string $uniqueId The controller ID that is prefixed with the module ID (if any).
|
|
* @property string $route The route (module ID, controller ID and action ID) of the current request.
|
|
* @property CWebModule $module The module that this controller belongs to. It returns null
|
|
* if the controller does not belong to any module.
|
|
* @property string $viewPath The directory containing the view files for this controller. Defaults to 'protected/views/ControllerID'.
|
|
* @property CMap $clips The list of clips.
|
|
* @property string $pageTitle The page title. Defaults to the controller name and the action name.
|
|
* @property CStack $cachingStack Stack of {@link COutputCache} objects.
|
|
*
|
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
|
* @package system.web
|
|
* @since 1.0
|
|
*/
|
|
class CController extends CBaseController
|
|
{
|
|
/**
|
|
* Name of the hidden field storing persistent page states.
|
|
*/
|
|
const STATE_INPUT_NAME='YII_PAGE_STATE';
|
|
|
|
/**
|
|
* @var mixed the name of the layout to be applied to this controller's views.
|
|
* Defaults to null, meaning the {@link CWebApplication::layout application layout}
|
|
* is used. If it is false, no layout will be applied.
|
|
* The {@link CWebModule::layout module layout} will be used
|
|
* if the controller belongs to a module and this layout property is null.
|
|
*/
|
|
public $layout;
|
|
/**
|
|
* @var string the name of the default action. Defaults to 'index'.
|
|
*/
|
|
public $defaultAction='index';
|
|
|
|
private $_id;
|
|
private $_action;
|
|
private $_pageTitle;
|
|
private $_cachingStack;
|
|
private $_clips;
|
|
private $_dynamicOutput;
|
|
private $_pageStates;
|
|
private $_module;
|
|
|
|
|
|
/**
|
|
* @param string $id id of this controller
|
|
* @param CWebModule $module the module that this controller belongs to.
|
|
*/
|
|
public function __construct($id,$module=null)
|
|
{
|
|
$this->_id=$id;
|
|
$this->_module=$module;
|
|
$this->attachBehaviors($this->behaviors());
|
|
}
|
|
|
|
/**
|
|
* Initializes the controller.
|
|
* This method is called by the application before the controller starts to execute.
|
|
* You may override this method to perform the needed initialization for the controller.
|
|
*/
|
|
public function init()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Returns the filter configurations.
|
|
*
|
|
* By overriding this method, child classes can specify filters to be applied to actions.
|
|
*
|
|
* This method returns an array of filter specifications. Each array element specify a single filter.
|
|
*
|
|
* For a method-based filter (called inline filter), it is specified as 'FilterName[ +|- Action1, Action2, ...]',
|
|
* where the '+' ('-') operators describe which actions should be (should not be) applied with the filter.
|
|
*
|
|
* For a class-based filter, it is specified as an array like the following:
|
|
* <pre>
|
|
* array(
|
|
* 'FilterClass[ +|- Action1, Action2, ...]',
|
|
* 'name1'=>'value1',
|
|
* 'name2'=>'value2',
|
|
* ...
|
|
* )
|
|
* </pre>
|
|
* where the name-value pairs will be used to initialize the properties of the filter.
|
|
*
|
|
* Note, in order to inherit filters defined in the parent class, a child class needs to
|
|
* merge the parent filters with child filters using functions like array_merge().
|
|
*
|
|
* @return array a list of filter configurations.
|
|
* @see CFilter
|
|
*/
|
|
public function filters()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Returns a list of external action classes.
|
|
* Array keys are action IDs, and array values are the corresponding
|
|
* action class in dot syntax (e.g. 'edit'=>'application.controllers.article.EditArticle')
|
|
* or arrays representing the configuration of the actions, such as the following,
|
|
* <pre>
|
|
* return array(
|
|
* 'action1'=>'path.to.Action1Class',
|
|
* 'action2'=>array(
|
|
* 'class'=>'path.to.Action2Class',
|
|
* 'property1'=>'value1',
|
|
* 'property2'=>'value2',
|
|
* ),
|
|
* );
|
|
* </pre>
|
|
* Derived classes may override this method to declare external actions.
|
|
*
|
|
* Note, in order to inherit actions defined in the parent class, a child class needs to
|
|
* merge the parent actions with child actions using functions like array_merge().
|
|
*
|
|
* You may import actions from an action provider
|
|
* (such as a widget, see {@link CWidget::actions}), like the following:
|
|
* <pre>
|
|
* return array(
|
|
* ...other actions...
|
|
* // import actions declared in ProviderClass::actions()
|
|
* // the action IDs will be prefixed with 'pro.'
|
|
* 'pro.'=>'path.to.ProviderClass',
|
|
* // similar as above except that the imported actions are
|
|
* // configured with the specified initial property values
|
|
* 'pro2.'=>array(
|
|
* 'class'=>'path.to.ProviderClass',
|
|
* 'action1'=>array(
|
|
* 'property1'=>'value1',
|
|
* ),
|
|
* 'action2'=>array(
|
|
* 'property2'=>'value2',
|
|
* ),
|
|
* ),
|
|
* )
|
|
* </pre>
|
|
*
|
|
* In the above, we differentiate action providers from other action
|
|
* declarations by the array keys. For action providers, the array keys
|
|
* must contain a dot. As a result, an action ID 'pro2.action1' will
|
|
* be resolved as the 'action1' action declared in the 'ProviderClass'.
|
|
*
|
|
* @return array list of external action classes
|
|
* @see createAction
|
|
*/
|
|
public function actions()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Returns a list of behaviors that this controller should behave as.
|
|
* The return value should be an array of behavior configurations indexed by
|
|
* behavior names. Each behavior configuration can be either a string specifying
|
|
* the behavior class or an array of the following structure:
|
|
* <pre>
|
|
* 'behaviorName'=>array(
|
|
* 'class'=>'path.to.BehaviorClass',
|
|
* 'property1'=>'value1',
|
|
* 'property2'=>'value2',
|
|
* )
|
|
* </pre>
|
|
*
|
|
* Note, the behavior classes must implement {@link IBehavior} or extend from
|
|
* {@link CBehavior}. Behaviors declared in this method will be attached
|
|
* to the controller when it is instantiated.
|
|
*
|
|
* For more details about behaviors, see {@link CComponent}.
|
|
* @return array the behavior configurations (behavior name=>behavior configuration)
|
|
*/
|
|
public function behaviors()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Returns the access rules for this controller.
|
|
* Override this method if you use the {@link filterAccessControl accessControl} filter.
|
|
* @return array list of access rules. See {@link CAccessControlFilter} for details about rule specification.
|
|
*/
|
|
public function accessRules()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Runs the named action.
|
|
* Filters specified via {@link filters()} will be applied.
|
|
* @param string $actionID action ID
|
|
* @throws CHttpException if the action does not exist or the action name is not proper.
|
|
* @see filters
|
|
* @see createAction
|
|
* @see runAction
|
|
*/
|
|
public function run($actionID)
|
|
{
|
|
if(($action=$this->createAction($actionID))!==null)
|
|
{
|
|
if(($parent=$this->getModule())===null)
|
|
$parent=Yii::app();
|
|
if($parent->beforeControllerAction($this,$action))
|
|
{
|
|
$this->runActionWithFilters($action,$this->filters());
|
|
$parent->afterControllerAction($this,$action);
|
|
}
|
|
}
|
|
else
|
|
$this->missingAction($actionID);
|
|
}
|
|
|
|
/**
|
|
* Runs an action with the specified filters.
|
|
* A filter chain will be created based on the specified filters
|
|
* and the action will be executed then.
|
|
* @param CAction $action the action to be executed.
|
|
* @param array $filters list of filters to be applied to the action.
|
|
* @see filters
|
|
* @see createAction
|
|
* @see runAction
|
|
*/
|
|
public function runActionWithFilters($action,$filters)
|
|
{
|
|
if(empty($filters))
|
|
$this->runAction($action);
|
|
else
|
|
{
|
|
$priorAction=$this->_action;
|
|
$this->_action=$action;
|
|
CFilterChain::create($this,$action,$filters)->run();
|
|
$this->_action=$priorAction;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Runs the action after passing through all filters.
|
|
* This method is invoked by {@link runActionWithFilters} after all possible filters have been executed
|
|
* and the action starts to run.
|
|
* @param CAction $action action to run
|
|
*/
|
|
public function runAction($action)
|
|
{
|
|
$priorAction=$this->_action;
|
|
$this->_action=$action;
|
|
if($this->beforeAction($action))
|
|
{
|
|
if($action->runWithParams($this->getActionParams())===false)
|
|
$this->invalidActionParams($action);
|
|
else
|
|
$this->afterAction($action);
|
|
}
|
|
$this->_action=$priorAction;
|
|
}
|
|
|
|
/**
|
|
* Returns the request parameters that will be used for action parameter binding.
|
|
* By default, this method will return $_GET. You may override this method if you
|
|
* want to use other request parameters (e.g. $_GET+$_POST).
|
|
* @return array the request parameters to be used for action parameter binding
|
|
* @since 1.1.7
|
|
*/
|
|
public function getActionParams()
|
|
{
|
|
return $_GET;
|
|
}
|
|
|
|
/**
|
|
* This method is invoked when the request parameters do not satisfy the requirement of the specified action.
|
|
* The default implementation will throw a 400 HTTP exception.
|
|
* @param CAction $action the action being executed
|
|
* @since 1.1.7
|
|
*/
|
|
public function invalidActionParams($action)
|
|
{
|
|
throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
|
|
}
|
|
|
|
/**
|
|
* Postprocesses the output generated by {@link render()}.
|
|
* This method is invoked at the end of {@link render()} and {@link renderText()}.
|
|
* If there are registered client scripts, this method will insert them into the output
|
|
* at appropriate places. If there are dynamic contents, they will also be inserted.
|
|
* This method may also save the persistent page states in hidden fields of
|
|
* stateful forms in the page.
|
|
* @param string $output the output generated by the current action
|
|
* @return string the output that has been processed.
|
|
*/
|
|
public function processOutput($output)
|
|
{
|
|
Yii::app()->getClientScript()->render($output);
|
|
|
|
// if using page caching, we should delay dynamic output replacement
|
|
if($this->_dynamicOutput!==null && $this->isCachingStackEmpty())
|
|
{
|
|
$output=$this->processDynamicOutput($output);
|
|
$this->_dynamicOutput=null;
|
|
}
|
|
|
|
if($this->_pageStates===null)
|
|
$this->_pageStates=$this->loadPageStates();
|
|
if(!empty($this->_pageStates))
|
|
$this->savePageStates($this->_pageStates,$output);
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Postprocesses the dynamic output.
|
|
* This method is internally used. Do not call this method directly.
|
|
* @param string $output output to be processed
|
|
* @return string the processed output
|
|
*/
|
|
public function processDynamicOutput($output)
|
|
{
|
|
if($this->_dynamicOutput)
|
|
{
|
|
$output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output);
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Replaces the dynamic content placeholders with actual content.
|
|
* This is a callback function used internally.
|
|
* @param array $matches matches
|
|
* @return string the replacement
|
|
* @see processOutput
|
|
*/
|
|
protected function replaceDynamicOutput($matches)
|
|
{
|
|
$content=$matches[0];
|
|
if(isset($this->_dynamicOutput[$matches[1]]))
|
|
{
|
|
$content=$this->_dynamicOutput[$matches[1]];
|
|
$this->_dynamicOutput[$matches[1]]=null;
|
|
}
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Creates the action instance based on the action name.
|
|
* The action can be either an inline action or an object.
|
|
* The latter is created by looking up the action map specified in {@link actions}.
|
|
* @param string $actionID ID of the action. If empty, the {@link defaultAction default action} will be used.
|
|
* @return CAction the action instance, null if the action does not exist.
|
|
* @see actions
|
|
*/
|
|
public function createAction($actionID)
|
|
{
|
|
if($actionID==='')
|
|
$actionID=$this->defaultAction;
|
|
if(method_exists($this,'action'.$actionID) && strcasecmp($actionID,'s')) // we have actions method
|
|
return new CInlineAction($this,$actionID);
|
|
else
|
|
{
|
|
$action=$this->createActionFromMap($this->actions(),$actionID,$actionID);
|
|
if($action!==null && !method_exists($action,'run'))
|
|
throw new CException(Yii::t('yii', 'Action class {class} must implement the "run" method.', array('{class}'=>get_class($action))));
|
|
return $action;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates the action instance based on the action map.
|
|
* This method will check to see if the action ID appears in the given
|
|
* action map. If so, the corresponding configuration will be used to
|
|
* create the action instance.
|
|
* @param array $actionMap the action map
|
|
* @param string $actionID the action ID that has its prefix stripped off
|
|
* @param string $requestActionID the originally requested action ID
|
|
* @param array $config the action configuration that should be applied on top of the configuration specified in the map
|
|
* @return CAction the action instance, null if the action does not exist.
|
|
*/
|
|
protected function createActionFromMap($actionMap,$actionID,$requestActionID,$config=array())
|
|
{
|
|
if(($pos=strpos($actionID,'.'))===false && isset($actionMap[$actionID]))
|
|
{
|
|
$baseConfig=is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class'=>$actionMap[$actionID]);
|
|
return Yii::createComponent(empty($config)?$baseConfig:array_merge($baseConfig,$config),$this,$requestActionID);
|
|
}
|
|
elseif($pos===false)
|
|
return null;
|
|
|
|
// the action is defined in a provider
|
|
$prefix=substr($actionID,0,$pos+1);
|
|
if(!isset($actionMap[$prefix]))
|
|
return null;
|
|
$actionID=(string)substr($actionID,$pos+1);
|
|
|
|
$provider=$actionMap[$prefix];
|
|
if(is_string($provider))
|
|
$providerType=$provider;
|
|
elseif(is_array($provider) && isset($provider['class']))
|
|
{
|
|
$providerType=$provider['class'];
|
|
if(isset($provider[$actionID]))
|
|
{
|
|
if(is_string($provider[$actionID]))
|
|
$config=array_merge(array('class'=>$provider[$actionID]),$config);
|
|
else
|
|
$config=array_merge($provider[$actionID],$config);
|
|
}
|
|
}
|
|
else
|
|
throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
|
|
|
|
$class=Yii::import($providerType,true);
|
|
$map=call_user_func(array($class,'actions'));
|
|
|
|
return $this->createActionFromMap($map,$actionID,$requestActionID,$config);
|
|
}
|
|
|
|
/**
|
|
* Handles the request whose action is not recognized.
|
|
* This method is invoked when the controller cannot find the requested action.
|
|
* The default implementation simply throws an exception.
|
|
* @param string $actionID the missing action name
|
|
* @throws CHttpException whenever this method is invoked
|
|
*/
|
|
public function missingAction($actionID)
|
|
{
|
|
throw new CHttpException(404,Yii::t('yii','The system is unable to find the requested action "{action}".',
|
|
array('{action}'=>$actionID==''?$this->defaultAction:$actionID)));
|
|
}
|
|
|
|
/**
|
|
* @return CAction the action currently being executed, null if no active action.
|
|
*/
|
|
public function getAction()
|
|
{
|
|
return $this->_action;
|
|
}
|
|
|
|
/**
|
|
* @param CAction $value the action currently being executed.
|
|
*/
|
|
public function setAction($value)
|
|
{
|
|
$this->_action=$value;
|
|
}
|
|
|
|
/**
|
|
* @return string ID of the controller
|
|
*/
|
|
public function getId()
|
|
{
|
|
return $this->_id;
|
|
}
|
|
|
|
/**
|
|
* @return string the controller ID that is prefixed with the module ID (if any).
|
|
*/
|
|
public function getUniqueId()
|
|
{
|
|
return $this->_module ? $this->_module->getId().'/'.$this->_id : $this->_id;
|
|
}
|
|
|
|
/**
|
|
* @return string the route (module ID, controller ID and action ID) of the current request.
|
|
* @since 1.1.0
|
|
*/
|
|
public function getRoute()
|
|
{
|
|
if(($action=$this->getAction())!==null)
|
|
return $this->getUniqueId().'/'.$action->getId();
|
|
else
|
|
return $this->getUniqueId();
|
|
}
|
|
|
|
/**
|
|
* @return CWebModule the module that this controller belongs to. It returns null
|
|
* if the controller does not belong to any module
|
|
*/
|
|
public function getModule()
|
|
{
|
|
return $this->_module;
|
|
}
|
|
|
|
/**
|
|
* Returns the directory containing view files for this controller.
|
|
* The default implementation returns 'protected/views/ControllerID'.
|
|
* Child classes may override this method to use customized view path.
|
|
* If the controller belongs to a module, the default view path
|
|
* is the {@link CWebModule::getViewPath module view path} appended with the controller ID.
|
|
* @return string the directory containing the view files for this controller. Defaults to 'protected/views/ControllerID'.
|
|
*/
|
|
public function getViewPath()
|
|
{
|
|
if(($module=$this->getModule())===null)
|
|
$module=Yii::app();
|
|
return $module->getViewPath().DIRECTORY_SEPARATOR.$this->getId();
|
|
}
|
|
|
|
/**
|
|
* Looks for the view file according to the given view name.
|
|
*
|
|
* When a theme is currently active, this method will call {@link CTheme::getViewFile} to determine
|
|
* which view file should be returned.
|
|
*
|
|
* Otherwise, this method will return the corresponding view file based on the following criteria:
|
|
* <ul>
|
|
* <li>absolute view within a module: the view name starts with a single slash '/'.
|
|
* In this case, the view will be searched for under the currently active module's view path.
|
|
* If there is no active module, the view will be searched for under the application's view path.</li>
|
|
* <li>absolute view within the application: the view name starts with double slashes '//'.
|
|
* In this case, the view will be searched for under the application's view path.
|
|
* This syntax has been available since version 1.1.3.</li>
|
|
* <li>aliased view: the view name contains dots and refers to a path alias.
|
|
* The view file is determined by calling {@link YiiBase::getPathOfAlias()}. Note that aliased views
|
|
* cannot be themed because they can refer to a view file located at arbitrary places.</li>
|
|
* <li>relative view: otherwise. Relative views will be searched for under the currently active
|
|
* controller's view path.</li>
|
|
* </ul>
|
|
*
|
|
* After the view file is identified, this method may further call {@link CApplication::findLocalizedFile}
|
|
* to find its localized version if internationalization is needed.
|
|
*
|
|
* @param string $viewName view name
|
|
* @return string the view file path, false if the view file does not exist
|
|
* @see resolveViewFile
|
|
* @see CApplication::findLocalizedFile
|
|
*/
|
|
public function getViewFile($viewName)
|
|
{
|
|
if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false)
|
|
return $viewFile;
|
|
$moduleViewPath=$basePath=Yii::app()->getViewPath();
|
|
if(($module=$this->getModule())!==null)
|
|
$moduleViewPath=$module->getViewPath();
|
|
return $this->resolveViewFile($viewName,$this->getViewPath(),$basePath,$moduleViewPath);
|
|
}
|
|
|
|
/**
|
|
* Looks for the layout view script based on the layout name.
|
|
*
|
|
* The layout name can be specified in one of the following ways:
|
|
*
|
|
* <ul>
|
|
* <li>layout is false: returns false, meaning no layout.</li>
|
|
* <li>layout is null: the currently active module's layout will be used. If there is no active module,
|
|
* the application's layout will be used.</li>
|
|
* <li>a regular view name.</li>
|
|
* </ul>
|
|
*
|
|
* The resolution of the view file based on the layout view is similar to that in {@link getViewFile}.
|
|
* In particular, the following rules are followed:
|
|
*
|
|
* Otherwise, this method will return the corresponding view file based on the following criteria:
|
|
* <ul>
|
|
* <li>When a theme is currently active, this method will call {@link CTheme::getLayoutFile} to determine
|
|
* which view file should be returned.</li>
|
|
* <li>absolute view within a module: the view name starts with a single slash '/'.
|
|
* In this case, the view will be searched for under the currently active module's view path.
|
|
* If there is no active module, the view will be searched for under the application's view path.</li>
|
|
* <li>absolute view within the application: the view name starts with double slashes '//'.
|
|
* In this case, the view will be searched for under the application's view path.
|
|
* This syntax has been available since version 1.1.3.</li>
|
|
* <li>aliased view: the view name contains dots and refers to a path alias.
|
|
* The view file is determined by calling {@link YiiBase::getPathOfAlias()}. Note that aliased views
|
|
* cannot be themed because they can refer to a view file located at arbitrary places.</li>
|
|
* <li>relative view: otherwise. Relative views will be searched for under the currently active
|
|
* module's layout path. In case when there is no active module, the view will be searched for
|
|
* under the application's layout path.</li>
|
|
* </ul>
|
|
*
|
|
* After the view file is identified, this method may further call {@link CApplication::findLocalizedFile}
|
|
* to find its localized version if internationalization is needed.
|
|
*
|
|
* @param mixed $layoutName layout name
|
|
* @return string the view file for the layout. False if the view file cannot be found
|
|
*/
|
|
public function getLayoutFile($layoutName)
|
|
{
|
|
if($layoutName===false)
|
|
return false;
|
|
if(($theme=Yii::app()->getTheme())!==null && ($layoutFile=$theme->getLayoutFile($this,$layoutName))!==false)
|
|
return $layoutFile;
|
|
|
|
if(empty($layoutName))
|
|
{
|
|
$module=$this->getModule();
|
|
while($module!==null)
|
|
{
|
|
if($module->layout===false)
|
|
return false;
|
|
if(!empty($module->layout))
|
|
break;
|
|
$module=$module->getParentModule();
|
|
}
|
|
if($module===null)
|
|
$module=Yii::app();
|
|
$layoutName=$module->layout;
|
|
}
|
|
elseif(($module=$this->getModule())===null)
|
|
$module=Yii::app();
|
|
|
|
return $this->resolveViewFile($layoutName,$module->getLayoutPath(),Yii::app()->getViewPath(),$module->getViewPath());
|
|
}
|
|
|
|
/**
|
|
* Finds a view file based on its name.
|
|
* The view name can be in one of the following formats:
|
|
* <ul>
|
|
* <li>absolute view within a module: the view name starts with a single slash '/'.
|
|
* In this case, the view will be searched for under the currently active module's view path.
|
|
* If there is no active module, the view will be searched for under the application's view path.</li>
|
|
* <li>absolute view within the application: the view name starts with double slashes '//'.
|
|
* In this case, the view will be searched for under the application's view path.
|
|
* This syntax has been available since version 1.1.3.</li>
|
|
* <li>aliased view: the view name contains dots and refers to a path alias.
|
|
* The view file is determined by calling {@link YiiBase::getPathOfAlias()}. Note that aliased views
|
|
* cannot be themed because they can refer to a view file located at arbitrary places.</li>
|
|
* <li>relative view: otherwise. Relative views will be searched for under the currently active
|
|
* controller's view path.</li>
|
|
* </ul>
|
|
* For absolute view and relative view, the corresponding view file is a PHP file
|
|
* whose name is the same as the view name. The file is located under a specified directory.
|
|
* This method will call {@link CApplication::findLocalizedFile} to search for a localized file, if any.
|
|
* @param string $viewName the view name
|
|
* @param string $viewPath the directory that is used to search for a relative view name
|
|
* @param string $basePath the directory that is used to search for an absolute view name under the application
|
|
* @param string $moduleViewPath the directory that is used to search for an absolute view name under the current module.
|
|
* If this is not set, the application base view path will be used.
|
|
* @return mixed the view file path. False if the view file does not exist.
|
|
*/
|
|
public function resolveViewFile($viewName,$viewPath,$basePath,$moduleViewPath=null)
|
|
{
|
|
if(empty($viewName))
|
|
return false;
|
|
|
|
if($moduleViewPath===null)
|
|
$moduleViewPath=$basePath;
|
|
|
|
if(($renderer=Yii::app()->getViewRenderer())!==null)
|
|
$extension=$renderer->fileExtension;
|
|
else
|
|
$extension='.php';
|
|
if($viewName[0]==='/')
|
|
{
|
|
if(strncmp($viewName,'//',2)===0)
|
|
$viewFile=$basePath.$viewName;
|
|
else
|
|
$viewFile=$moduleViewPath.$viewName;
|
|
}
|
|
elseif(strpos($viewName,'.'))
|
|
$viewFile=Yii::getPathOfAlias($viewName);
|
|
else
|
|
$viewFile=$viewPath.DIRECTORY_SEPARATOR.$viewName;
|
|
|
|
if(is_file($viewFile.$extension))
|
|
return Yii::app()->findLocalizedFile($viewFile.$extension);
|
|
elseif($extension!=='.php' && is_file($viewFile.'.php'))
|
|
return Yii::app()->findLocalizedFile($viewFile.'.php');
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the list of clips.
|
|
* A clip is a named piece of rendering result that can be
|
|
* inserted at different places.
|
|
* @return CMap the list of clips
|
|
* @see CClipWidget
|
|
*/
|
|
public function getClips()
|
|
{
|
|
if($this->_clips!==null)
|
|
return $this->_clips;
|
|
else
|
|
return $this->_clips=new CMap;
|
|
}
|
|
|
|
/**
|
|
* Processes the request using another controller action.
|
|
* This is like {@link redirect}, but the user browser's URL remains unchanged.
|
|
* In most cases, you should call {@link redirect} instead of this method.
|
|
* @param string $route the route of the new controller action. This can be an action ID, or a complete route
|
|
* with module ID (optional in the current module), controller ID and action ID. If the former, the action is assumed
|
|
* to be located within the current controller.
|
|
* @param boolean $exit whether to end the application after this call. Defaults to true.
|
|
* @since 1.1.0
|
|
*/
|
|
public function forward($route,$exit=true)
|
|
{
|
|
if(strpos($route,'/')===false)
|
|
$this->run($route);
|
|
else
|
|
{
|
|
if($route[0]!=='/' && ($module=$this->getModule())!==null)
|
|
$route=$module->getId().'/'.$route;
|
|
Yii::app()->runController($route);
|
|
}
|
|
if($exit)
|
|
Yii::app()->end();
|
|
}
|
|
|
|
/**
|
|
* Renders a view with a layout.
|
|
*
|
|
* This method first calls {@link renderPartial} to render the view (called content view).
|
|
* It then renders the layout view which may embed the content view at appropriate place.
|
|
* In the layout view, the content view rendering result can be accessed via variable
|
|
* <code>$content</code>. At the end, it calls {@link processOutput} to insert scripts
|
|
* and dynamic contents if they are available.
|
|
*
|
|
* By default, the layout view script is "protected/views/layouts/main.php".
|
|
* This may be customized by changing {@link layout}.
|
|
*
|
|
* @param string $view name of the view to be rendered. See {@link getViewFile} for details
|
|
* about how the view script is resolved.
|
|
* @param array $data data to be extracted into PHP variables and made available to the view script
|
|
* @param boolean $return whether the rendering result should be returned instead of being displayed to end users.
|
|
* @return string the rendering result. Null if the rendering result is not required.
|
|
* @see renderPartial
|
|
* @see getLayoutFile
|
|
*/
|
|
public function render($view,$data=null,$return=false)
|
|
{
|
|
if($this->beforeRender($view))
|
|
{
|
|
$output=$this->renderPartial($view,$data,true);
|
|
if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
|
|
$output=$this->renderFile($layoutFile,array('content'=>$output),true);
|
|
|
|
$this->afterRender($view,$output);
|
|
|
|
$output=$this->processOutput($output);
|
|
|
|
if($return)
|
|
return $output;
|
|
else
|
|
echo $output;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method is invoked at the beginning of {@link render()}.
|
|
* You may override this method to do some preprocessing when rendering a view.
|
|
* @param string $view the view to be rendered
|
|
* @return boolean whether the view should be rendered.
|
|
* @since 1.1.5
|
|
*/
|
|
protected function beforeRender($view)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This method is invoked after the specified view is rendered by calling {@link render()}.
|
|
* Note that this method is invoked BEFORE {@link processOutput()}.
|
|
* You may override this method to do some postprocessing for the view rendering.
|
|
* @param string $view the view that has been rendered
|
|
* @param string $output the rendering result of the view. Note that this parameter is passed
|
|
* as a reference. That means you can modify it within this method.
|
|
* @since 1.1.5
|
|
*/
|
|
protected function afterRender($view, &$output)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Renders a static text string.
|
|
* The string will be inserted in the current controller layout and returned back.
|
|
* @param string $text the static text string
|
|
* @param boolean $return whether the rendering result should be returned instead of being displayed to end users.
|
|
* @return string the rendering result. Null if the rendering result is not required.
|
|
* @see getLayoutFile
|
|
*/
|
|
public function renderText($text,$return=false)
|
|
{
|
|
if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
|
|
$text=$this->renderFile($layoutFile,array('content'=>$text),true);
|
|
|
|
$text=$this->processOutput($text);
|
|
|
|
if($return)
|
|
return $text;
|
|
else
|
|
echo $text;
|
|
}
|
|
|
|
/**
|
|
* Renders a view.
|
|
*
|
|
* The named view refers to a PHP script (resolved via {@link getViewFile})
|
|
* that is included by this method. If $data is an associative array,
|
|
* it will be extracted as PHP variables and made available to the script.
|
|
*
|
|
* This method differs from {@link render()} in that it does not
|
|
* apply a layout to the rendered result. It is thus mostly used
|
|
* in rendering a partial view, or an AJAX response.
|
|
*
|
|
* @param string $view name of the view to be rendered. See {@link getViewFile} for details
|
|
* about how the view script is resolved.
|
|
* @param array $data data to be extracted into PHP variables and made available to the view script
|
|
* @param boolean $return whether the rendering result should be returned instead of being displayed to end users
|
|
* @param boolean $processOutput whether the rendering result should be postprocessed using {@link processOutput}.
|
|
* @return string the rendering result. Null if the rendering result is not required.
|
|
* @throws CException if the view does not exist
|
|
* @see getViewFile
|
|
* @see processOutput
|
|
* @see render
|
|
*/
|
|
public function renderPartial($view,$data=null,$return=false,$processOutput=false)
|
|
{
|
|
if(($viewFile=$this->getViewFile($view))!==false)
|
|
{
|
|
$output=$this->renderFile($viewFile,$data,true);
|
|
if($processOutput)
|
|
$output=$this->processOutput($output);
|
|
if($return)
|
|
return $output;
|
|
else
|
|
echo $output;
|
|
}
|
|
else
|
|
throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
|
|
array('{controller}'=>get_class($this), '{view}'=>$view)));
|
|
}
|
|
|
|
/**
|
|
* Renders a named clip with the supplied parameters.
|
|
* This is similar to directly accessing the {@link clips} property.
|
|
* The main difference is that it can take an array of named parameters
|
|
* which will replace the corresponding placeholders in the clip.
|
|
* @param string $name the name of the clip
|
|
* @param array $params an array of named parameters (name=>value) that should replace
|
|
* their corresponding placeholders in the clip
|
|
* @param boolean $return whether to return the clip content or echo it.
|
|
* @return mixed either the clip content or null
|
|
* @since 1.1.8
|
|
*/
|
|
public function renderClip($name,$params=array(),$return=false)
|
|
{
|
|
$text=isset($this->clips[$name]) ? strtr($this->clips[$name], $params) : '';
|
|
|
|
if($return)
|
|
return $text;
|
|
else
|
|
echo $text;
|
|
}
|
|
|
|
/**
|
|
* Renders dynamic content returned by the specified callback.
|
|
* This method is used together with {@link COutputCache}. Dynamic contents
|
|
* will always show as their latest state even if the content surrounding them is being cached.
|
|
* This is especially useful when caching pages that are mostly static but contain some small
|
|
* dynamic regions, such as username or current time.
|
|
* We can use this method to render these dynamic regions to ensure they are always up-to-date.
|
|
*
|
|
* The first parameter to this method should be a valid PHP callback, while the rest parameters
|
|
* will be passed to the callback.
|
|
*
|
|
* Note, the callback and its parameter values will be serialized and saved in cache.
|
|
* Make sure they are serializable.
|
|
*
|
|
* @param callback $callback a PHP callback which returns the needed dynamic content.
|
|
* When the callback is specified as a string, it will be first assumed to be a method of the current
|
|
* controller class. If the method does not exist, it is assumed to be a global PHP function.
|
|
* Note, the callback should return the dynamic content instead of echoing it.
|
|
*/
|
|
public function renderDynamic($callback)
|
|
{
|
|
$n=count($this->_dynamicOutput);
|
|
echo "<###dynamic-$n###>";
|
|
$params=func_get_args();
|
|
array_shift($params);
|
|
$this->renderDynamicInternal($callback,$params);
|
|
}
|
|
|
|
/**
|
|
* This method is internally used.
|
|
* @param callback $callback a PHP callback which returns the needed dynamic content.
|
|
* @param array $params parameters passed to the PHP callback
|
|
* @see renderDynamic
|
|
*/
|
|
public function renderDynamicInternal($callback,$params)
|
|
{
|
|
$this->recordCachingAction('','renderDynamicInternal',array($callback,$params));
|
|
if(is_string($callback) && method_exists($this,$callback))
|
|
$callback=array($this,$callback);
|
|
$this->_dynamicOutput[]=call_user_func_array($callback,$params);
|
|
}
|
|
|
|
/**
|
|
* Creates a relative URL for the specified action defined in this controller.
|
|
* @param string $route the URL route. This should be in the format of 'ControllerID/ActionID'.
|
|
* If the ControllerID is not present, the current controller ID will be prefixed to the route.
|
|
* If the route is empty, it is assumed to be the current action.
|
|
* If the controller belongs to a module, the {@link CWebModule::getId module ID}
|
|
* will be prefixed to the route. (If you do not want the module ID prefix, the route should start with a slash '/'.)
|
|
* @param array $params additional GET parameters (name=>value). Both the name and value will be URL-encoded.
|
|
* If the name is '#', the corresponding value will be treated as an anchor
|
|
* and will be appended at the end of the URL.
|
|
* @param string $ampersand the token separating name-value pairs in the URL.
|
|
* @return string the constructed URL
|
|
*/
|
|
public function createUrl($route,$params=array(),$ampersand='&')
|
|
{
|
|
if($route==='')
|
|
$route=$this->getId().'/'.$this->getAction()->getId();
|
|
elseif(strpos($route,'/')===false)
|
|
$route=$this->getId().'/'.$route;
|
|
if($route[0]!=='/' && ($module=$this->getModule())!==null)
|
|
$route=$module->getId().'/'.$route;
|
|
return Yii::app()->createUrl(trim($route,'/'),$params,$ampersand);
|
|
}
|
|
|
|
/**
|
|
* Creates an absolute URL for the specified action defined in this controller.
|
|
* @param string $route the URL route. This should be in the format of 'ControllerID/ActionID'.
|
|
* If the ControllerPath is not present, the current controller ID will be prefixed to the route.
|
|
* If the route is empty, it is assumed to be the current action.
|
|
* @param array $params additional GET parameters (name=>value). Both the name and value will be URL-encoded.
|
|
* @param string $schema schema to use (e.g. http, https). If empty, the schema used for the current request will be used.
|
|
* @param string $ampersand the token separating name-value pairs in the URL.
|
|
* @return string the constructed URL
|
|
*/
|
|
public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
|
|
{
|
|
$url=$this->createUrl($route,$params,$ampersand);
|
|
if(strpos($url,'http')===0)
|
|
return $url;
|
|
else
|
|
return Yii::app()->getRequest()->getHostInfo($schema).$url;
|
|
}
|
|
|
|
/**
|
|
* @return string the page title. Defaults to the controller name and the action name.
|
|
*/
|
|
public function getPageTitle()
|
|
{
|
|
if($this->_pageTitle!==null)
|
|
return $this->_pageTitle;
|
|
else
|
|
{
|
|
$name=ucfirst(basename($this->getId()));
|
|
if($this->getAction()!==null && strcasecmp($this->getAction()->getId(),$this->defaultAction))
|
|
return $this->_pageTitle=Yii::app()->name.' - '.ucfirst($this->getAction()->getId()).' '.$name;
|
|
else
|
|
return $this->_pageTitle=Yii::app()->name.' - '.$name;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $value the page title.
|
|
*/
|
|
public function setPageTitle($value)
|
|
{
|
|
$this->_pageTitle=$value;
|
|
}
|
|
|
|
/**
|
|
* Redirects the browser to the specified URL or route (controller/action).
|
|
* @param mixed $url the URL to be redirected to. If the parameter is an array,
|
|
* the first element must be a route to a controller action and the rest
|
|
* are GET parameters in name-value pairs.
|
|
* @param boolean $terminate whether to terminate the current application after calling this method. Defaults to true.
|
|
* @param integer $statusCode the HTTP status code. Defaults to 302. See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html}
|
|
* for details about HTTP status code.
|
|
*/
|
|
public function redirect($url,$terminate=true,$statusCode=302)
|
|
{
|
|
if(is_array($url))
|
|
{
|
|
$route=isset($url[0]) ? $url[0] : '';
|
|
$url=$this->createUrl($route,array_splice($url,1));
|
|
}
|
|
Yii::app()->getRequest()->redirect($url,$terminate,$statusCode);
|
|
}
|
|
|
|
/**
|
|
* Refreshes the current page.
|
|
* The effect of this method call is the same as user pressing the
|
|
* refresh button on the browser (without post data).
|
|
* @param boolean $terminate whether to terminate the current application after calling this method
|
|
* @param string $anchor the anchor that should be appended to the redirection URL.
|
|
* Defaults to empty. Make sure the anchor starts with '#' if you want to specify it.
|
|
*/
|
|
public function refresh($terminate=true,$anchor='')
|
|
{
|
|
$this->redirect(Yii::app()->getRequest()->getUrl().$anchor,$terminate);
|
|
}
|
|
|
|
/**
|
|
* Records a method call when an output cache is in effect.
|
|
* When the content is served from the output cache, the recorded
|
|
* method will be re-invoked.
|
|
* @param string $context a property name of the controller. It refers to an object
|
|
* whose method is being called. If empty it means the controller itself.
|
|
* @param string $method the method name
|
|
* @param array $params parameters passed to the method
|
|
* @see COutputCache
|
|
*/
|
|
public function recordCachingAction($context,$method,$params)
|
|
{
|
|
if($this->_cachingStack) // record only when there is an active output cache
|
|
{
|
|
foreach($this->_cachingStack as $cache)
|
|
$cache->recordAction($context,$method,$params);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param boolean $createIfNull whether to create a stack if it does not exist yet. Defaults to true.
|
|
* @return CStack stack of {@link COutputCache} objects
|
|
*/
|
|
public function getCachingStack($createIfNull=true)
|
|
{
|
|
if(!$this->_cachingStack)
|
|
$this->_cachingStack=new CStack;
|
|
return $this->_cachingStack;
|
|
}
|
|
|
|
/**
|
|
* Returns whether the caching stack is empty.
|
|
* @return boolean whether the caching stack is empty. If not empty, it means currently there are
|
|
* some output cache in effect. Note, the return result of this method may change when it is
|
|
* called in different output regions, depending on the partition of output caches.
|
|
*/
|
|
public function isCachingStackEmpty()
|
|
{
|
|
return $this->_cachingStack===null || !$this->_cachingStack->getCount();
|
|
}
|
|
|
|
/**
|
|
* This method is invoked right before an action is to be executed (after all possible filters.)
|
|
* You may override this method to do last-minute preparation for the action.
|
|
* @param CAction $action the action to be executed.
|
|
* @return boolean whether the action should be executed.
|
|
*/
|
|
protected function beforeAction($action)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This method is invoked right after an action is executed.
|
|
* You may override this method to do some postprocessing for the action.
|
|
* @param CAction $action the action just executed.
|
|
*/
|
|
protected function afterAction($action)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* The filter method for 'postOnly' filter.
|
|
* This filter throws an exception (CHttpException with code 400) if the applied action is receiving a non-POST request.
|
|
* @param CFilterChain $filterChain the filter chain that the filter is on.
|
|
* @throws CHttpException if the current request is not a POST request
|
|
*/
|
|
public function filterPostOnly($filterChain)
|
|
{
|
|
if(Yii::app()->getRequest()->getIsPostRequest())
|
|
$filterChain->run();
|
|
else
|
|
throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
|
|
}
|
|
|
|
/**
|
|
* The filter method for 'ajaxOnly' filter.
|
|
* This filter throws an exception (CHttpException with code 400) if the applied action is receiving a non-AJAX request.
|
|
* @param CFilterChain $filterChain the filter chain that the filter is on.
|
|
* @throws CHttpException if the current request is not an AJAX request.
|
|
*/
|
|
public function filterAjaxOnly($filterChain)
|
|
{
|
|
if(Yii::app()->getRequest()->getIsAjaxRequest())
|
|
$filterChain->run();
|
|
else
|
|
throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
|
|
}
|
|
|
|
/**
|
|
* The filter method for 'accessControl' filter.
|
|
* This filter is a wrapper of {@link CAccessControlFilter}.
|
|
* To use this filter, you must override {@link accessRules} method.
|
|
* @param CFilterChain $filterChain the filter chain that the filter is on.
|
|
*/
|
|
public function filterAccessControl($filterChain)
|
|
{
|
|
$filter=new CAccessControlFilter;
|
|
$filter->setRules($this->accessRules());
|
|
$filter->filter($filterChain);
|
|
}
|
|
|
|
/**
|
|
* Returns a persistent page state value.
|
|
* A page state is a variable that is persistent across POST requests of the same page.
|
|
* In order to use persistent page states, the form(s) must be stateful
|
|
* which are generated using {@link CHtml::statefulForm}.
|
|
* @param string $name the state name
|
|
* @param mixed $defaultValue the value to be returned if the named state is not found
|
|
* @return mixed the page state value
|
|
* @see setPageState
|
|
* @see CHtml::statefulForm
|
|
*/
|
|
public function getPageState($name,$defaultValue=null)
|
|
{
|
|
if($this->_pageStates===null)
|
|
$this->_pageStates=$this->loadPageStates();
|
|
return isset($this->_pageStates[$name])?$this->_pageStates[$name]:$defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Saves a persistent page state value.
|
|
* A page state is a variable that is persistent across POST requests of the same page.
|
|
* In order to use persistent page states, the form(s) must be stateful
|
|
* which are generated using {@link CHtml::statefulForm}.
|
|
* @param string $name the state name
|
|
* @param mixed $value the page state value
|
|
* @param mixed $defaultValue the default page state value. If this is the same as
|
|
* the given value, the state will be removed from persistent storage.
|
|
* @see getPageState
|
|
* @see CHtml::statefulForm
|
|
*/
|
|
public function setPageState($name,$value,$defaultValue=null)
|
|
{
|
|
if($this->_pageStates===null)
|
|
$this->_pageStates=$this->loadPageStates();
|
|
if($value===$defaultValue)
|
|
unset($this->_pageStates[$name]);
|
|
else
|
|
$this->_pageStates[$name]=$value;
|
|
|
|
$params=func_get_args();
|
|
$this->recordCachingAction('','setPageState',$params);
|
|
}
|
|
|
|
/**
|
|
* Removes all page states.
|
|
*/
|
|
public function clearPageStates()
|
|
{
|
|
$this->_pageStates=array();
|
|
}
|
|
|
|
/**
|
|
* Loads page states from a hidden input.
|
|
* @return array the loaded page states
|
|
*/
|
|
protected function loadPageStates()
|
|
{
|
|
if(!empty($_POST[self::STATE_INPUT_NAME]))
|
|
{
|
|
if(($data=base64_decode($_POST[self::STATE_INPUT_NAME]))!==false)
|
|
{
|
|
if(extension_loaded('zlib'))
|
|
$data=@gzuncompress($data);
|
|
if(($data=Yii::app()->getSecurityManager()->validateData($data))!==false)
|
|
return unserialize($data);
|
|
}
|
|
}
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Saves page states as a base64 string.
|
|
* @param array $states the states to be saved.
|
|
* @param string $output the output to be modified. Note, this is passed by reference.
|
|
*/
|
|
protected function savePageStates($states,&$output)
|
|
{
|
|
$data=Yii::app()->getSecurityManager()->hashData(serialize($states));
|
|
if(extension_loaded('zlib'))
|
|
$data=gzcompress($data);
|
|
$value=base64_encode($data);
|
|
$output=str_replace(CHtml::pageStateField(''),CHtml::pageStateField($value),$output);
|
|
}
|
|
}
|