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






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章