diff options
Diffstat (limited to 'framework/web/CWidgetFactory.php')
| -rw-r--r-- | framework/web/CWidgetFactory.php | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/framework/web/CWidgetFactory.php b/framework/web/CWidgetFactory.php new file mode 100644 index 0000000..9c94b68 --- /dev/null +++ b/framework/web/CWidgetFactory.php @@ -0,0 +1,198 @@ +<?php +/** + * CWidgetFactory class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + + +/** + * CWidgetFactory creates new widgets to be used in views. + * + * CWidgetFactory is used as the default "widgetFactory" application component. + * + * When calling {@link CBaseController::createWidget}, {@link CBaseController::widget} + * or {@link CBaseController::beginWidget}, if the "widgetFactory" component is installed, + * it will be used to create the requested widget. To install the "widgetFactory" component, + * we should have the following application configuration: + * <pre> + * return array( + * 'components'=>array( + * 'widgetFactory'=>array( + * 'class'=>'CWidgetFactory', + * ), + * ), + * ) + * </pre> + * + * CWidgetFactory implements the "skin" feature, which allows a new widget to be created + * and initialized with a set of predefined property values (called skin). + * + * When CWidgetFactory is used to create a new widget, it will first instantiate the + * widget instance. It then checks if there is a skin available for this widget + * according to the widget class name and the widget {@link CWidget::skin} property. + * If a skin is found, it will be merged with the initial properties passed via + * {@link createWidget}. Then the merged initial properties will be used to initialize + * the newly created widget instance. + * + * As aforementioned, a skin is a set of initial property values for a widget. + * It is thus represented as an associative array of name-value pairs. + * Skins are stored in PHP scripts like other configurations. Each script file stores the skins + * for a particular widget type and is named as the widget class name (e.g. CLinkPager.php). + * Each widget type may have one or several skins, identified by the skin name set via + * {@link CWidget::skin} property. If the {@link CWidget::skin} property is not set for a given + * widget, it means the default skin would be used. The following shows the possible skins for + * the {@link CLinkPager} widget: + * <pre> + * return array( + * 'default'=>array( + * 'nextPageLabel'=>'>>', + * 'prevPageLabel'=>'<<', + * ), + * 'short'=>array( + * 'header'=>'', + * 'maxButtonCount'=>5, + * ), + * ); + * </pre> + * In the above, there are two skins. The first one is the default skin which is indexed by the string "default". + * Note that {@link CWidget::skin} defaults to "default". Therefore, this is the skin that will be applied + * if we do not explicitly specify the {@link CWidget::skin} property. + * The second one is named as the "short" skin which will be used only when we set {@link CWidget::skin} + * to be "short". + * + * By default, CWidgetFactory looks for the skin of a widget under the "skins" directory + * of the current application's {@link CWebApplication::viewPath} (e.g. protected/views/skins). + * If a theme is being used, it will look for the skin under the "skins" directory of + * the theme's {@link CTheme::viewPath} (as well as the aforementioned skin directory). + * In case the specified skin is not found, a widget will still be created + * normally without causing any error. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CWidgetFactory.php 3421 2011-10-20 21:23:38Z alexander.makarow $ + * @package system.web + * @since 1.1 + */ +class CWidgetFactory extends CApplicationComponent implements IWidgetFactory +{ + /** + * @var boolean whether to enable widget skinning. Defaults to false. + * @see skinnableWidgets + * @since 1.1.3 + */ + public $enableSkin=false; + /** + * @var array widget initial property values. Each array key-value pair + * represents the initial property values for a single widget class, with + * the array key being the widget class name, and array value being the initial + * property value array. For example, + * <pre> + * array( + * 'CLinkPager'=>array( + * 'maxButtonCount'=>5, + * 'cssFile'=>false, + * ), + * 'CJuiDatePicker'=>array( + * 'language'=>'ru', + * ), + * ) + * </pre> + * + * Note that the initial values specified here may be overridden by + * the values given in {@link CBaseController::createWidget} calls. + * They may also be overridden by widget skins, if {@link enableSkin} is true. + * @since 1.1.3 + */ + public $widgets=array(); + /** + * @var array list of widget class names that can be skinned. + * Because skinning widgets has performance impact, you may want to specify this property + * to limit skinning only to specific widgets. Any widgets that are not in this list + * will not be skinned. Defaults to null, meaning all widgets can be skinned. + * @since 1.1.3 + */ + public $skinnableWidgets; + /** + * @var string the directory containing all the skin files. Defaults to null, + * meaning using the "skins" directory under the current application's {@link CWebApplication::viewPath}. + */ + public $skinPath; + + private $_skins=array(); // class name, skin name, property name => value + + /** + * Initializes the application component. + * This method overrides the parent implementation by resolving the skin path. + */ + public function init() + { + parent::init(); + + if($this->enableSkin && $this->skinPath===null) + $this->skinPath=Yii::app()->getViewPath().DIRECTORY_SEPARATOR.'skins'; + } + + /** + * Creates a new widget based on the given class name and initial properties. + * @param CBaseController $owner the owner of the new widget + * @param string $className the class name of the widget. This can also be a path alias (e.g. system.web.widgets.COutputCache) + * @param array $properties the initial property values (name=>value) of the widget. + * @return CWidget the newly created widget whose properties have been initialized with the given values. + */ + public function createWidget($owner,$className,$properties=array()) + { + $className=Yii::import($className,true); + $widget=new $className($owner); + + if(isset($this->widgets[$className])) + $properties=$properties===array() ? $this->widgets[$className] : CMap::mergeArray($this->widgets[$className],$properties); + if($this->enableSkin) + { + if($this->skinnableWidgets===null || in_array($className,$this->skinnableWidgets)) + { + $skinName=isset($properties['skin']) ? $properties['skin'] : 'default'; + if($skinName!==false && ($skin=$this->getSkin($className,$skinName))!==array()) + $properties=$properties===array() ? $skin : CMap::mergeArray($skin,$properties); + } + } + foreach($properties as $name=>$value) + $widget->$name=$value; + return $widget; + } + + /** + * Returns the skin for the specified widget class and skin name. + * @param string $className the widget class name + * @param string $skinName the widget skin name + * @return array the skin (name=>value) for the widget + */ + protected function getSkin($className,$skinName) + { + if(!isset($this->_skins[$className][$skinName])) + { + $skinFile=$this->skinPath.DIRECTORY_SEPARATOR.$className.'.php'; + if(is_file($skinFile)) + $this->_skins[$className]=require($skinFile); + else + $this->_skins[$className]=array(); + + if(($theme=Yii::app()->getTheme())!==null) + { + $skinFile=$theme->getSkinPath().DIRECTORY_SEPARATOR.$className.'.php'; + if(is_file($skinFile)) + { + $skins=require($skinFile); + foreach($skins as $name=>$skin) + $this->_skins[$className][$name]=$skin; + } + } + + if(!isset($this->_skins[$className][$skinName])) + $this->_skins[$className][$skinName]=array(); + } + return $this->_skins[$className][$skinName]; + } +}
\ No newline at end of file |
