CWebApplication.php
17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
<?php
/**
* CWebApplication 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/
*/
/**
* CWebApplication extends CApplication by providing functionalities specific to Web requests.
*
* CWebApplication manages the controllers in MVC pattern, and provides the following additional
* core application components:
* <ul>
* <li>{@link urlManager}: provides URL parsing and constructing functionality;</li>
* <li>{@link request}: encapsulates the Web request information;</li>
* <li>{@link session}: provides the session-related functionalities;</li>
* <li>{@link assetManager}: manages the publishing of private asset files.</li>
* <li>{@link user}: represents the user session information.</li>
* <li>{@link themeManager}: manages themes.</li>
* <li>{@link authManager}: manages role-based access control (RBAC).</li>
* <li>{@link clientScript}: manages client scripts (javascripts and CSS).</li>
* <li>{@link widgetFactory}: creates widgets and supports widget skinning.</li>
* </ul>
*
* User requests are resolved as controller-action pairs and additional parameters.
* CWebApplication creates the requested controller instance and let it to handle
* the actual user request. If the user does not specify controller ID, it will
* assume {@link defaultController} is requested (which defaults to 'site').
*
* Controller class files must reside under the directory {@link getControllerPath controllerPath}
* (defaults to 'protected/controllers'). The file name and the class name must be
* the same as the controller ID with the first letter in upper case and appended with 'Controller'.
* For example, the controller 'article' is defined by the class 'ArticleController'
* which is in the file 'protected/controllers/ArticleController.php'.
*
* @property IAuthManager $authManager The authorization manager component.
* @property CAssetManager $assetManager The asset manager component.
* @property CHttpSession $session The session component.
* @property CWebUser $user The user session information.
* @property IViewRenderer $viewRenderer The view renderer.
* @property CClientScript $clientScript The client script manager.
* @property IWidgetFactory $widgetFactory The widget factory.
* @property CThemeManager $themeManager The theme manager.
* @property CTheme $theme The theme used currently. Null if no theme is being used.
* @property CController $controller The currently active controller.
* @property string $controllerPath The directory that contains the controller classes. Defaults to 'protected/controllers'.
* @property string $viewPath The root directory of view files. Defaults to 'protected/views'.
* @property string $systemViewPath The root directory of system view files. Defaults to 'protected/views/system'.
* @property string $layoutPath The root directory of layout files. Defaults to 'protected/views/layouts'.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.web
* @since 1.0
*/
class CWebApplication extends CApplication
{
/**
* @return string the route of the default controller, action or module. Defaults to 'site'.
*/
public $defaultController='site';
/**
* @var mixed the application-wide layout. Defaults to 'main' (relative to {@link getLayoutPath layoutPath}).
* If this is false, then no layout will be used.
*/
public $layout='main';
/**
* @var array mapping from controller ID to controller configurations.
* Each name-value pair specifies the configuration for a single controller.
* A controller configuration can be either a string or an array.
* If the former, the string should be the class name or
* {@link YiiBase::getPathOfAlias class path alias} of the controller.
* If the latter, the array must contain a 'class' element which specifies
* the controller's class name or {@link YiiBase::getPathOfAlias class path alias}.
* The rest name-value pairs in the array are used to initialize
* the corresponding controller properties. For example,
* <pre>
* array(
* 'post'=>array(
* 'class'=>'path.to.PostController',
* 'pageTitle'=>'something new',
* ),
* 'user'=>'path.to.UserController',,
* )
* </pre>
*
* Note, when processing an incoming request, the controller map will first be
* checked to see if the request can be handled by one of the controllers in the map.
* If not, a controller will be searched for under the {@link getControllerPath default controller path}.
*/
public $controllerMap=array();
/**
* @var array the configuration specifying a controller which should handle
* all user requests. This is mainly used when the application is in maintenance mode
* and we should use a controller to handle all incoming requests.
* The configuration specifies the controller route (the first element)
* and GET parameters (the rest name-value pairs). For example,
* <pre>
* array(
* 'offline/notice',
* 'param1'=>'value1',
* 'param2'=>'value2',
* )
* </pre>
* Defaults to null, meaning catch-all is not effective.
*/
public $catchAllRequest;
/**
* @var string Namespace that should be used when loading controllers.
* Default is to use global namespace.
* @since 1.1.11
*/
public $controllerNamespace;
private $_controllerPath;
private $_viewPath;
private $_systemViewPath;
private $_layoutPath;
private $_controller;
private $_theme;
/**
* Processes the current request.
* It first resolves the request into controller and action,
* and then creates the controller to perform the action.
*/
public function processRequest()
{
if(is_array($this->catchAllRequest) && isset($this->catchAllRequest[0]))
{
$route=$this->catchAllRequest[0];
foreach(array_splice($this->catchAllRequest,1) as $name=>$value)
$_GET[$name]=$value;
}
else
$route=$this->getUrlManager()->parseUrl($this->getRequest());
$this->runController($route);
}
/**
* Registers the core application components.
* This method overrides the parent implementation by registering additional core components.
* @see setComponents
*/
protected function registerCoreComponents()
{
parent::registerCoreComponents();
$components=array(
'session'=>array(
'class'=>'CHttpSession',
),
'assetManager'=>array(
'class'=>'CAssetManager',
),
'user'=>array(
'class'=>'CWebUser',
),
'themeManager'=>array(
'class'=>'CThemeManager',
),
'authManager'=>array(
'class'=>'CPhpAuthManager',
),
'clientScript'=>array(
'class'=>'CClientScript',
),
'widgetFactory'=>array(
'class'=>'CWidgetFactory',
),
);
$this->setComponents($components);
}
/**
* @return IAuthManager the authorization manager component
*/
public function getAuthManager()
{
return $this->getComponent('authManager');
}
/**
* @return CAssetManager the asset manager component
*/
public function getAssetManager()
{
return $this->getComponent('assetManager');
}
/**
* @return CHttpSession the session component
*/
public function getSession()
{
return $this->getComponent('session');
}
/**
* @return CWebUser the user session information
*/
public function getUser()
{
return $this->getComponent('user');
}
/**
* Returns the view renderer.
* If this component is registered and enabled, the default
* view rendering logic defined in {@link CBaseController} will
* be replaced by this renderer.
* @return IViewRenderer the view renderer.
*/
public function getViewRenderer()
{
return $this->getComponent('viewRenderer');
}
/**
* Returns the client script manager.
* @return CClientScript the client script manager
*/
public function getClientScript()
{
return $this->getComponent('clientScript');
}
/**
* Returns the widget factory.
* @return IWidgetFactory the widget factory
* @since 1.1
*/
public function getWidgetFactory()
{
return $this->getComponent('widgetFactory');
}
/**
* @return CThemeManager the theme manager.
*/
public function getThemeManager()
{
return $this->getComponent('themeManager');
}
/**
* @return CTheme the theme used currently. Null if no theme is being used.
*/
public function getTheme()
{
if(is_string($this->_theme))
$this->_theme=$this->getThemeManager()->getTheme($this->_theme);
return $this->_theme;
}
/**
* @param string $value the theme name
*/
public function setTheme($value)
{
$this->_theme=$value;
}
/**
* Creates the controller and performs the specified action.
* @param string $route the route of the current request. See {@link createController} for more details.
* @throws CHttpException if the controller could not be created.
*/
public function runController($route)
{
if(($ca=$this->createController($route))!==null)
{
list($controller,$actionID)=$ca;
$oldController=$this->_controller;
$this->_controller=$controller;
$controller->init();
$controller->run($actionID);
$this->_controller=$oldController;
}
else
throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',
array('{route}'=>$route===''?$this->defaultController:$route)));
}
/**
* Creates a controller instance based on a route.
* The route should contain the controller ID and the action ID.
* It may also contain additional GET variables. All these must be concatenated together with slashes.
*
* This method will attempt to create a controller in the following order:
* <ol>
* <li>If the first segment is found in {@link controllerMap}, the corresponding
* controller configuration will be used to create the controller;</li>
* <li>If the first segment is found to be a module ID, the corresponding module
* will be used to create the controller;</li>
* <li>Otherwise, it will search under the {@link controllerPath} to create
* the corresponding controller. For example, if the route is "admin/user/create",
* then the controller will be created using the class file "protected/controllers/admin/UserController.php".</li>
* </ol>
* @param string $route the route of the request.
* @param CWebModule $owner the module that the new controller will belong to. Defaults to null, meaning the application
* instance is the owner.
* @return array the controller instance and the action ID. Null if the controller class does not exist or the route is invalid.
*/
public function createController($route,$owner=null)
{
if($owner===null)
$owner=$this;
if(($route=trim($route,'/'))==='')
$route=$owner->defaultController;
$caseSensitive=$this->getUrlManager()->caseSensitive;
$route.='/';
while(($pos=strpos($route,'/'))!==false)
{
$id=substr($route,0,$pos);
if(!preg_match('/^\w+$/',$id))
return null;
if(!$caseSensitive)
$id=strtolower($id);
$route=(string)substr($route,$pos+1);
if(!isset($basePath)) // first segment
{
if(isset($owner->controllerMap[$id]))
{
return array(
Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner),
$this->parseActionParams($route),
);
}
if(($module=$owner->getModule($id))!==null)
return $this->createController($route,$module);
$basePath=$owner->getControllerPath();
$controllerID='';
}
else
$controllerID.='/';
$className=ucfirst($id).'Controller';
$classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php';
if($owner->controllerNamespace!==null)
$className=$owner->controllerNamespace.'\\'.$className;
if(is_file($classFile))
{
if(!class_exists($className,false))
require($classFile);
if(class_exists($className,false) && is_subclass_of($className,'CController'))
{
$id[0]=strtolower($id[0]);
return array(
new $className($controllerID.$id,$owner===$this?null:$owner),
$this->parseActionParams($route),
);
}
return null;
}
$controllerID.=$id;
$basePath.=DIRECTORY_SEPARATOR.$id;
}
}
/**
* Parses a path info into an action ID and GET variables.
* @param string $pathInfo path info
* @return string action ID
*/
protected function parseActionParams($pathInfo)
{
if(($pos=strpos($pathInfo,'/'))!==false)
{
$manager=$this->getUrlManager();
$manager->parsePathInfo((string)substr($pathInfo,$pos+1));
$actionID=substr($pathInfo,0,$pos);
return $manager->caseSensitive ? $actionID : strtolower($actionID);
}
else
return $pathInfo;
}
/**
* @return CController the currently active controller
*/
public function getController()
{
return $this->_controller;
}
/**
* @param CController $value the currently active controller
*/
public function setController($value)
{
$this->_controller=$value;
}
/**
* @return string the directory that contains the controller classes. Defaults to 'protected/controllers'.
*/
public function getControllerPath()
{
if($this->_controllerPath!==null)
return $this->_controllerPath;
else
return $this->_controllerPath=$this->getBasePath().DIRECTORY_SEPARATOR.'controllers';
}
/**
* @param string $value the directory that contains the controller classes.
* @throws CException if the directory is invalid
*/
public function setControllerPath($value)
{
if(($this->_controllerPath=realpath($value))===false || !is_dir($this->_controllerPath))
throw new CException(Yii::t('yii','The controller path "{path}" is not a valid directory.',
array('{path}'=>$value)));
}
/**
* @return string the root directory of view files. Defaults to 'protected/views'.
*/
public function getViewPath()
{
if($this->_viewPath!==null)
return $this->_viewPath;
else
return $this->_viewPath=$this->getBasePath().DIRECTORY_SEPARATOR.'views';
}
/**
* @param string $path the root directory of view files.
* @throws CException if the directory does not exist.
*/
public function setViewPath($path)
{
if(($this->_viewPath=realpath($path))===false || !is_dir($this->_viewPath))
throw new CException(Yii::t('yii','The view path "{path}" is not a valid directory.',
array('{path}'=>$path)));
}
/**
* @return string the root directory of system view files. Defaults to 'protected/views/system'.
*/
public function getSystemViewPath()
{
if($this->_systemViewPath!==null)
return $this->_systemViewPath;
else
return $this->_systemViewPath=$this->getViewPath().DIRECTORY_SEPARATOR.'system';
}
/**
* @param string $path the root directory of system view files.
* @throws CException if the directory does not exist.
*/
public function setSystemViewPath($path)
{
if(($this->_systemViewPath=realpath($path))===false || !is_dir($this->_systemViewPath))
throw new CException(Yii::t('yii','The system view path "{path}" is not a valid directory.',
array('{path}'=>$path)));
}
/**
* @return string the root directory of layout files. Defaults to 'protected/views/layouts'.
*/
public function getLayoutPath()
{
if($this->_layoutPath!==null)
return $this->_layoutPath;
else
return $this->_layoutPath=$this->getViewPath().DIRECTORY_SEPARATOR.'layouts';
}
/**
* @param string $path the root directory of layout files.
* @throws CException if the directory does not exist.
*/
public function setLayoutPath($path)
{
if(($this->_layoutPath=realpath($path))===false || !is_dir($this->_layoutPath))
throw new CException(Yii::t('yii','The layout path "{path}" is not a valid directory.',
array('{path}'=>$path)));
}
/**
* The pre-filter for controller actions.
* This method is invoked before the currently requested controller action and all its filters
* are executed. You may override this method with logic that needs to be done
* before all controller actions.
* @param CController $controller the controller
* @param CAction $action the action
* @return boolean whether the action should be executed.
*/
public function beforeControllerAction($controller,$action)
{
return true;
}
/**
* The post-filter for controller actions.
* This method is invoked after the currently requested controller action and all its filters
* are executed. You may override this method with logic that needs to be done
* after all controller actions.
* @param CController $controller the controller
* @param CAction $action the action
*/
public function afterControllerAction($controller,$action)
{
}
/**
* Do not call this method. This method is used internally to search for a module by its ID.
* @param string $id module ID
* @return CWebModule the module that has the specified ID. Null if no module is found.
*/
public function findModule($id)
{
if(($controller=$this->getController())!==null && ($module=$controller->getModule())!==null)
{
do
{
if(($m=$module->getModule($id))!==null)
return $m;
} while(($module=$module->getParentModule())!==null);
}
if(($m=$this->getModule($id))!==null)
return $m;
}
/**
* Initializes the application.
* This method overrides the parent implementation by preloading the 'request' component.
*/
protected function init()
{
parent::init();
// preload 'request' so that it has chance to respond to onBeginRequest event.
$this->getRequest();
}
}