mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 18:47:33 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			325 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Modules
 | |
| =======
 | |
| 
 | |
| Modules are self-contained software units that consist of [models](structure-models.md), [views](structure-views.md),
 | |
| [controllers](structure-controllers.md), and other supporting components. End users can access the controllers
 | |
| of a module when it is installed in [application](structure-applications.md). For these reasons, modules are
 | |
| often viewed as mini-applications. Modules differ from [applications](structure-applications.md) in that
 | |
| modules cannot be deployed alone and must reside within applications.
 | |
| 
 | |
| 
 | |
| ## Creating Modules <span id="creating-modules"></span>
 | |
| 
 | |
| 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
 | |
| ```
 | |
| 
 | |
| 
 | |
| ### Module Classes <span id="module-classes"></span>
 | |
| 
 | |
| Each module should have a unique 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](concept-autoloading.md).
 | |
| When a module is being accessed, a single instance of the corresponding module class will be created.
 | |
| Like [application instances](structure-applications.md), 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:
 | |
| 
 | |
| ```php
 | |
| 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](concept-configurations.md) and load it with the following code in `init()`:
 | |
| 
 | |
| ```php
 | |
| 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](structure-applications.md#application-configurations).
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| return [
 | |
|     'components' => [
 | |
|         // list of component configurations
 | |
|     ],
 | |
|     'params' => [
 | |
|         // list of parameters
 | |
|     ],
 | |
| ];
 | |
| ```
 | |
| 
 | |
| 
 | |
| ### Controllers in Modules <span id="controllers-in-modules"></span>
 | |
| 
 | |
| 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:
 | |
| 
 | |
| ```php
 | |
| 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 some of the controllers are outside of this namespace, you may make them accessible
 | |
| by configuring the [[yii\base\Module::controllerMap]] property, similar to [what you do in an application](structure-applications.md#controller-map).
 | |
| 
 | |
| 
 | |
| ### Views in Modules <span id="views-in-modules"></span>
 | |
| 
 | |
| 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](structure-controllers.md#routes). 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](structure-views.md#layouts) 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.
 | |
| 
 | |
| 
 | |
| ### Console commands in Modules <span id="console-commands-in-modules"></span>
 | |
| 
 | |
| Your module may also declare commands, that will be available through the [Console](tutorial-console.md) mode.
 | |
| 
 | |
| In order for the command line utility to see your commands, you will need to change the [[yii\base\Module::controllerNamespace]]
 | |
| property, when Yii is executed in the console mode, and point it to your commands namespace.
 | |
| 
 | |
| One way to achieve that is to test the instance type of the Yii application in the module's `init()` method:
 | |
| 
 | |
| ```php
 | |
| public function init()
 | |
| {
 | |
|     parent::init();
 | |
|     if (Yii::$app instanceof \yii\console\Application) {
 | |
|         $this->controllerNamespace = 'app\modules\forum\commands';
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| Your commands will then be available from the command line using the following route:
 | |
| 
 | |
| ```
 | |
| yii <module_id>/<command>/<sub_command>
 | |
| ```
 | |
| 
 | |
| ## Using Modules <span id="using-modules"></span>
 | |
| 
 | |
| 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](structure-applications.md#application-configurations) uses the `forum` module:
 | |
| 
 | |
| ```php
 | |
| [
 | |
|     'modules' => [
 | |
|         'forum' => [
 | |
|             'class' => 'app\modules\forum\Module',
 | |
|             // ... other configurations for the module ...
 | |
|         ],
 | |
|     ],
 | |
| ]
 | |
| ```
 | |
| 
 | |
| > Info: To connect console commands of your module,
 | |
| > you also need to include it in the [console application configuration](tutorial-console.md#configuration)
 | |
| 
 | |
| 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](concept-configurations.md) for creating the module.
 | |
| 
 | |
| 
 | |
| ### Routes <span id="routes"></span>
 | |
| 
 | |
| Like accessing controllers in an application, [routes](structure-controllers.md#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](structure-controllers.md#controller-ids) and [action ID](structure-controllers.md#action-ids).
 | |
| 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.
 | |
| 
 | |
| The URL manager rules for the modules should be added before [[yii\web\UrlManager::parseRequest()]] is fired. That means doing it 
 | |
| in module's `init()` won't work because module will be initialized when routes were already processed. Thus, the rules
 | |
| should be added at [bootstrap stage](structure-extensions.md#bootstrapping-classes). It is a also a good practice
 | |
| to wrap module's URL rules with [[\yii\web\GroupUrlRule]].  
 | |
| 
 | |
| In case a module is used to [version API](rest-versioning.md), its URL rules should be added directly in `urlManager` 
 | |
| section of the application config.
 | |
| 
 | |
| 
 | |
| ### Accessing Modules <span id="accessing-modules"></span>
 | |
| 
 | |
| Within a module, you may often need to get the instance of the [module class](#module-classes) so that you can
 | |
| access the module ID, module parameters, module components, etc. You can do so by using the following statement:
 | |
| 
 | |
| ```php
 | |
| $module = MyModuleClass::getInstance();
 | |
| ```
 | |
| 
 | |
| where `MyModuleClass` refers to the name of the module class that you are interested in. The `getInstance()` method
 | |
| will return the currently requested instance of the module class. If the module is not requested, the method will
 | |
| return `null`. Note that you do not want to manually create a new instance of the module class because it will be
 | |
| different from the one created by Yii in response to a request.
 | |
| 
 | |
| > Info: When developing a module, you should not assume the module will use a fixed ID. This is because a module
 | |
|   can be associated with an arbitrary ID when used in an application or within another module. In order to get
 | |
|   the module ID, you should use the above approach to get the module instance first, and then get the ID via
 | |
|   `$module->id`.
 | |
| 
 | |
| You may also access the instance of a module using the following approaches:
 | |
| 
 | |
| ```php
 | |
| // get the child 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 when you know the module ID, while the second approach is best used when you
 | |
| know about the controllers being requested.
 | |
| 
 | |
| Once you have the module instance, you can access parameters and components registered with the module. For example,
 | |
| 
 | |
| ```php
 | |
| $maxPostCount = $module->params['maxPostCount'];
 | |
| ```
 | |
| 
 | |
| 
 | |
| ### Bootstrapping Modules <span id="bootstrapping-modules"></span>
 | |
| 
 | |
| 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 loaded:
 | |
| 
 | |
| ```php
 | |
| [
 | |
|     'bootstrap' => [
 | |
|         'debug',
 | |
|     ],
 | |
| 
 | |
|     'modules' => [
 | |
|         'debug' => 'yii\debug\Module',
 | |
|     ],
 | |
| ]
 | |
| ```
 | |
| 
 | |
| 
 | |
| ## Nested Modules <span id="nested-modules"></span>
 | |
| 
 | |
| 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\base\Module::modules|modules]] property of their parent modules. For example,
 | |
| 
 | |
| ```php
 | |
| 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 modules.
 | |
| 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.
 | |
| 
 | |
| > Info: The [[yii\base\Module::getModule()|getModule()]] method only returns the child module directly belonging
 | |
| to its parent. The [[yii\base\Application::loadedModules]] property keeps a list of loaded modules, including both
 | |
| direct children and nested ones, indexed by their class names.
 | |
| 
 | |
| ## Accessing components from within modules
 | |
| 
 | |
| Since version 2.0.13 modules support [tree traversal](concept-service-locator.md#tree-traversal). This allows module 
 | |
| developers to reference (application) components via the service locator that is their module.
 | |
| This means that it is preferable to use `$module->get('db')` over `Yii::$app->get('db')`.
 | |
| The user of a module is able to specify a specific component to be used for the module in case a different component
 | |
| (configuration) is required.
 | |
| 
 | |
| For example consider partial this application configuration:
 | |
| 
 | |
| ```php
 | |
| 'components' => [
 | |
|     'db' => [
 | |
|         'tablePrefix' => 'main_',
 | |
|         'class' => Connection::class,
 | |
|         'enableQueryCache' => false
 | |
|     ],
 | |
| ],
 | |
| 'modules' => [
 | |
|     'mymodule' => [
 | |
|         'components' => [
 | |
|             'db' => [
 | |
|                 'tablePrefix' => 'module_',
 | |
|                 'class' => Connection::class
 | |
|             ],
 | |
|         ],
 | |
|     ],
 | |
| ],
 | |
| ```
 | |
| 
 | |
| The application database tables will be prefixed with `main_`, while all module tables will be prefixed with `module_`.
 | |
| Note that configuration above is not merged; the modules' component for example will have the query cache enabled since that is the default value.
 | |
| 
 | |
| ## Best Practices <span id="best-practices"></span>
 | |
| 
 | |
| 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 reused easily
 | |
| in future projects.
 |