Modules are self-contained software units that consist of models, views, controllers, and other supporting components. End users can access the controllers of a module when it is installed in application. Modules differ from applications in that the former cannot be deployed alone and must reside within the latter.
A module is organized as a directory which is called the [[yii\base\Module::basePath|base path]] of the module.
Within the directory, there are sub-directories, such as controllers
, models
, views
, which hold controllers,
models, views, and other code, just like in an application. The following example shows the content within a module:
forum/
Module.php the module class file
controllers/ containing controller class files
DefaultController.php the default controller class file
models/ containing model class files
views/ containing controller view and layout files
layouts/ containing layout view files
default/ containing view files for DefaultController
index.php the index view file
Each module should have a module class which extends from [[yii\base\Module]]. The class should be located directly under the module's [[yii\base\Module::basePath|base path]] and should be autoloadable. When a module is being accessed, a single instance of the corresponding module class will be created. Like application instances, module instances are used to share data and components for code within modules.
The following is an example how a module class may look like:
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->params['foo'] = 'bar';
// ... other initialization code ...
}
}
If the init()
method contains a lot of code initializing the module's properties, you may also save them in terms
of a configuration and load it with the following code in init()
:
public function init()
{
parent::init();
// initialize the module with the configuration loaded from config.php
\Yii::configure($this, require(__DIR__ . '/config.php'));
}
where the configuration file config.php
may contain the following content, similar to that in an
application configuration.
<?php
return [
'components' => [
// list of component configurations
],
'params' => [
// list of parameters
],
];
When creating controllers in a module, a convention is to put the controller classes under the controllers
sub-namespace of the namespace of the module class. This also means the controller class files should be
put in the controllers
directory within the module's [[yii\base\Module::basePath|base path]].
For example, to create a post
controller in the forum
module shown in the last subsection, you should
declare the controller class like the following:
namespace app\modules\forum\controllers;
use yii\web\Controller;
class PostController extends Controller
{
// ...
}
You may customize the namespace of controller classes by configuring the [[yii\base\Module::controllerNamespace]] property. In case when some of the controllers are out of this namespace, you may make them accessible by configuring the [[yii\base\Module::controllerMap]] property, similar to what you do in an application.
Views in a module should be put in the views
directory within the module's [[yii\base\Module::basePath|base path]].
For views rendered by a controller in the module, they should be put under the directory views/ControllerID
,
where ControllerID
refers to the controller ID. For example, if
the controller class is PostController
, the directory would be views/post
within the module's
[[yii\base\Module::basePath|base path]].
A module can specify a layout that is applied to the views rendered by the module's
controllers. The layout should be put in the views/layouts
directory by default, and you should configure
the [[yii\base\Module::layout]] property to point to the layout name. If you do not configure the layout
property,
the application's layout will be used instead.
To use a module in an application, simply configure the application by listing the module in
the [[yii\base\Application::modules|modules]] property of the application. The following code in the
application configuration uses the forum
module:
[
'modules' => [
'forum' => [
'class' => 'app\modules\forum\Module',
// ... other configurations for the module ...
],
],
]
The [[yii\base\Application::modules|modules]] property takes an array of module configurations. Each array key represents a module ID which uniquely identifies the module among all modules in the application, and the corresponding array value is a configuration for creating the module.
Like accessing controllers in an application, routes are used to address
controllers in a module. A route for a controller within a module must begin with the module ID followed by
the controller ID and action ID. For example, if an application uses a module named forum
, then the route
forum/post/index
would represent the index
action of the post
controller in the module. If the route
only contains the module ID, then the [[yii\base\Module::defaultRoute]] property, which defaults to default
,
will determine which controller/action should be used. This means a route forum
would represent the default
controller in the forum
module.
A module is instantiated when one of its controllers is accessed by end users. You may access the instance of a module using the approaches shown in the following example:
// get the module whose ID is "forum"
$module = \Yii::$app->getModule('forum');
// get the module to which the currently requested controller belongs
$module = \Yii::$app->controller->module;
The first approach is only useful in application code which has knowledge about the module ID, while the second approach is best used by the code within the module.
Once getting hold of a module instance, you can access parameters or components registered with the module. For example,
$maxPostCount = $module->params['maxPostCount'];
Some modules may need to be run for every request. The [[yii\debug\Module|debug]] module is such an example. To do so, list the IDs of such modules in the [[yii\base\Application::bootstrap|bootstrap]] property of the application.
For example, the following application configuration makes sure the debug
module is always load:
[
'bootstrap' => [
'debug',
],
'modules' => [
'debug' => 'yii\debug\Module',
],
]
Modules can be nested in unlimited levels. That is, a module can contain another module which can contain yet another module. We call the former parent module while the latter child module. Child modules must be declared in the [[yii\bas\Module::modules|modules]] property of their parent modules. For example,
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->modules = [
'admin' => [
// you should consider using a shorter namespace here!
'class' => 'app\modules\forum\modules\admin\Module',
],
];
}
}
For a controller within a nested module, its route should include the IDs of all its ancestor module.
For example, the route forum/admin/dashboard/index
represents the index
action of the dashboard
controller
in the admin
module which is a child module of the forum
module.
Modules are best used in large applications whose features can be divided into several groups, each consisting of a set of closely related features. Each such feature group can be developed as a module which is developed and maintained by a specific developer or team.
Modules are also a good way of reusing code at the feature group level. Some commonly used features, such as user management, comment management, can all be developed in terms of modules so that they can be resued easily in future projects.