PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/yii/framework/web/CWebApplication.php

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