module是对相同业务逻辑的app中的内容模块化,比如博客前台系统可以模块化成blog,博客后台系统可以模块化成admin,模块化便于对应用的管理扩展。
加载module的配置
//加载框架中自带gii模块和一个自定义admin模块 'modules'=>array( // uncomment the following to enable the Gii tool 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'111111', // If removed, Gii defaults to localhost only. Edit carefully to taste. 'ipFilters'=>array('127.0.0.1','::1'), ), 'admin' ),
//应用初始化配置时通过CModule::setModules()来配置模块 public function setModules($modules) { foreach($modules as $id=>$module) { if(is_int($id)) { $id=$module; $module=array(); } if(!isset($module['class'])) { Yii::setPathOfAlias($id,$this->getModulePath().DIRECTORY_SEPARATOR.$id); $module['class']=$id.'.'.ucfirst($id).'Module'; } if(isset($this->_moduleConfig[$id])) $this->_moduleConfig[$id]=CMap::mergeArray($this->_moduleConfig[$id],$module); else $this->_moduleConfig[$id]=$module; } }定位模块
CWebApplication: //路由分发,定位模块和模块下的controller public function createController($route,$owner=null) { if($owner===null) $owner=$this; if(($route=trim($route,'/'))==='') $route=$owner->defaultController; $caseSensitive=$this->getUrlManager()->caseSensitive; $route.='/'; while(($pos=strpos($route,'/'))!==false) { $id=substr($route,0,$pos); if(!preg_match('/^\w+$/',$id)) return null; if(!$caseSensitive) $id=strtolower($id); $route=(string)substr($route,$pos+1); if(!isset($basePath)) // first segment { if(isset($owner->controllerMap[$id])) { return array( Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner), $this->parseActionParams($route), ); } if(($module=$owner->getModule($id))!==null) /* 如果找到module,再次调用本方法, 注意这个时候的第二个参数ower不再是CWebApplication或其子类,而是CWebModule子类 这对获取控制器和视图的默认路径很重要,CWebModule控制器路径是相应module下面的 */ return $this->createController($route,$module); $basePath=$owner->getControllerPath(); $controllerID=''; } else $controllerID.='/'; $className=ucfirst($id).'Controller'; $classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php'; if(is_file($classFile)) { if(!class_exists($className,false)) require($classFile); if(class_exists($className,false) && is_subclass_of($className,'CController')) { $id[0]=strtolower($id[0]); return array( new $className($controllerID.$id,$owner===$this?null:$owner), $this->parseActionParams($route), ); } return null; } $controllerID.=$id; $basePath.=DIRECTORY_SEPARATOR.$id; } }
CWebModule: /** * Retrieves the named application module. 查找模块 * The module has to be declared in {@link modules}. A new instance will be created * when calling this method with the given ID for the first time. * @param string $id application module ID (case-sensitive) * @return CModule the module instance, null if the module is disabled or does not exist. */ public function getModule($id) { if(isset($this->_modules[$id]) || array_key_exists($id,$this->_modules)) return $this->_modules[$id]; else if(isset($this->_moduleConfig[$id])) { $config=$this->_moduleConfig[$id]; if(!isset($config['enabled']) || $config['enabled']) { Yii::trace("Loading \"$id\" module",'system.base.CModule'); $class=$config['class']; unset($config['class'], $config['enabled']); if($this===Yii::app()) $module=Yii::createComponent($class,$id,null,$config); else $module=Yii::createComponent($class,$this->getId().'/'.$id,$this,$config); return $this->_modules[$id]=$module; } } }模块里有一个CWebModule的子类重载CWebModule的一些方法,通过int()导入模块中要导入的路径,通过 beforeControllerAction($controller, $action)和afterControllerAction($controller, $action)实现动作执行前后钩子的添加。
class AdminModule extends CWebModule { public function init() { // this method is called when the module is being created // you may place code here to customize the module or the application // import the module-level models and components $this->setImport(array( 'admin.models.*', 'admin.components.*', )); } public function beforeControllerAction($controller, $action) { if(parent::beforeControllerAction($controller, $action)) { // this method is called before any module controller action is performed // you may place customized code here return true; } else return false; } }