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' ), ); }过滤器
执行动作
再返回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; }