Module.php 18.2 KB
Newer Older
w  
Qiang Xue committed
1 2 3 4 5
<?php
/**
 * Module class file.
 *
 * @link http://www.yiiframework.com/
Qiang Xue committed
6
 * @copyright Copyright &copy; 2008 Yii Software LLC
w  
Qiang Xue committed
7 8 9 10 11
 * @license http://www.yiiframework.com/license/
 */

namespace yii\base;

Qiang Xue committed
12 13
use yii\util\FileHelper;

w  
Qiang Xue committed
14 15 16
/**
 * Module is the base class for module and application classes.
 *
Qiang Xue committed
17
 * Module mainly manages application components and sub-modules that belongs to a module.
w  
Qiang Xue committed
18
 *
Qiang Xue committed
19 20
 * @property string $uniqueId An ID that uniquely identifies this module among all modules within
 * the current application.
Qiang Xue committed
21 22 23 24 25 26
 * @property string $basePath The root directory of the module. Defaults to the directory containing the module class.
 * @property array $modules The configuration of the currently installed modules (module ID => configuration).
 * @property array $components The application components (indexed by their IDs).
 * @property array $import List of aliases to be imported. This property is write-only.
 * @property array $aliases List of aliases to be defined. This property is write-only.
 *
w  
Qiang Xue committed
27 28 29
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
Qiang Xue committed
30
abstract class Module extends Component
w  
Qiang Xue committed
31
{
m  
Qiang Xue committed
32 33 34 35
	/**
	 * @var array custom module parameters (name => value).
	 */
	public $params = array();
w  
Qiang Xue committed
36
	/**
Qiang Xue committed
37
	 * @var array the IDs of the application components that should be preloaded when this module is created.
w  
Qiang Xue committed
38 39
	 */
	public $preload = array();
Qiang Xue committed
40 41 42 43 44 45 46 47
	/**
	 * @var string an ID that uniquely identifies this module among other modules which have the same [[parent]].
	 */
	public $id;
	/**
	 * @var Module the parent module of this module. Null if this module does not have a parent.
	 */
	public $module;
Qiang Xue committed
48 49 50 51 52 53
	/**
	 * @var mixed the layout that should be applied for views within this module. This refers to a view name
	 * relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]]
	 * will be taken. If this is false, layout will be disabled within this module.
	 */
	public $layout;
Qiang Xue committed
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
	/**
	 * @var array mapping from controller ID to controller configurations.
	 * Each name-value pair specifies the configuration of 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 path alias of the controller.
	 * If the latter, the array must contain a 'class' element which specifies
	 * the controller's class name or path alias, and the rest of the name-value pairs
	 * in the array are used to initialize the corresponding controller properties. For example,
	 *
	 * ~~~
	 * array(
	 *   'account' => '@application/controllers/UserController',
	 *   'article' => array(
	 *      'class' => '@application/controllers/PostController',
	 *      'pageTitle' => 'something new',
	 *   ),
	 * )
	 * ~~~
	 */
	public $controllers = array();
	/**
	 * @return string the default route of this module. Defaults to 'default'.
	 * The route may consist of child module ID, controller ID, and/or action ID.
	 * For example, `help`, `post/create`, `admin/post/create`.
	 * If action ID is not given, it will take the default value as specified in
	 * [[Controller::defaultAction]].
	 */
	public $defaultRoute = 'default';
	/**
	 * @var string the root directory of the module.
	 */
	protected $_basePath;
Qiang Xue committed
86 87 88 89 90 91 92 93
	/**
	 * @var string the root directory that contains view files.
	 */
	protected $_viewPath;
	/**
	 * @var string the root directory that contains layout view files.
	 */
	protected $_layoutPath;
Qiang Xue committed
94 95 96 97 98 99 100 101 102 103 104 105
	/**
	 * @var string the directory containing controller classes in the module.
	 */
	protected $_controllerPath;
	/**
	 * @var array child modules of this module
	 */
	protected $_modules = array();
	/**
	 * @var array application components of this module
	 */
	protected $_components = array();
w  
Qiang Xue committed
106 107 108 109

	/**
	 * Constructor.
	 * @param string $id the ID of this module
Qiang Xue committed
110
	 * @param Module $parent the parent module (if any)
Qiang Xue committed
111
	 * @param array $config name-value pairs that will be used to initialize the object properties
w  
Qiang Xue committed
112
	 */
Qiang Xue committed
113
	public function __construct($id, $parent = null, $config = array())
w  
Qiang Xue committed
114
	{
Qiang Xue committed
115 116
		$this->id = $id;
		$this->module = $parent;
Qiang Xue committed
117
		parent::__construct($config);
w  
Qiang Xue committed
118 119 120 121 122 123 124 125 126 127 128
	}

	/**
	 * Getter magic method.
	 * This method is overridden to support accessing application components
	 * like reading module properties.
	 * @param string $name application component or property name
	 * @return mixed the named property value
	 */
	public function __get($name)
	{
w  
Qiang Xue committed
129
		if ($this->hasComponent($name)) {
w  
Qiang Xue committed
130
			return $this->getComponent($name);
Qiang Xue committed
131
		} else {
w  
Qiang Xue committed
132
			return parent::__get($name);
w  
Qiang Xue committed
133
		}
w  
Qiang Xue committed
134 135 136 137 138 139 140 141 142 143 144
	}

	/**
	 * Checks if a property value is null.
	 * This method overrides the parent implementation by checking
	 * if the named application component is loaded.
	 * @param string $name the property name or the event name
	 * @return boolean whether the property value is null
	 */
	public function __isset($name)
	{
w  
Qiang Xue committed
145
		if ($this->hasComponent($name)) {
w  
Qiang Xue committed
146
			return $this->getComponent($name) !== null;
Qiang Xue committed
147
		} else {
w  
Qiang Xue committed
148
			return parent::__isset($name);
w  
Qiang Xue committed
149 150 151 152
		}
	}

	/**
Qiang Xue committed
153 154
	 * Initializes the module.
	 * This method is called after the module is created and initialized with property values
.  
Qiang Xue committed
155 156
	 * given in configuration. The default implement will create a path alias using the module [[id]]
	 * and then call [[preloadComponents()]] to load components that are declared in [[preload]].
w  
Qiang Xue committed
157
	 */
Qiang Xue committed
158
	public function init()
w  
Qiang Xue committed
159
	{
Qiang Xue committed
160
		\Yii::setAlias('@' . $this->id, $this->getBasePath());
Qiang Xue committed
161
		$this->preloadComponents();
w  
Qiang Xue committed
162 163 164
	}

	/**
Qiang Xue committed
165 166
	 * Returns an ID that uniquely identifies this module among all modules within the current application.
	 * @return string the unique ID of the module.
w  
Qiang Xue committed
167
	 */
Qiang Xue committed
168
	public function getUniqueId()
w  
Qiang Xue committed
169
	{
Qiang Xue committed
170 171 172 173 174
		if ($this->module && !$this->module instanceof Application) {
			return $this->module->getUniqueId() . "/{$this->id}";
		} else {
			return $this->id;
		}
w  
Qiang Xue committed
175 176 177 178
	}

	/**
	 * Returns the root directory of the module.
Qiang Xue committed
179 180
	 * It defaults to the directory containing the module class file.
	 * @return string the root directory of the module.
w  
Qiang Xue committed
181 182 183
	 */
	public function getBasePath()
	{
m  
Qiang Xue committed
184
		if ($this->_basePath === null) {
Qiang Xue committed
185
			$class = new \ReflectionClass($this);
w  
Qiang Xue committed
186 187 188 189 190 191 192 193
			$this->_basePath = dirname($class->getFileName());
		}
		return $this->_basePath;
	}

	/**
	 * Sets the root directory of the module.
	 * This method can only be invoked at the beginning of the constructor.
Qiang Xue committed
194
	 * @param string $path the root directory of the module. This can be either a directory name or a path alias.
m  
Qiang Xue committed
195
	 * @throws Exception if the directory does not exist.
w  
Qiang Xue committed
196 197 198
	 */
	public function setBasePath($path)
	{
Qiang Xue committed
199
		$this->_basePath = FileHelper::ensureDirectory($path);
w  
Qiang Xue committed
200 201
	}

Qiang Xue committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
	/**
	 * Returns the directory that contains the controller classes.
	 * Defaults to "[[basePath]]/controllers".
	 * @return string the directory that contains the controller classes.
	 */
	public function getControllerPath()
	{
		if ($this->_controllerPath !== null) {
			return $this->_controllerPath;
		} else {
			return $this->_controllerPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'controllers';
		}
	}

	/**
	 * Sets the directory that contains the controller classes.
	 * @param string $path the directory that contains the controller classes.
	 * This can be either a directory name or a path alias.
	 * @throws Exception if the directory is invalid
	 */
	public function setControllerPath($path)
	{
Qiang Xue committed
224
		$this->_controllerPath = FileHelper::ensureDirectory($path);
Qiang Xue committed
225 226
	}

Qiang Xue committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240
	/**
	 * @return string the root directory of view files. Defaults to 'moduleDir/views' where
	 * moduleDir is the directory containing the module class.
	 */
	public function getViewPath()
	{
		if ($this->_viewPath !== null) {
			return $this->_viewPath;
		} else {
			return $this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views';
		}
	}

	/**
Qiang Xue committed
241
	 * Sets the directory that contains the view files.
Qiang Xue committed
242
	 * @param string $path the root directory of view files.
Qiang Xue committed
243
	 * @throws Exception if the directory is invalid
Qiang Xue committed
244 245 246
	 */
	public function setViewPath($path)
	{
Qiang Xue committed
247
		$this->_viewPath = FileHelper::ensureDirectory($path);
Qiang Xue committed
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	}

	/**
	 * @return string the root directory of layout files. Defaults to 'moduleDir/views/layouts' where
	 * moduleDir is the directory containing the module class.
	 */
	public function getLayoutPath()
	{
		if ($this->_layoutPath !== null) {
			return $this->_layoutPath;
		} else {
			return $this->_layoutPath = $this->getViewPath() . DIRECTORY_SEPARATOR . 'layouts';
		}
	}

	/**
Qiang Xue committed
264
	 * Sets the directory that contains the layout files.
Qiang Xue committed
265
	 * @param string $path the root directory of layout files.
Qiang Xue committed
266
	 * @throws Exception if the directory is invalid
Qiang Xue committed
267 268 269
	 */
	public function setLayoutPath($path)
	{
Qiang Xue committed
270
		$this->_layoutPath = FileHelper::ensureDirectory($path);
Qiang Xue committed
271 272
	}

w  
Qiang Xue committed
273
	/**
m  
Qiang Xue committed
274
	 * Imports the specified path aliases.
Qiang Xue committed
275 276
	 * This method is provided so that you can import a set of path aliases when configuring a module.
	 * The path aliases will be imported by calling [[\Yii::import()]].
m  
Qiang Xue committed
277
	 * @param array $aliases list of path aliases to be imported
w  
Qiang Xue committed
278 279 280
	 */
	public function setImport($aliases)
	{
m  
Qiang Xue committed
281 282 283
		foreach ($aliases as $alias) {
			\Yii::import($alias);
		}
w  
Qiang Xue committed
284 285 286
	}

	/**
w  
Qiang Xue committed
287
	 * Defines path aliases.
Qiang Xue committed
288 289
	 * This method calls [[\Yii::setAlias()]] to register the path aliases.
	 * This method is provided so that you can define path aliases when configuring a module.
w  
Qiang Xue committed
290
	 * @param array $aliases list of path aliases to be defined. The array keys are alias names
Qiang Xue committed
291
	 * (must start with '@') and the array values are the corresponding paths or aliases.
w  
Qiang Xue committed
292
	 * For example,
w  
Qiang Xue committed
293 294
	 *
	 * ~~~
w  
Qiang Xue committed
295
	 * array(
Qiang Xue committed
296
	 *	'@models' => '@app/models', // an existing alias
Qiang Xue committed
297
	 *	'@backend' => __DIR__ . '/../backend',  // a directory
w  
Qiang Xue committed
298
	 * )
w  
Qiang Xue committed
299
	 * ~~~
w  
Qiang Xue committed
300
	 */
w  
Qiang Xue committed
301
	public function setAliases($aliases)
w  
Qiang Xue committed
302
	{
w  
Qiang Xue committed
303 304
		foreach ($aliases as $name => $alias) {
			\Yii::setAlias($name, $alias);
w  
Qiang Xue committed
305 306 307 308
		}
	}

	/**
Qiang Xue committed
309 310 311 312
	 * Checks whether the named module exists.
	 * @param string $id module ID
	 * @return boolean whether the named module exists. Both loaded and unloaded modules
	 * are considered.
w  
Qiang Xue committed
313
	 */
Qiang Xue committed
314
	public function hasModule($id)
w  
Qiang Xue committed
315
	{
Qiang Xue committed
316 317 318 319 320 321
		return isset($this->_modules[$id]);
	}

	/**
	 * Retrieves the named module.
	 * @param string $id module ID (case-sensitive)
322
	 * @param boolean $load whether to load the module if it is not yet loaded.
Qiang Xue committed
323 324 325 326
	 * @return Module|null the module instance, null if the module
	 * does not exist.
	 * @see hasModule()
	 */
327
	public function getModule($id, $load = true)
Qiang Xue committed
328 329 330 331
	{
		if (isset($this->_modules[$id])) {
			if ($this->_modules[$id] instanceof Module) {
				return $this->_modules[$id];
332
			} elseif ($load) {
Qiang Xue committed
333 334
				\Yii::trace("Loading \"$id\" module", __CLASS__);
				return $this->_modules[$id] = \Yii::createObject($this->_modules[$id], $id, $this);
w  
Qiang Xue committed
335 336
			}
		}
Qiang Xue committed
337
		return null;
w  
Qiang Xue committed
338 339 340
	}

	/**
Qiang Xue committed
341 342 343 344 345 346 347 348 349
	 * Adds a sub-module to this module.
	 * @param string $id module ID
	 * @param Module|array|null $module the sub-module to be added to this module. This can
	 * be one of the followings:
	 *
	 * - a [[Module]] object
	 * - a configuration array: when [[getModule()]] is called initially, the array
	 *   will be used to instantiate the sub-module
	 * - null: the named sub-module will be removed from this module
w  
Qiang Xue committed
350
	 */
Qiang Xue committed
351
	public function setModule($id, $module)
w  
Qiang Xue committed
352
	{
Qiang Xue committed
353 354 355 356 357
		if ($module === null) {
			unset($this->_modules[$id]);
		} else {
			$this->_modules[$id] = $module;
		}
w  
Qiang Xue committed
358 359 360
	}

	/**
Qiang Xue committed
361 362 363 364 365
	 * Returns the sub-modules in this module.
	 * @param boolean $loadedOnly whether to return the loaded sub-modules only. If this is set false,
	 * then all sub-modules registered in this module will be returned, whether they are loaded or not.
	 * Loaded modules will be returned as objects, while unloaded modules as configuration arrays.
	 * @return array the modules (indexed by their IDs)
w  
Qiang Xue committed
366
	 */
Qiang Xue committed
367
	public function getModules($loadedOnly = false)
w  
Qiang Xue committed
368
	{
Qiang Xue committed
369 370 371 372 373 374 375 376 377 378 379
		if ($loadedOnly) {
			$modules = array();
			foreach ($this->_modules as $module) {
				if ($module instanceof Module) {
					$modules[] = $module;
				}
			}
			return $modules;
		} else {
			return $this->_modules;
		}
w  
Qiang Xue committed
380 381 382
	}

	/**
Qiang Xue committed
383
	 * Registers sub-modules in the current module.
w  
Qiang Xue committed
384
	 *
Qiang Xue committed
385 386 387 388
	 * Each sub-module should be specified as a name-value pair, where
	 * name refers to the ID of the module and value the module or a configuration
	 * array that can be used to create the module. In the latter case, [[\Yii::createObject()]]
	 * will be used to create the module.
w  
Qiang Xue committed
389
	 *
Qiang Xue committed
390
	 * If a new sub-module has the same ID as an existing one, the existing one will be overwritten silently.
w  
Qiang Xue committed
391
	 *
Qiang Xue committed
392
	 * The following is an example for registering two sub-modules:
w  
Qiang Xue committed
393
	 *
Qiang Xue committed
394 395 396 397 398 399 400 401 402 403 404
	 * ~~~
	 * array(
	 *     'comment' => array(
	 *         'class' => 'app\modules\CommentModule',
	 *         'connectionID' => 'db',
	 *     ),
	 *     'booking' => array(
	 *         'class' => 'app\modules\BookingModule',
	 *     ),
	 * )
	 * ~~~
w  
Qiang Xue committed
405
	 *
Qiang Xue committed
406
	 * @param array $modules modules (id => module configuration or instances)
w  
Qiang Xue committed
407 408 409
	 */
	public function setModules($modules)
	{
Qiang Xue committed
410 411
		foreach ($modules as $id => $module) {
			$this->_modules[$id] = $module;
w  
Qiang Xue committed
412 413
		}
	}
414

w  
Qiang Xue committed
415 416 417
	/**
	 * Checks whether the named component exists.
	 * @param string $id application component ID
Qiang Xue committed
418 419
	 * @return boolean whether the named application component exists. Both loaded and unloaded components
	 * are considered.
w  
Qiang Xue committed
420 421 422
	 */
	public function hasComponent($id)
	{
Qiang Xue committed
423
		return isset($this->_components[$id]);
w  
Qiang Xue committed
424 425 426 427 428
	}

	/**
	 * Retrieves the named application component.
	 * @param string $id application component ID (case-sensitive)
429
	 * @param boolean $load whether to load the component if it is not yet loaded.
Qiang Xue committed
430 431 432
	 * @return ApplicationComponent|null the application component instance, null if the application component
	 * does not exist.
	 * @see hasComponent()
w  
Qiang Xue committed
433
	 */
434
	public function getComponent($id, $load = true)
w  
Qiang Xue committed
435
	{
Qiang Xue committed
436
		if (isset($this->_components[$id])) {
Qiang Xue committed
437 438
			if ($this->_components[$id] instanceof ApplicationComponent) {
				return $this->_components[$id];
439
			} elseif ($load) {
Qiang Xue committed
440 441
				\Yii::trace("Loading \"$id\" application component", __CLASS__);
				return $this->_components[$id] = \Yii::createObject($this->_components[$id]);
w  
Qiang Xue committed
442 443
			}
		}
Qiang Xue committed
444
		return null;
w  
Qiang Xue committed
445 446 447
	}

	/**
Qiang Xue committed
448
	 * Registers an application component in this module.
w  
Qiang Xue committed
449
	 * @param string $id component ID
Qiang Xue committed
450 451 452 453 454 455 456
	 * @param ApplicationComponent|array|null $component the component to be added to the module. This can
	 * be one of the followings:
	 *
	 * - an [[ApplicationComponent]] object
	 * - a configuration array: when [[getComponent()]] is called initially for this component, the array
	 *   will be used to instantiate the component
	 * - null: the named component will be removed from the module
w  
Qiang Xue committed
457 458 459
	 */
	public function setComponent($id, $component)
	{
Qiang Xue committed
460
		if ($component === null) {
w  
Qiang Xue committed
461
			unset($this->_components[$id]);
Qiang Xue committed
462
		} else {
w  
Qiang Xue committed
463 464 465 466 467 468 469 470 471 472 473
			$this->_components[$id] = $component;
		}
	}

	/**
	 * Returns the application components.
	 * @param boolean $loadedOnly whether to return the loaded components only. If this is set false,
	 * then all components specified in the configuration will be returned, whether they are loaded or not.
	 * Loaded components will be returned as objects, while unloaded components as configuration arrays.
	 * @return array the application components (indexed by their IDs)
	 */
Qiang Xue committed
474
	public function getComponents($loadedOnly = false)
w  
Qiang Xue committed
475
	{
Qiang Xue committed
476
		if ($loadedOnly) {
Qiang Xue committed
477 478 479 480 481 482 483
			$components = array();
			foreach ($this->_components as $component) {
				if ($component instanceof ApplicationComponent) {
					$components[] = $component;
				}
			}
			return $components;
Qiang Xue committed
484
		} else {
Qiang Xue committed
485
			return $this->_components;
Qiang Xue committed
486
		}
w  
Qiang Xue committed
487 488 489
	}

	/**
Qiang Xue committed
490
	 * Registers a set of application components in this module.
w  
Qiang Xue committed
491
	 *
Qiang Xue committed
492 493 494 495
	 * Each application component should be specified as a name-value pair, where
	 * name refers to the ID of the component and value the component or a configuration
	 * array that can be used to create the component. In the latter case, [[\Yii::createObject()]]
	 * will be used to create the component.
w  
Qiang Xue committed
496
	 *
Qiang Xue committed
497
	 * If a new component has the same ID as an existing one, the existing one will be overwritten silently.
w  
Qiang Xue committed
498
	 *
Qiang Xue committed
499 500 501
	 * The following is an example for setting two components:
	 *
	 * ~~~
w  
Qiang Xue committed
502
	 * array(
Qiang Xue committed
503
	 *     'db' => array(
Qiang Xue committed
504
	 *         'class' => 'yii\db\Connection',
Qiang Xue committed
505 506 507 508 509 510
	 *         'dsn' => 'sqlite:path/to/file.db',
	 *     ),
	 *     'cache' => array(
	 *         'class' => 'yii\caching\DbCache',
	 *         'connectionID' => 'db',
	 *     ),
w  
Qiang Xue committed
511
	 * )
Qiang Xue committed
512
	 * ~~~
w  
Qiang Xue committed
513
	 *
Qiang Xue committed
514
	 * @param array $components application components (id => component configuration or instance)
w  
Qiang Xue committed
515
	 */
Qiang Xue committed
516
	public function setComponents($components)
w  
Qiang Xue committed
517
	{
Qiang Xue committed
518 519
		foreach ($components as $id => $component) {
			$this->_components[$id] = $component;
w  
Qiang Xue committed
520 521 522 523
		}
	}

	/**
Qiang Xue committed
524
	 * Loads application components that are declared in [[preload]].
w  
Qiang Xue committed
525
	 */
w  
Qiang Xue committed
526
	public function preloadComponents()
w  
Qiang Xue committed
527
	{
Qiang Xue committed
528
		foreach ($this->preload as $id) {
w  
Qiang Xue committed
529
			$this->getComponent($id);
Qiang Xue committed
530
		}
w  
Qiang Xue committed
531
	}
Qiang Xue committed
532 533

	/**
Qiang Xue committed
534 535
	 * Creates a controller instance based on the given route.
	 * This method tries to parse the given route (e.g. `post/create`) using the following algorithm:
Qiang Xue committed
536 537 538 539 540
	 *
	 * 1. Get the first segment in route
	 * 2. If the segment matches
	 *    - an ID in [[controllers]], create a controller instance using the corresponding configuration,
	 *      and return the controller with the rest part of the route;
Qiang Xue committed
541
	 *    - an ID in [[modules]], call the [[createController()]] method of the corresponding module.
Qiang Xue committed
542 543 544 545
	 *    - a controller class under [[controllerPath]], create the controller instance, and return it
	 *      with the rest part of the route;
	 *
	 * @param string $route the route which may consist module ID, controller ID and/or action ID (e.g. `post/create`)
Qiang Xue committed
546
	 * @return array|boolean the array of controller instance and action ID. False if the route cannot be resolved.
Qiang Xue committed
547
	 */
Qiang Xue committed
548
	public function createController($route)
Qiang Xue committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
	{
		if (($route = trim($route, '/')) === '') {
			$route = $this->defaultRoute;
		}

		if (($pos = strpos($route, '/')) !== false) {
			$id = substr($route, 0, $pos);
			$route = (string)substr($route, $pos + 1);
		} else {
			$id = $route;
			$route = '';
		}

		// Controller IDs must start with a lower-case letter and consist of word characters only
		if (!preg_match('/^[a-z][a-zA-Z0-9_]*$/', $id)) {
Qiang Xue committed
564
			return false;
Qiang Xue committed
565 566 567
		}

		if (isset($this->controllers[$id])) {
Qiang Xue committed
568 569 570 571
			return array(
				\Yii::createObject($this->controllers[$id], $id, $this),
				$route,
			);
Qiang Xue committed
572 573
		}

Qiang Xue committed
574 575 576 577 578 579 580
		if (($module = $this->getModule($id)) !== null) {
			$result = $module->createController($route);
			if ($result !== false) {
				return $result;
			}
		}

Qiang Xue committed
581 582 583 584 585 586 587
		$className = ucfirst($id) . 'Controller';
		$classFile = $this->getControllerPath() . DIRECTORY_SEPARATOR . $className . '.php';
		if (is_file($classFile)) {
			if (!class_exists($className, false)) {
				require($classFile);
			}
			if (class_exists($className, false) && is_subclass_of($className, '\yii\base\Controller')) {
Qiang Xue committed
588
				return array(
Qiang Xue committed
589
					new $className($id, $this),
Qiang Xue committed
590 591
					$route,
				);
Qiang Xue committed
592 593 594
			}
		}

Qiang Xue committed
595
		return false;
Qiang Xue committed
596
	}
w  
Qiang Xue committed
597
}