加载中...

YII框架分析笔记5:控制器和动作


CBaseController是控制器和挂件的基类,主要提供了视图渲染,挂件,剪辑、片段缓存等方法,CController是所有应用中自定义控制器的基类。

创建动作

public function run($actionID)
{
	if(($action=$this->createAction($actionID))!==null)
	{
		if(($parent=$this->getModule())===null)
			$parent=Yii::app();
		if($parent->beforeControllerAction($this,$action))
		{
			$this->runActionWithFilters($action,$this->filters());
			$parent->afterControllerAction($this,$action);
		}
	}
	else
		$this->missingAction($actionID);
}

控制器的调用从CWebApplication执行runController()起,通过路由找到控制器和动作id,初始化控制器实例,然后执行$controller->run($actionID),通过actionId创建动作对象(预留beforeControllerAction和afterControllerAction钩子)。
如果动作方法存在于控制器中并且不是actions(),会创建一个CInlineAction对象,否则通过actions()中会返回外部动作的关联数组射找到外部动作对象,这个好处是可以共用一些同样的动作,比如下面curd动作代码,通过http://www.test.com/index.php?r=post/read就可以通过外部ReadAction对象读取post

class PostController extends Controller
{
	function actions(){
		return array(
			'create' => array(
				'class'		 => 'application.actions.CreateAction',
				'modelClass' => 'Post',
			),
			'update' => array(
				'class'		 => 'application.actions.UpdateAction',
				'modelClass' => 'Post',
			),
			'read' => array(
				'class'		 => 'application.actions.ReadAction',
				'param'		 => 'Postid', 
				'modelClass' => 'Post',
			),			
			'delete' => array(
				'class'		 => 'application.actions.DeleteAction',
				'modelClass' => 'Post',
			)
		);
	}
}
在actions()中还可以指定CViewAction对象,它其实就是YII框架写的一个调用外部动作的一个扩展。如下面代码可以按照用户指定的参数显示一个视图,通过GET参数来定位视图文件,这样对加载静态内容而又不用单独写动作方法很有帮助。
public function actions()
{
    return array(
        'page'=>array(
            'class'=>'CViewAction',
			'basePath' => '$path',
			'defaultView '=> '$view'
        ),
    );
}
过滤器
在创建完Action对象后,现在又返回到CController接着执行过滤动作(预留beforeControllerAction和afterControllerAction钩子),此时会加载过滤器,控制器通过CController::filters()方法返回过滤器配置关联数组,和验证器相似,过滤器可以在控制器内部定义(方法名必须以filter开头)也可以自定义过滤器类继承CFilter扩展preFilter()和postFilter()方法, 如框架中自带的授权验证CAccessControlFilter。

执行动作
再返回CController执行动作(预留beforeAction和afterAction钩子),进入CActon子类(以CInlineAction为例)中执行runWithParams($params)方法通过php反射判断控制器中的动作方法是不是需要参数
1、如果需要参数执行runWithParamsInternal()方法,通过反射获取动作方法中的参数和值得键值对数组(写API经常用的方法),并执行动作方法
2、如果不要参数执行run()方法定位到控制器的动作中

/**
 * Runs the action with the supplied request parameters.
 * This method is internally called by {@link CController::runAction()}.
 * @param array $params the request parameters (name=>value)
 * @return boolean whether the request parameters are valid
 * @since 1.1.7
 */
public function runWithParams($params)
{
	$methodName='action'.$this->getId();
	$controller=$this->getController();
	$method=new ReflectionMethod($controller, $methodName);
	if($method->getNumberOfParameters()>0)
		return $this->runWithParamsInternal($controller, $method, $params);
	else
		return $controller->$methodName();
}
/**
 * Executes a method of an object with the supplied named parameters.
 * This method is internally used.
 * @param mixed $object the object whose method is to be executed
 * @param ReflectionMethod $method the method reflection
 * @param array $params the named parameters
 * @return boolean whether the named parameters are valid
 * @since 1.1.7
 */
protected function runWithParamsInternal($object, $method, $params)
{
	$ps=array();
	foreach($method->getParameters() as $i=>$param)
	{
		$name=$param->getName();
		if(isset($params[$name]))
		{
			if($param->isArray())
				$ps[]=is_array($params[$name]) ? $params[$name] : array($params[$name]);
			else if(!is_array($params[$name]))
				$ps[]=$params[$name];
			else
				return false;
		}
		else if($param->isDefaultValueAvailable())
			$ps[]=$param->getDefaultValue();
		else
			return false;
	}
	$method->invokeArgs($object,$ps);
	return true;
}








还没有评论.