ZendFramework中的路由器(router)究竟能做什么

有时候,可能会无意中浏览到有的网站,发它们的URL设计的很接近于自然语言,即很符合语意思。例如,当我们去一个博客网站申请一个博客时,一般情况下都会有一个功能,可以设置个性化域名,本来正常情况下,当一个用户登录系统后的URL地址是http://blog.xx.com?id=34或者http://blog.xx.com?username=hqlong,但由于这样URL结构复杂,增加了用户的记忆难度,所以系统会提供一个个性化域名设计功能,让用户自己去设计便于自己记忆的域名,最好我就设计出一个便于我记忆的博客地址http://blog.xx.com/hqlong或者http://blog.xx.com/author/hqlong.

这样是不是感觉上这地址符合语意多了,当然也就更容易让人记住。

又比如,为了页面更容易搜索引擎检索到,我们需要对URL进行优化,常见的就是把所有地址以静态页面的形式访问(伪静态).。

如用PHP编写的一个系统,一个文章的地址可能是http://hqlong.com/detail.php?postid=34,那么我们为了让搜索引擎更好的收录我的文章,所以我需要对这个地址进行优化(当然,目前我还没有对我的博客的URL进行优化),优化后这篇文章的访问地址就变成了http://hqlong.com/blog/34.html或者http://hqlong.com/blog_34.html。

是不是突然感到这技术很有意思。

是的,这技术确实很有意思,而且目前也很流行。

那么该技术是怎么实现的呢?

这就是今天要谈的zendframework的router,它就能帮我们完成上述功能.

router的功能就是能让我们动态个性化的设计我们所需要的URL地址,它可以让我们所访问的URL地址去访问直接的controller的action.

当然这一些都需要建立在APACHE的rewrite模块被打开的情况下,并且要在.htaccess文件中,打开重写引擎。不过这一点似乎不需要担心,既然你都在使用zf的控制器了,我想,这一些设置也应该都设置好了。

我们先来看一下router是怎么被使用的。(以下例子基本上引用至官方手册)

 

<?php
/* Create a router */
$router = $front_controller->getRouter(); // returns a rewrite router by default
$router->addRoute(
    'user',
    new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info'))
);

首先我们需要或能通过前端控制器的getRouter()方法来得到路由对象,然后我们通过addRouter来增加一个路由规则。

注意:第二个参数是传递一个路由规则对象,这个对象表示我们需要创建一个什么样的URL地址,而这个URL地址和哪个controller中的action有关。

上面的路由器完成的功能就是,当我们输入http://xx.com/user/hqlong这个重写后的地址里,实现上他访问的是user/info/username/hqlong

即:访问user这个controller下的info,并且传递了username=hqlong这个参数。

那么在info中, 我们可能通过

$this->_getParam('username')

来获取用户名的值 。

对于上面的地址,确定比较形象直观,但如果能更短一些,就太完美了,如果访问hqlong的博客,如果能通过http://blog.xx.com/hqlong来访问,就太好了,人呢?就这样,始终永远不能被完全满足,那行吧,今天就让我用router来满足一回大家。

如果要实现上面的路由,那么我们的路由器就应该向下面这样的设置。

 

<?php
$router = $front_controller->getRouter();
$router->addRoute(
    'user',
    new Zend_Controller_Router_Route(':username', array())
);

 

现在就可以通过http://blog.xx.com/hqlong来访问我的博客了,但如果仔细观察上面两块代码就会发现,第一块代码中有影射的控制器,最二块代码中没有,那么这个请求将由谁来接收呢?

首先说明一下路由规则对象的第一个参数。user/:username,这个参数中/前面的部分为不变部分,而;后面的为可变部分,即后面的部分为传递的参数信息。

对于影射的问题,如果在规则中没有指定相关的controller和action,那么该路由将会被分发到系统默认的controllr和action,也就说访问http://blog.xx.com/hqlong时,由IndexController中的indexAction去处理该请求。

从 前面的例子中,会发现其中有变量,也就是说这个地址是一个可变以的地址,可能是blog.xx.com/hqlong也可以是blog.xx.com/aux,如果在进行URL重写时,我们只是想把一个段地址用另外一个地址来代替,而并不想向其中传递什么参数的情况。当然,上面的方法完全可以解决这个需求,但大家都知道,要处理动址后的变量,必定会使用一些匹配的方法来处理,所以在效率,可能不会被大多数同行所看好,对于这种情况,我们可以使用ZF给我们提供的静态路由来解决。

当我们只是想把http://blog.xx.com/auth/login这个地址重写成http://blog.xx.com/login时,路由实现如下:

 

<?php
$route = new Zend_Controller_Router_Route_Static(
    'login',
    array('controller' => 'auth', 'action' => 'login')
);
$router->addRoute('login', $route);

注意:上面的是通过Zend_Controller_Router_Route_Static这个类来创建的对象,而不是Zend_Controller_Router_Route这个类。

好像在前面我说了一个伪静态的例子,对一个url进行静态化,由于对博客的日志文章的重写时,必然会有一个能识别该日志和其它日志不同的标题,所以这进我们所面对的需求是一个随时变动的地址,同样,对于这样情况,zf也给我们提供了解决方案,就是使用里面所提供的正则类(Zend_Controller_Router_Route_Regex)来创建。

需求:通过http://hqlong.com/blog_343.shtml替代http://hqlong.com/post/detail?postid=343。

实现如下:

 

<?php
$route = new Zend_Controller_Router_Route_Regex(
    'blog_(\d+)\.shtml',
    array('controller'=>'post','action'=>'detail'),
    array('postid' => 1),
    'blog_/%s.shtml'
);

对于第三个参数说明:如果我们没有设置该参数的话,那么我们只能够通过$this->_getParam(1)来访问所匹配的ID号,当然这样也可以,但似乎使用数字来有些不保险,所以需要设置一个替换的别名。即或能通过$this->_getParam(‘postid’)来访问。

好了,今晚晚班,快下班了。大致就这样吧,如果有什么疑问,或者设置有什么不成功的地主,我们可以进行讨论。

参考资料:ZendFramework的参考文档

机器人 2008-4-3 21:00 于 北京

此条目发表在 LAMP 分类目录,贴了 , , , , 标签。将固定链接加入收藏夹。

ZendFramework中的路由器(router)究竟能做什么》有 2 条评论

  1. 小黑米 说:

    恩 非常好 以前看不懂的现在看懂了 谢谢小龙哦~
    还有 我的友情链接写错啦~
    呵呵 blog.phpexp.cn

  2. 机器人 说:

    好的,已经改过来了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>