加载中...

YII框架分析笔记11:模块module


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;
	}
}
定位模块
由module[/controller/action]获取路由中第一个"/"前字符串(必须是只含字母,否则抛出404错误)假定是模块id,根据模块id判断如果存在该id的模块或者存在该id的模块配置,则返回模块,由代码分析可以知道如果禁用一个模块很简单,只需在主配置文件中加上'enabled' => false就可。

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;
	}
}







还没有评论.