303 lines
10 KiB
PHP
303 lines
10 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* CBaseController 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/
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* CBaseController is the base class for {@link CController} and {@link CWidget}.
|
||
|
*
|
||
|
* It provides the common functionalities shared by controllers who need to render views.
|
||
|
*
|
||
|
* CBaseController also implements the support for the following features:
|
||
|
* <ul>
|
||
|
* <li>{@link CClipWidget Clips} : a clip is a piece of captured output that can be inserted elsewhere.</li>
|
||
|
* <li>{@link CWidget Widgets} : a widget is a self-contained sub-controller with its own view and model.</li>
|
||
|
* <li>{@link COutputCache Fragment cache} : fragment cache selectively caches a portion of the output.</li>
|
||
|
* </ul>
|
||
|
*
|
||
|
* To use a widget in a view, use the following in the view:
|
||
|
* <pre>
|
||
|
* $this->widget('path.to.widgetClass',array('property1'=>'value1',...));
|
||
|
* </pre>
|
||
|
* or
|
||
|
* <pre>
|
||
|
* $this->beginWidget('path.to.widgetClass',array('property1'=>'value1',...));
|
||
|
* // ... display other contents here
|
||
|
* $this->endWidget();
|
||
|
* </pre>
|
||
|
*
|
||
|
* To create a clip, use the following:
|
||
|
* <pre>
|
||
|
* $this->beginClip('clipID');
|
||
|
* // ... display the clip contents
|
||
|
* $this->endClip();
|
||
|
* </pre>
|
||
|
* Then, in a different view or place, the captured clip can be inserted as:
|
||
|
* <pre>
|
||
|
* echo $this->clips['clipID'];
|
||
|
* </pre>
|
||
|
*
|
||
|
* Note that $this in the code above refers to current controller so, for example,
|
||
|
* if you need to access clip from a widget where $this refers to widget itself
|
||
|
* you need to do it the following way:
|
||
|
*
|
||
|
* <pre>
|
||
|
* echo $this->getController()->clips['clipID'];
|
||
|
* </pre>
|
||
|
*
|
||
|
* To use fragment cache, do as follows,
|
||
|
* <pre>
|
||
|
* if($this->beginCache('cacheID',array('property1'=>'value1',...))
|
||
|
* {
|
||
|
* // ... display the content to be cached here
|
||
|
* $this->endCache();
|
||
|
* }
|
||
|
* </pre>
|
||
|
*
|
||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||
|
* @package system.web
|
||
|
* @since 1.0
|
||
|
*/
|
||
|
abstract class CBaseController extends CComponent
|
||
|
{
|
||
|
private $_widgetStack=array();
|
||
|
|
||
|
/**
|
||
|
* Returns the view script file according to the specified view name.
|
||
|
* This method must be implemented by child classes.
|
||
|
* @param string $viewName view name
|
||
|
* @return string the file path for the named view. False if the view cannot be found.
|
||
|
*/
|
||
|
abstract public function getViewFile($viewName);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Renders a view file.
|
||
|
*
|
||
|
* @param string $viewFile view file path
|
||
|
* @param array $data data to be extracted and made available to the view
|
||
|
* @param boolean $return whether the rendering result should be returned instead of being echoed
|
||
|
* @return string the rendering result. Null if the rendering result is not required.
|
||
|
* @throws CException if the view file does not exist
|
||
|
*/
|
||
|
public function renderFile($viewFile,$data=null,$return=false)
|
||
|
{
|
||
|
$widgetCount=count($this->_widgetStack);
|
||
|
if(($renderer=Yii::app()->getViewRenderer())!==null && $renderer->fileExtension==='.'.CFileHelper::getExtension($viewFile))
|
||
|
$content=$renderer->renderFile($this,$viewFile,$data,$return);
|
||
|
else
|
||
|
$content=$this->renderInternal($viewFile,$data,$return);
|
||
|
if(count($this->_widgetStack)===$widgetCount)
|
||
|
return $content;
|
||
|
else
|
||
|
{
|
||
|
$widget=end($this->_widgetStack);
|
||
|
throw new CException(Yii::t('yii','{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.',
|
||
|
array('{controller}'=>get_class($this), '{view}'=>$viewFile, '{widget}'=>get_class($widget))));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Renders a view file.
|
||
|
* This method includes the view file as a PHP script
|
||
|
* and captures the display result if required.
|
||
|
* @param string $_viewFile_ view file
|
||
|
* @param array $_data_ data to be extracted and made available to the view file
|
||
|
* @param boolean $_return_ whether the rendering result should be returned as a string
|
||
|
* @return string the rendering result. Null if the rendering result is not required.
|
||
|
*/
|
||
|
public function renderInternal($_viewFile_,$_data_=null,$_return_=false)
|
||
|
{
|
||
|
// we use special variable names here to avoid conflict when extracting data
|
||
|
if(is_array($_data_))
|
||
|
extract($_data_,EXTR_PREFIX_SAME,'data');
|
||
|
else
|
||
|
$data=$_data_;
|
||
|
if($_return_)
|
||
|
{
|
||
|
ob_start();
|
||
|
ob_implicit_flush(false);
|
||
|
require($_viewFile_);
|
||
|
return ob_get_clean();
|
||
|
}
|
||
|
else
|
||
|
require($_viewFile_);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a widget and initializes it.
|
||
|
* This method first creates the specified widget instance.
|
||
|
* It then configures the widget's properties with the given initial values.
|
||
|
* At the end it calls {@link CWidget::init} to initialize the widget.
|
||
|
* Starting from version 1.1, if a {@link CWidgetFactory widget factory} is enabled,
|
||
|
* this method will use the factory to create the widget, instead.
|
||
|
* @param string $className class name (can be in path alias format)
|
||
|
* @param array $properties initial property values
|
||
|
* @return CWidget the fully initialized widget instance.
|
||
|
*/
|
||
|
public function createWidget($className,$properties=array())
|
||
|
{
|
||
|
$widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
|
||
|
$widget->init();
|
||
|
return $widget;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a widget and executes it.
|
||
|
* @param string $className the widget class name or class in dot syntax (e.g. application.widgets.MyWidget)
|
||
|
* @param array $properties list of initial property values for the widget (Property Name => Property Value)
|
||
|
* @param boolean $captureOutput whether to capture the output of the widget. If true, the method will capture
|
||
|
* and return the output generated by the widget. If false, the output will be directly sent for display
|
||
|
* and the widget object will be returned. This parameter is available since version 1.1.2.
|
||
|
* @return mixed the widget instance when $captureOutput is false, or the widget output when $captureOutput is true.
|
||
|
*/
|
||
|
public function widget($className,$properties=array(),$captureOutput=false)
|
||
|
{
|
||
|
if($captureOutput)
|
||
|
{
|
||
|
ob_start();
|
||
|
ob_implicit_flush(false);
|
||
|
$widget=$this->createWidget($className,$properties);
|
||
|
$widget->run();
|
||
|
return ob_get_clean();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
$widget=$this->createWidget($className,$properties);
|
||
|
$widget->run();
|
||
|
return $widget;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a widget and executes it.
|
||
|
* This method is similar to {@link widget()} except that it is expecting
|
||
|
* a {@link endWidget()} call to end the execution.
|
||
|
* @param string $className the widget class name or class in dot syntax (e.g. application.widgets.MyWidget)
|
||
|
* @param array $properties list of initial property values for the widget (Property Name => Property Value)
|
||
|
* @return CWidget the widget created to run
|
||
|
* @see endWidget
|
||
|
*/
|
||
|
public function beginWidget($className,$properties=array())
|
||
|
{
|
||
|
$widget=$this->createWidget($className,$properties);
|
||
|
$this->_widgetStack[]=$widget;
|
||
|
return $widget;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ends the execution of the named widget.
|
||
|
* This method is used together with {@link beginWidget()}.
|
||
|
* @param string $id optional tag identifying the method call for debugging purpose.
|
||
|
* @return CWidget the widget just ended running
|
||
|
* @throws CException if an extra endWidget call is made
|
||
|
* @see beginWidget
|
||
|
*/
|
||
|
public function endWidget($id='')
|
||
|
{
|
||
|
if(($widget=array_pop($this->_widgetStack))!==null)
|
||
|
{
|
||
|
$widget->run();
|
||
|
return $widget;
|
||
|
}
|
||
|
else
|
||
|
throw new CException(Yii::t('yii','{controller} has an extra endWidget({id}) call in its view.',
|
||
|
array('{controller}'=>get_class($this),'{id}'=>$id)));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Begins recording a clip.
|
||
|
* This method is a shortcut to beginning {@link CClipWidget}.
|
||
|
* @param string $id the clip ID.
|
||
|
* @param array $properties initial property values for {@link CClipWidget}.
|
||
|
*/
|
||
|
public function beginClip($id,$properties=array())
|
||
|
{
|
||
|
$properties['id']=$id;
|
||
|
$this->beginWidget('CClipWidget',$properties);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ends recording a clip.
|
||
|
* This method is an alias to {@link endWidget}.
|
||
|
*/
|
||
|
public function endClip()
|
||
|
{
|
||
|
$this->endWidget('CClipWidget');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Begins fragment caching.
|
||
|
* This method will display cached content if it is availabe.
|
||
|
* If not, it will start caching and would expect a {@link endCache()}
|
||
|
* call to end the cache and save the content into cache.
|
||
|
* A typical usage of fragment caching is as follows,
|
||
|
* <pre>
|
||
|
* if($this->beginCache($id))
|
||
|
* {
|
||
|
* // ...generate content here
|
||
|
* $this->endCache();
|
||
|
* }
|
||
|
* </pre>
|
||
|
* @param string $id a unique ID identifying the fragment to be cached.
|
||
|
* @param array $properties initial property values for {@link COutputCache}.
|
||
|
* @return boolean whether we need to generate content for caching. False if cached version is available.
|
||
|
* @see endCache
|
||
|
*/
|
||
|
public function beginCache($id,$properties=array())
|
||
|
{
|
||
|
$properties['id']=$id;
|
||
|
$cache=$this->beginWidget('COutputCache',$properties);
|
||
|
if($cache->getIsContentCached())
|
||
|
{
|
||
|
$this->endCache();
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ends fragment caching.
|
||
|
* This is an alias to {@link endWidget}.
|
||
|
* @see beginCache
|
||
|
*/
|
||
|
public function endCache()
|
||
|
{
|
||
|
$this->endWidget('COutputCache');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Begins the rendering of content that is to be decorated by the specified view.
|
||
|
* @param mixed $view the name of the view that will be used to decorate the content. The actual view script
|
||
|
* is resolved via {@link getViewFile}. If this parameter is null (default),
|
||
|
* the default layout will be used as the decorative view.
|
||
|
* Note that if the current controller does not belong to
|
||
|
* any module, the default layout refers to the application's {@link CWebApplication::layout default layout};
|
||
|
* If the controller belongs to a module, the default layout refers to the module's
|
||
|
* {@link CWebModule::layout default layout}.
|
||
|
* @param array $data the variables (name=>value) to be extracted and made available in the decorative view.
|
||
|
* @see endContent
|
||
|
* @see CContentDecorator
|
||
|
*/
|
||
|
public function beginContent($view=null,$data=array())
|
||
|
{
|
||
|
$this->beginWidget('CContentDecorator',array('view'=>$view, 'data'=>$data));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ends the rendering of content.
|
||
|
* @see beginContent
|
||
|
*/
|
||
|
public function endContent()
|
||
|
{
|
||
|
$this->endWidget('CContentDecorator');
|
||
|
}
|
||
|
}
|