第二层内功 - 模块 ¶
作者:KK
发表日期:2017.8.28
大家都知道一个软件大了可以分模块,但具体怎么分,种语言的各个框架都有自己的一套办法,Yii2在这方面也是有解决方案的。
要点速读 ¶
通常来说,模块的代码都在一个目录里(也可以改开去,一般不改)
通常在应用目录下建立一个
modules
目录,里面放模块目录,比如modules/shop
这样来放一个商店模块模块和APP一样可以有控制器、视图和模型和组件等等,本质上APP也是一个模块,我们可以称APP为顶级模块,其它都是里面的子模块
模块可以无限组嵌套,但不提倡超过2级嵌套
快速体验 ¶
在应用目录下建一个
modules
目录,里面再建一个shop
目录,形成modules/shop
,后面我们称这个是shop模块目录在shop模块目录下建一个
Module.php
,里面的代码如下:namespace app\modules\shop; class Module extends \yii\base\Module{}
就这样可以了,里面不用写代码
在shop模块下再建
controllers
、views
目录在
controllers
里建一个DefaultController
控制器,代码:namespace app\modules\shop\controllers; class DefaultController extends \yii\web\Controller{ public function actionIndex(){ return 'shop index'; } public function actionIndex2(){ return $this->renderPartial('index2'); } }
在
views
里建一个default
目录,这是Default控制器对应的视图目录,里面再建index2.php
,内容就写“index2 in tpl”这样吧
向配置文件添加自定义模块信息 ¶
这样一个基本的模块就建立起来了,可是还不能运行,要在配置文件中为app添加modules
这个属性的配置(如果有了就基于原来的值追加内容),它值是一个数组,每个元素就是一个模块。如果我没记错,它原来的值默认应该是这样的:
'modules' => [
'gii' => 'yii\gii\Module',
'debug' => 'yii\debug\Module',
]
这表示有2个模块,分别是gii模块和debug模块,分别对应两个yii下的Module类(这个类咱们上面也有创建),好了咱们也追加一个自定义的模块:
'modules' => [
'gii' => 'yii\gii\Module',
'debug' => 'yii\debug\Module',
'shop' => 'app\modules\shop\Module', //指向上面创建的Module类
]
访问模块 ¶
假设使用默认的URL路由模式(就是那个?r=controller/action
模式),那么访问shop模块可以这样:
?r=shop/default/index2
会显示“index2 in tpl”,很容易角读,就是找shop模块的default控制器的index2这个action?r=shop/default
会显示“shop index”,定位到shop的default控制器了嘛,没指定action就默认找index
咯?r=shop
也会显示“shop index”,因为默认找Default控制器
模块的结构 ¶
模块目录里除了多了个Module类以外,其它跟顶层应用目录很像,至少会有controllers目录,如果控制器有render的话还可以加views目录,如果模块自己要添加模型还可以加个models目录
简单地说模块就是个小APP,而你观察网站入口文件new出来的yii\web\Application,它的继承链前面就是Module一个,所以说顶层App本质上就是一个模块
模块可以嵌套 ¶
上面在应用项目下添加shop的过程等于在APP模块下再加了个shop模块,而你甚至还可以尝试再在shop模块下再建一个modules目录再嵌套一个子模块
yii支持无限级模块嵌套,只是通常情况下一般不提倡超过2层嵌套,不是说不能正常稳定地运作,而是这样软件复杂度变大了,应该分割成不同的项目,将一些计算职责独立分给另一个项目
个人看法嘛,我用Yii2三年了其实也只嵌套过1层模块,没嵌过2层的,在1层的时候已经感知到应用开始变得不太好管制了,像个野孩子,越长大越难管。
所以如果嵌套第2层模块的时候来临,那意味着我要思考项目是否应该将某些内容独立成另一个项目了(变成一个服务),这样能更好地解耦软件架构,形成面向服务的组织形态。
获取当前模块的目录 ¶
比如在模块的Default控制器里要输出本模块的目录可以这样:
echo Yii::getAlias('@app') . '/modules/shop';
//或者
echo Yii::getAlias('@app/modules/shop');
//或者
echo Yii::getAlias('@app/modules/' . $this->module->id)
模块配置 ¶
如果模块要有自己的配置,最笨的人都能想到在配置文件(比如那个web.php或main.php)里的params
加东西,然后模块根据params的值来进行不同的工作就行了
实际上正确的姿势是这样的:
在模块的Module类里声明一个public属性,比如
public $interfaceUrl = '';
在模块目录下加一个config.php用来写模块配置,内容如下:
return [ 'interfaceUrl' => 'http://xxx.com/interface' ];
在
Module
类添加如下方法:public function init(){ parent::init(); $config = include(__DIR__ . '/config.php')); Yii::configure($this, $config); }
记得我在第一层内功 - Object 基类的特性里讲过的东西嘛?所有继承yii\base\Object的类都提供了一个空的init方法给你重写,利用它来加载配置,通过属性注入到自身就行了
测试,在控制器里执行:
$module = Yii::$app->getModule('shop'); // getModule你可以理解为去配置文件的`modules`下找key为shop的模块,然后value就是类名嘛,new出来就行了 //也可以通过如下代码取得module实例 //$module = \app\modules\shop\Module::getInstance(); echo $module->interfaceUrl; // http://xxx.com/interface
模块也能加组件 ¶
模块就像一个小APP,顶层APP可以加组件,这里也可以,在配置文件中像APP那样增加components
吧,里面的内容怎么写就不啰嗦了,一下就懂
而且Module类里不需要声明components
属性,因为模块类自带这个属性,所以我那句废话又来了:APP本身就是一个继承了模块的子类啊
这里只是简单基本地介绍了模块,和官方的权威指南讲的内容差不多,要深入了解模块,你可以自己看源代码的执行流程,未来考虑写深入的模块知识