1: <?php
2: /**
3: * CWidget 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: * CWidget is the base class for widgets.
13: *
14: * A widget is a self-contained component that may generate presentation
15: * based on model data. It can be viewed as a micro-controller that embeds
16: * into the controller-managed views.
17: *
18: * Compared with {@link CController controller}, a widget has neither actions nor filters.
19: *
20: * Usage is described at {@link CBaseController} and {@link CBaseController::widget}.
21: *
22: * @property CBaseController $owner Owner/creator of this widget. It could be either a widget or a controller.
23: * @property string $id Id of the widget.
24: * @property CController $controller The controller that this widget belongs to.
25: * @property string $viewPath The directory containing the view files for this widget.
26: *
27: * @author Qiang Xue <qiang.xue@gmail.com>
28: * @package system.web.widgets
29: * @since 1.0
30: */
31: class CWidget extends CBaseController
32: {
33: /**
34: * @var string the prefix to the IDs of the {@link actions}.
35: * When a widget is declared an action provider in {@link CController::actions},
36: * a prefix can be specified to differentiate its action IDs from others.
37: * The same prefix should then also be used to configure this property
38: * when the widget is used in a view of the controller.
39: */
40: public $actionPrefix;
41: /**
42: * @var mixed the name of the skin to be used by this widget. Defaults to 'default'.
43: * If this is set as false, no skin will be applied to this widget.
44: * @see CWidgetFactory
45: * @since 1.1
46: */
47: public $skin='default';
48:
49: /**
50: * @var array view paths for different types of widgets
51: */
52: private static $_viewPaths;
53: /**
54: * @var integer the counter for generating implicit IDs.
55: */
56: private static $_counter=0;
57: /**
58: * @var string id of the widget.
59: */
60: private $_id;
61: /**
62: * @var CBaseController owner/creator of this widget. It could be either a widget or a controller.
63: */
64: private $_owner;
65:
66: /**
67: * Returns a list of actions that are used by this widget.
68: * The structure of this method's return value is similar to
69: * that returned by {@link CController::actions}.
70: *
71: * When a widget uses several actions, you can declare these actions using
72: * this method. The widget will then become an action provider, and the actions
73: * can be easily imported into a controller.
74: *
75: * Note, when creating URLs referring to the actions listed in this method,
76: * make sure the action IDs are prefixed with {@link actionPrefix}.
77: *
78: * @return array
79: *
80: * @see actionPrefix
81: * @see CController::actions
82: */
83: public static function actions()
84: {
85: return array();
86: }
87:
88: /**
89: * Constructor.
90: * @param CBaseController $owner owner/creator of this widget. It could be either a widget or a controller.
91: */
92: public function __construct($owner=null)
93: {
94: $this->_owner=$owner===null?Yii::app()->getController():$owner;
95: }
96:
97: /**
98: * Returns the owner/creator of this widget.
99: * @return CBaseController owner/creator of this widget. It could be either a widget or a controller.
100: */
101: public function getOwner()
102: {
103: return $this->_owner;
104: }
105:
106: /**
107: * Returns the ID of the widget or generates a new one if requested.
108: * @param boolean $autoGenerate whether to generate an ID if it is not set previously
109: * @return string id of the widget.
110: */
111: public function getId($autoGenerate=true)
112: {
113: if($this->_id!==null)
114: return $this->_id;
115: elseif($autoGenerate)
116: return $this->_id='yw'.self::$_counter++;
117: }
118:
119: /**
120: * Sets the ID of the widget.
121: * @param string $value id of the widget.
122: */
123: public function setId($value)
124: {
125: $this->_id=$value;
126: }
127:
128: /**
129: * Returns the controller that this widget belongs to.
130: * @return CController the controller that this widget belongs to.
131: */
132: public function getController()
133: {
134: if($this->_owner instanceof CController)
135: return $this->_owner;
136: else
137: return Yii::app()->getController();
138: }
139:
140: /**
141: * Initializes the widget.
142: * This method is called by {@link CBaseController::createWidget}
143: * and {@link CBaseController::beginWidget} after the widget's
144: * properties have been initialized.
145: */
146: public function init()
147: {
148: }
149:
150: /**
151: * Executes the widget.
152: * This method is called by {@link CBaseController::endWidget}.
153: */
154: public function run()
155: {
156: }
157:
158: /**
159: * Returns the directory containing the view files for this widget.
160: * The default implementation returns the 'views' subdirectory of the directory containing the widget class file.
161: * If $checkTheme is set true, the directory "ThemeID/views/ClassName" will be returned when it exists.
162: * @param boolean $checkTheme whether to check if the theme contains a view path for the widget.
163: * @return string the directory containing the view files for this widget.
164: */
165: public function getViewPath($checkTheme=false)
166: {
167: $className=get_class($this);
168: $scope=$checkTheme?'theme':'local';
169: if(isset(self::$_viewPaths[$className][$scope]))
170: return self::$_viewPaths[$className][$scope];
171: else
172: {
173: if($checkTheme && ($theme=Yii::app()->getTheme())!==null)
174: {
175: $path=$theme->getViewPath().DIRECTORY_SEPARATOR;
176: if(strpos($className,'\\')!==false) // namespaced class
177: $path.=str_replace('\\','_',ltrim($className,'\\'));
178: else
179: $path.=$className;
180: if(is_dir($path))
181: return self::$_viewPaths[$className]['theme']=$path;
182: }
183:
184: $class=new ReflectionClass($className);
185: return self::$_viewPaths[$className]['local']=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views';
186: }
187: }
188:
189: /**
190: * Looks for the view script file according to the view name.
191: * This method will look for the view under the widget's {@link getViewPath viewPath}.
192: * The view script file is named as "ViewName.php". A localized view file
193: * may be returned if internationalization is needed. See {@link CApplication::findLocalizedFile}
194: * for more details.
195: * The view name can also refer to a path alias if it contains dot characters.
196: * @param string $viewName name of the view (without file extension)
197: * @return string the view file path. False if the view file does not exist
198: * @see CApplication::findLocalizedFile
199: */
200: public function getViewFile($viewName)
201: {
202: if(($renderer=Yii::app()->getViewRenderer())!==null)
203: $extension=$renderer->fileExtension;
204: else
205: $extension='.php';
206: if(strpos($viewName,'.')) // a path alias
207: $viewFile=Yii::getPathOfAlias($viewName);
208: else
209: {
210: $viewFile=$this->getViewPath(true).DIRECTORY_SEPARATOR.$viewName;
211: if(is_file($viewFile.$extension))
212: return Yii::app()->findLocalizedFile($viewFile.$extension);
213: elseif($extension!=='.php' && is_file($viewFile.'.php'))
214: return Yii::app()->findLocalizedFile($viewFile.'.php');
215: $viewFile=$this->getViewPath(false).DIRECTORY_SEPARATOR.$viewName;
216: }
217:
218: if(is_file($viewFile.$extension))
219: return Yii::app()->findLocalizedFile($viewFile.$extension);
220: elseif($extension!=='.php' && is_file($viewFile.'.php'))
221: return Yii::app()->findLocalizedFile($viewFile.'.php');
222: else
223: return false;
224: }
225:
226: /**
227: * Renders a view.
228: *
229: * The named view refers to a PHP script (resolved via {@link getViewFile})
230: * that is included by this method. If $data is an associative array,
231: * it will be extracted as PHP variables and made available to the script.
232: *
233: * @param string $view name of the view to be rendered. See {@link getViewFile} for details
234: * about how the view script is resolved.
235: * @param array $data data to be extracted into PHP variables and made available to the view script
236: * @param boolean $return whether the rendering result should be returned instead of being displayed to end users
237: * @return string the rendering result. Null if the rendering result is not required.
238: * @throws CException if the view does not exist
239: * @see getViewFile
240: */
241: public function render($view,$data=null,$return=false)
242: {
243: if(($viewFile=$this->getViewFile($view))!==false)
244: return $this->renderFile($viewFile,$data,$return);
245: else
246: throw new CException(Yii::t('yii','{widget} cannot find the view "{view}".',
247: array('{widget}'=>get_class($this), '{view}'=>$view)));
248: }
249: }