我直的很懒,由于大概流程我已搞懂,我也懒得一步步分析了,转载吧。
6、$config 之 import
其中 import 被传递给 CModule 的 setImport:
1. public function setImport( $aliases)
2. {
3. foreach( $aliases as $alias)
4. Yii::import( $alias);
5. }
Yii::import( $alias)里的处理:
1. public static function import( $alias, $forceInclude= false)
2. {
3. // 先判断$alias是否存在于YiiBase::$_imports[] 中,已存在的直接return, 避免重复import。
4. if( isset(self:: $_imports[ $alias])) // previously imported
5. return self:: $_imports[ $alias];
6.
7. // $alias类已定义,记入$_imports[],直接返回
8. if( class_exists( $alias, false))
9. return self:: $_imports[ $alias]= $alias;
10.
11. // 类似 urlManager 这样的已定义于$_coreClasses[]的类,或不含.的直接类名,记入$_imports[],直接返回
12. if( isset(self:: $_coreClasses[ $alias]) || ( $pos= strrpos( $alias,'.'))=== false) // a simple class name
13. {
14. self:: $_imports[ $alias]= $alias;
15. if( $forceInclude)
16. {
17. if( isset(self:: $_coreClasses[ $alias])) // a core class
18. require(YII_PATH.self:: $_coreClasses[ $alias]);
19. else
20. require( $alias.'.php');
21. }
22. return $alias;
23. }
24.
25. // 产生一个变量 $className,为$alias最后一个.后面的部分
26. // 这样的:'x.y.ClassNamer'
27. // $className不等于 '*', 并且ClassNamer类已定义的, ClassNamer' 记入 $_imports[],直接返回
28. if(( $className=( string) substr( $alias, $pos+1))!=='*' && class_exists( $className, false))
29. return self:: $_imports[ $alias]= $className;
30.
31. // 取得 $alias 里真实的路径部分并且路径有效
32. if(( $path=self::getPathOfAlias( $alias))!== false)
33. {
34. // $className!=='*',$className 记入 $_imports[]
35. if( $className!=='*')
36. {
37. self:: $_imports[ $alias]= $className;
38. if( $forceInclude)
39. require( $path.'.php');
40. else
41. self:: $_classes[ $className]= $path.'.php';
42. return $className;
43. }
44. // $alias是'system.web.*'这样的已*结尾的路径,将路径加到include_path中
45. else // a directory
46. {
47. set_include_path( get_include_path().PATH_SEPARATOR. $path);
48. return self:: $_imports[ $alias]= $path;
49. }
50. }
51. else
52. throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
53. array('{alias}'=> $alias)));
54. }
7. $config 之 components
$config 数组里的 $components 被传递给CModule 的setComponents( $components)
1. public function setComponents( $components)
2. {
3. foreach( $components as $id=> $component)
4. {
5. if( $component instanceof IApplicationComponent)
6. $this->setComponent( $id, $component);
7. else if( isset( $this->_componentConfig[ $id]))
8. $this->_componentConfig[ $id]=CMap::mergeArray( $this->_componentConfig[ $id], $component);
9. else
10. $this->_componentConfig[ $id]= $component;
11. }
12. }
$componen是IApplicationComponen的实例的时候,直接赋值:
$this->setComponent( $id, $component),
1. public function setComponent( $id, $component)
2. {
3. $this->_components[ $id]= $component;
4. if(! $component->getIsInitialized())
5. $component->init();
6. }
如果 $id已存在于_componentConfig[]中(前面注册的coreComponent),将 $component 属性加进入。
其他的component将component属性存入_componentConfig[]中。
1. public function setImport( $aliases)
2. {
3. foreach( $aliases as $alias)
4. Yii::import( $alias);
5. }
Yii::import( $alias)里的处理:
1. public static function import( $alias, $forceInclude= false)
2. {
3. // 先判断$alias是否存在于YiiBase::$_imports[] 中,已存在的直接return, 避免重复import。
4. if( isset(self:: $_imports[ $alias])) // previously imported
5. return self:: $_imports[ $alias];
6.
7. // $alias类已定义,记入$_imports[],直接返回
8. if( class_exists( $alias, false))
9. return self:: $_imports[ $alias]= $alias;
10.
11. // 类似 urlManager 这样的已定义于$_coreClasses[]的类,或不含.的直接类名,记入$_imports[],直接返回
12. if( isset(self:: $_coreClasses[ $alias]) || ( $pos= strrpos( $alias,'.'))=== false) // a simple class name
13. {
14. self:: $_imports[ $alias]= $alias;
15. if( $forceInclude)
16. {
17. if( isset(self:: $_coreClasses[ $alias])) // a core class
18. require(YII_PATH.self:: $_coreClasses[ $alias]);
19. else
20. require( $alias.'.php');
21. }
22. return $alias;
23. }
24.
25. // 产生一个变量 $className,为$alias最后一个.后面的部分
26. // 这样的:'x.y.ClassNamer'
27. // $className不等于 '*', 并且ClassNamer类已定义的, ClassNamer' 记入 $_imports[],直接返回
28. if(( $className=( string) substr( $alias, $pos+1))!=='*' && class_exists( $className, false))
29. return self:: $_imports[ $alias]= $className;
30.
31. // 取得 $alias 里真实的路径部分并且路径有效
32. if(( $path=self::getPathOfAlias( $alias))!== false)
33. {
34. // $className!=='*',$className 记入 $_imports[]
35. if( $className!=='*')
36. {
37. self:: $_imports[ $alias]= $className;
38. if( $forceInclude)
39. require( $path.'.php');
40. else
41. self:: $_classes[ $className]= $path.'.php';
42. return $className;
43. }
44. // $alias是'system.web.*'这样的已*结尾的路径,将路径加到include_path中
45. else // a directory
46. {
47. set_include_path( get_include_path().PATH_SEPARATOR. $path);
48. return self:: $_imports[ $alias]= $path;
49. }
50. }
51. else
52. throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
53. array('{alias}'=> $alias)));
54. }
7. $config 之 components
$config 数组里的 $components 被传递给CModule 的setComponents( $components)
1. public function setComponents( $components)
2. {
3. foreach( $components as $id=> $component)
4. {
5. if( $component instanceof IApplicationComponent)
6. $this->setComponent( $id, $component);
7. else if( isset( $this->_componentConfig[ $id]))
8. $this->_componentConfig[ $id]=CMap::mergeArray( $this->_componentConfig[ $id], $component);
9. else
10. $this->_componentConfig[ $id]= $component;
11. }
12. }
$componen是IApplicationComponen的实例的时候,直接赋值:
$this->setComponent( $id, $component),
1. public function setComponent( $id, $component)
2. {
3. $this->_components[ $id]= $component;
4. if(! $component->getIsInitialized())
5. $component->init();
6. }
如果 $id已存在于_componentConfig[]中(前面注册的coreComponent),将 $component 属性加进入。
其他的component将component属性存入_componentConfig[]中。
8. $config 之 params
这个很简单
1. public function setParams( $value)
2. {
3. $params= $this->getParams();
4. foreach( $value as $k=> $v)
5. $params->add( $k, $v);
6. }
configure 完毕!
9. attachBehaviors
$this->attachBehaviors( $this->behaviors);
空的,没动作
预创建组件对象
1. $this->preloadComponents();
2.
3. protected function preloadComponents()
4. {
5. foreach( $this->preload as $id)
6. $this->getComponent( $id);
7. }
getComponent() 判断_components[] 数组里是否有 $id的实例,如果没有,就根据_componentConfig[ $id]里的配置来创建组件对象,调用组件的init()方法,然后存入_components[ $id]中。
10. init()
this->init();
函数内: $this->getRequest();
创建了Reques 组件并初始化。
11. run()
1. public function run()
2. {
3. $this->onBeginRequest( new CEvent( $this));
4. $this->processRequest();
5. $this->onEndRequest( new CEvent( $this));
6. }
三 大概过程
application构造函数:
1 设置当前运行实例
2 获取配置参数
3 设置basepath
4 设置几个path;application,webroot ,ext
5 preinit
6 注册error、exception处理函数 initSystemHandlers
7 加载核心组件 registerCoreComponents 包括webapplication的和application的
8 设置配置文件 configure( $config)
9 附加行为 $this->attachBehaviors( $this->behaviors);
10处理加载config中的preload, // 通过getComponent分别加载并初始化 $this->preloadComponents();
11 初始化init(); // 加载CHttpRequest组件
run:
1 处理onBeginRequest
2 processRequest();真正处理请求
3 处理onEndRequest
webapplication->processRequest():
1 如果配置文件设置了catchAllRequest , // 'catchAllRequest'=>array('site/error','p1'=>'1','p2'=>'2'),
则所有请求都跳转到这个controller/action这个route,并且设置 $_GET参数。
2 分析url得到route,便于后面的控制器/动作创建
3 执行runController
runController:
1 创建controller, createController(),创建失败,则抛出404错误
2 得到controller对象和actionID
3 控制器初始化 $controller->init();
4 最后执行 $controller->run( $actionID); // 真正执行页面请求
控制器类
CController:默认控制器在CWebApplication::defaultController定义('site'),可以在配置文件修改
run():
1 // 根据actionID创建action对象,这里生成的action对象分为定义在controller内联动作和自定义action,比如CViewAction
$action= $this->createAction( $actionID),如果创建动作失败,missingAction抛出404错误
2 beforeControllerAction(beforeControllerAction定义在CWebApplication,有时也在module里面)为真,才执行runActionWithFilters;
3 afterControllerAction
runActionWithFilters( $action, $this->filters()):
1 // 如果过滤器为空,直接运行runAction()
2 执行过滤器链
runAction():
1 beforeAction()返回真,才执行
2 执行 $action->runWithParams();注意:这里存在多态,每个action都可以实现这个方法, 因为CInlineAction自己实现了runWithParams()
3 第2步骤为真,才执行afterAction( $action);
动作类 默认动作在CController:: $defaultAction定义('index'),可以在CController的继承类重新定义
runWithParams():
1 分为2种情况,1种是内联动作,1种是通过控制器的actions方法定义的外联动作。
2 内联动作 通过action+动作id作为动作处理函数
3 外联动作 通过调用run()函数来实现
4 如果动作方法参数个数大于0,执行runWithParamsInternal,否则直接执行动作方法。
runWithParamsInternal();
1 根据反射的方法对象得到方法的形参列表,从 控制器对象->getActionParams()得到实参,
如果实参有形参要求的参数,取其值,不然取形参默认值,否则,出错。
2 调用动作方法 2种形式 1是action+动作id ,2是Caction的派生类(比如cviewaction)的run()
3 执行控制器的CController->render方法; $controller->render( $view)
控制器类
CController:
render();
1 renderPartial();得到视图, // 先得到contact页面的view文件内容,注意是用include的形式,所以其中的$this是指siteControlerd对象,
这里调用了renderFile();
2 然后 $output= $this->renderFile( $layoutFile, array('content'=> $output), true)
把view中的内容插入到布局页面layouts的column1.php, 'content'和layout的页面的 $content变量相关
renderFile();
1 如果程序没有定义viewrender,则执行controller->renderInternal();否则,执行 $renderer=Yii::app()->getViewRenderer())->renderFile();
view sourceprint?发生404错误
errorHandler 在配置文件main中,'errorAction' => 'site/error',
**********************************************************
runActionWithFilters
过滤:
CFilterChain(继承CList,提供数字索引存取功能,遍历)::create( $this, $action, $filters)->run();
首先创建过滤链,然后执行过滤
CFilterChain::create( $controller, $action, $filters):
1 $chain= new CFilterChain( $controller, $action);创建一个过滤链 $chain
2 根据参数filters数组,遍历创建过滤器 $filter(字符串:通过CInlineFilter::create或者 数组:Yii::createComponent),
并且初始化 $filter::init,通过 $chain->add( $filter)添加到过滤链中,并且返回这个过滤链 $chain
注意:如果是字符串,控制器类controller必须要有"filter"+过滤器名的方法。
$chain::run();
1 如果数字索引合法,得到 $filter,然后执行 $filter->filter( $this);
1.1 $filter->filter( $this):
1 执行动作的'filter'+过滤器名称的方法。 // 比如CController::filterAccessControl($filterChain);
1.1.1 CController::filterAccessControl( $filterChain):
1 $filter= new CAccessControlFilter; // 新建过滤器
2 $filter->setRules( $this->accessRules()); // 设置规则
3 $filter->filter( $filterChain) ; // 执行过滤
4 $filter->preFilter( $filterChain)为真,继续执行 $filterChain->run();
5 $filter->postFilter( $filterChain); // 这个是在动作执行之后过滤
2 否则,说明过滤完毕, $this->controller->runAction( $this->action); 直接执行动作。
CController:
render();
1 renderPartial();得到视图, // 先得到contact页面的view文件内容,注意是用include的形式,所以其中的$this是指siteControlerd对象,
这里调用了renderFile();
2 然后 $output= $this->renderFile( $layoutFile, array('content'=> $output), true)
把view中的内容插入到布局页面layouts的column1.php, 'content'和layout的页面的 $content变量相关
renderFile();
1 如果程序没有定义viewrender,则执行controller->renderInternal();否则,执行 $renderer=Yii::app()->getViewRenderer())->renderFile();
view sourceprint?发生404错误
errorHandler 在配置文件main中,'errorAction' => 'site/error',
**********************************************************
runActionWithFilters
过滤:
CFilterChain(继承CList,提供数字索引存取功能,遍历)::create( $this, $action, $filters)->run();
首先创建过滤链,然后执行过滤
CFilterChain::create( $controller, $action, $filters):
1 $chain= new CFilterChain( $controller, $action);创建一个过滤链 $chain
2 根据参数filters数组,遍历创建过滤器 $filter(字符串:通过CInlineFilter::create或者 数组:Yii::createComponent),
并且初始化 $filter::init,通过 $chain->add( $filter)添加到过滤链中,并且返回这个过滤链 $chain
注意:如果是字符串,控制器类controller必须要有"filter"+过滤器名的方法。
$chain::run();
1 如果数字索引合法,得到 $filter,然后执行 $filter->filter( $this);
1.1 $filter->filter( $this):
1 执行动作的'filter'+过滤器名称的方法。 // 比如CController::filterAccessControl($filterChain);
1.1.1 CController::filterAccessControl( $filterChain):
1 $filter= new CAccessControlFilter; // 新建过滤器
2 $filter->setRules( $this->accessRules()); // 设置规则
3 $filter->filter( $filterChain) ; // 执行过滤
4 $filter->preFilter( $filterChain)为真,继续执行 $filterChain->run();
5 $filter->postFilter( $filterChain); // 这个是在动作执行之后过滤
2 否则,说明过滤完毕, $this->controller->runAction( $this->action); 直接执行动作。