前面已经看完了启动一个yii程序所要经过的流程,以及渲染一个页面是怎么完成的。今天要分析的是yii是如何处理用户请求的。也就是控制和动作部分。
还是以helloworld为例演示这一过程。我们在地址栏输入http://localhost/study/yii/demos/helloworld/index.php,页面就显示了hello world.
前面的分析都是用的默认值,但是如果url有参数的时候,yii又是怎么处理的呢?带着这个问题,我们具体来分析一下。
在CWebApplication中有这样一行代码:
<span>$route</span>=<span>$this</span>->getUrlManager()->parseUrl(<span>$this</span>->getRequest());
这就是传说中的路由了,是不是有点小鸡冻呢?先看看getUrlManager是个神马。
<span>public</span> <span>function</span><span> getUrlManager() { </span><span>return</span> <span>$this</span>->getComponent('urlManager'<span>); }</span>
这个又要通过找关系了.
<span>public</span> <span>function</span> getComponent(<span>$id</span>,<span>$createIfNull</span>=<span>true</span><span>) { </span><span>if</span>(<span>isset</span>(<span>$this</span>->_components[<span>$id</span><span>])) </span><span>return</span> <span>$this</span>->_components[<span>$id</span><span>]; </span><span>elseif</span>(<span>isset</span>(<span>$this</span>->_componentConfig[<span>$id</span>]) && <span>$createIfNull</span><span>) { </span><span>$config</span>=<span>$this</span>->_componentConfig[<span>$id</span><span>]; </span><span>if</span>(!<span>isset</span>(<span>$config</span>['enabled']) || <span>$config</span>['enabled'<span>]) { Yii</span>::trace("Loading \"<span>$id</span>\" application component",'system.CModule'<span>); </span><span>unset</span>(<span>$config</span>['enabled'<span>]); </span><span>$component</span>=Yii::createComponent(<span>$config</span><span>); </span><span>$component</span>-><span>init(); </span><span>return</span> <span>$this</span>->_components[<span>$id</span>]=<span>$component</span><span>; } } }</span>
执行了return $this->_components[$id]; id就是传进去的urlManager,其实从这里也还看不出什么,直接找到urlManager这个类,看parseUrl:
<span>public</span> <span>function</span> parseUrl(<span>$request</span><span>) { </span><span>if</span>(<span>$this</span>->getUrlFormat()===self::<span>PATH_FORMAT) { </span><span>$rawPathInfo</span>=<span>$request</span>-><span>getPathInfo(); </span><span>$pathInfo</span>=<span>$this</span>->removeUrlSuffix(<span>$rawPathInfo</span>,<span>$this</span>-><span>urlSuffix); </span><span>foreach</span>(<span>$this</span>->_rules <span>as</span> <span>$i</span>=><span>$rule</span><span>) { </span><span>if</span>(<span>is_array</span>(<span>$rule</span><span>)) </span><span>$this</span>->_rules[<span>$i</span>]=<span>$rule</span>=Yii::createComponent(<span>$rule</span><span>); </span><span>if</span>((<span>$r</span>=<span>$rule</span>->parseUrl(<span>$this</span>,<span>$request</span>,<span>$pathInfo</span>,<span>$rawPathInfo</span>))!==<span>false</span><span>) </span><span>return</span> <span>isset</span>(<span>$_GET</span>[<span>$this</span>->routeVar]) ? <span>$_GET</span>[<span>$this</span>->routeVar] : <span>$r</span><span>; } </span><span>if</span>(<span>$this</span>-><span>useStrictParsing) </span><span>throw</span> <span>new</span> CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".', <span>array</span>('{route}'=><span>$pathInfo</span><span>))); </span><span>else</span> <span>return</span> <span>$pathInfo</span><span>; } </span><span>elseif</span>(<span>isset</span>(<span>$_GET</span>[<span>$this</span>-><span>routeVar])) </span><span>return</span> <span>$_GET</span>[<span>$this</span>-><span>routeVar]; </span><span>elseif</span>(<span>isset</span>(<span>$_POST</span>[<span>$this</span>-><span>routeVar])) </span><span>return</span> <span>$_POST</span>[<span>$this</span>-><span>routeVar]; </span><span>else</span> <span>return</span> ''<span>; }</span>
从上面的代码来看,如果我们不在url上传点东西,直接就return ''了。于是问题来了,参数要怎么传呢?
isset($_GET[$this-><span>routeVar]) <br /><br /></span>
<span>public</span> <span>$routeVar</span>='r';
于是有办法了,让我们一起来使点坏吧。加上这样的一个参数helloworld/index.php?r=abc
发现报错了。说明abc这个控制器是不存在的,事实上也是不存在的,使点小坏坏而已,正所谓男人不坏,女人不爱。
改成helloworld/index.php?r=site就可以显示hello world了,这是什么鬼原理呢?原因很简单,因为定义了site控制器嘛。
<span>class</span> SiteController <span>extends</span><span> CController { </span><span>/*</span><span>* * Index action is the default action in a controller. </span><span>*/</span> <span>public</span> <span>function</span><span> actionIndex() { </span><span>echo</span> 'Hello World'<span>; }</span><span> }</span>
好吧,这个我没有意见,但是actionIndex又是神么鬼?在yii中,这称为动作。它捕获的是控制器后面的参数,如果我们输?r=site/index就是index,动作是用“/"进行分隔的,为了验正一下我说的不是骗女孩子的鬼话,我在site控制器里加一个动作给你看一下:
<span>class</span> SiteController <span>extends</span><span> CController { </span><span>/*</span><span>* * Index action is the default action in a controller. </span><span>*/</span> <span>public</span> <span>function</span><span> actionIndex() { </span><span>echo</span> 'Hello World'<span>; } </span><span>public</span> <span>function</span><span> actionView() { </span><span>echo</span> 'Hello View'<span>; } }</span>
访问?r=site/view的时候,是不是看到输出'Hello View'了呢?肯定是的,虽然我读的书少,但是你骗不了我的,有图有真相:
我一点儿也不喜欢用site这个名字,test才是我的最爱,于是我又建了一个test控制器来尝试一下。
眼尖的一定看到怎么写了一个actions,这是什么鬼?我也是刚试了才知道,它其实是另一种表示方式。
我记得在blog那个例子中有用过,用来显示验证码:
<span>/*</span><span>* * Declares class-based actions. </span><span>*/</span> <span>public</span> <span>function</span><span> actions() { </span><span>return</span> <span>array</span><span>( </span><span>//</span><span> captcha action renders the CAPTCHA image displayed on the contact page</span> 'captcha'=><span>array</span><span>( </span>'class'=>'CCaptchaAction', 'backColor'=>0xFFFFFF,<span> )</span>, <span>//</span><span> page action renders "static" pages stored under 'protected/views/site/pages' // They can be accessed via: index.php?r=site/page&view=FileName</span> 'page'=><span>array</span><span>( </span>'class'=>'CViewAction',<span> )</span>,<span> ); }</span>
我把它理解为集中声明第三方业务的动作集合,因为本控制器内的动作,我觉得还是action+ID 的方式直接。
什么鬼?你说我用的是index.php/site/captcha 而不是index.php?r=site/captcha .这又得从配置文件说起。
'urlManager'=><span>array</span><span>( </span>'urlFormat'=>'path', 'rules'=><span>array</span><span>( </span>'post/<id:\d+>/<title:.*?>'=>'post/view', 'posts/<tag:.*?>'=>'post/index', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',<span> )</span>,<span> )</span>,
urlFormat 有path 和 get两种,如果在main.php中没有指定,那么就是get方式,也就是index.php?r=site/captcha这种。如果指定了,即index.php/site/captcha这种
从字面上也很好理解,path就是像路径的格式,get就是?这种形式。
关于路由和控制器部分的内容还有很多,但是本节就到这里了。