
4.4 创建文章详细信息页面
在News首页,文章标题应是一个超链接,单击后可以进入文章详细页面,显示文章的详细信息。为此我们将创建一个文章详细信息页面,取出该文章的模型方法就用getPage。至于控制器,可以在现有的NewsController控制器里添加一个detail方法,但考虑到除News频道页面外,其他的频道页面也会大量用到detail页面,所以我们创建一个PageController,在其中创建一个detail,作为公用的文章详情页面,相应地,视图会用/page/detail.phtml。
先对news/index.phtml视图部分加以完善,把即将要创建的page/detail页面作为超链接目标地址,后面再附上名为id的参数,这个参数会通过URL以get方式提交,以供PageController.php获得,然后作为getPage方法的参数传给模型,以查询到该文章。
application/views/scripts/partials/row-news.phtml <ul> <li><a href = "/page/detail/id/<?php echo $this->id; ?>"><?php echo$this->title; ?></a> </li> </ul>
4.4.1 创建PageController控制器并添加detail方法
现在来创建PageController控制器:
zf create controller Page
紧接着在PageController控制器中创建detail方法:
zf create action detail Page
然后打开application/controllers/PageController.php,在detailAction方法中编写代码:
application/controllers/PageController.php public function detailAction() { $id = $this->_request->getParam('id'); $modelPage = new Kh_Model_Page($id); $page = $modelPage->getPage($id); $this->view->page = $page; }
$this->_request->getParam('id')会获取到news/index.phtml视图通过get方式传递的URL参数id的值。
现在又有了点小问题:按照之前的模型设计,我们应该在getPage方法中传入数组作为参数,所以查询条件应该写成$where = array('id'=>$id)才符合要求。没错,但做一件事情,总是可能会出现另一种方法供我们选择。对于知道主键id号的数据,数据库有一个更高效的查询方法find(),我们打算把它也用起来,所以在这里直接传入id号作为参数,然后相应地对getPage方法也要做一些改进。
下面继续改进Page模型的getPage方法。
我们把哆啦A梦拆开来,对它进行更进一步的加工,使其智能不断提升。
application/models/Page.php // 获取页面 public function getPage($where = null) { if (is_numeric($where)){ $row = $this->find($where)->current(); } if (is_array($where) & count($where) > 0){ $select = $this->select(); foreach ($where as $key=>$value){ $select->where($key. ' = ?', $value); } $row = $this->fetchRow($select); } if($row){ return $row; } else { return null; } }
如果$where是一个主键id,$this->find($where)->current()会非常干净利落地找到它那一行数据!经过改进的getPage方法更加强大了,现在传入的参数既可以是数组,也可以是一个数字类型的id号。如果没有参数传进来,它返回空值,以确保控制器因得不到回应而显示错误。
4.4.2 创建detail页面视图
实际上用ZF tool在Page控制器中创建detail方法时,detail的默认视图就已经创建好了,我们要做的只是修改一下。打开application/views/scripts/page/detail.phtml,将其中的内容清空,写入以下代码:
application/views/scripts/page/detail.phtml <?php echo "<h2>".$this->page->title."</h2>"; echo "<span>发表于:".date('Y-m-d',$this->page->createtime)."</span>"; echo "<span>更新于:".date('Y-m-d',$this->page->updatetime)."</span>"; echo "<hr />"; echo $this->page->body;
去浏览器里试一下,文章详情页面出来了。因为数据库中添加示例数据时没有填发表时间和更新时间这两个字段的值,它们默认是0,所以经date函数处理后,显示为UNIX纪元初始的1970年1月1日。
4.4.3 在detail页面添加其他文章的链接
如果不想让detail页面只显示一篇孤零零的文章,那就像News首页那样,放一个其他文章的标题列表在下面吧!运用我们所学过的知识,只需区区几行代码,就可以轻松做到。
1.控制器
在Page控制器中获取文章列表,并输出到视图:
application/controllers/PageController.php public function detailAction() { $id = $this->_request->getParam('id'); $modelPage = new Kh_Model_Page(); $page = $modelPage->getPage($id); $this->view->page = $page; // 其他新闻文章列表 $where = "id != ".$id; $pages = $modelPage->getPages($where); $this->view->pages = $pages->toArray(); }
什么? "$where = "id != ".$id"!查询条件是个字符串?没办法,这个页面是这位id的地盘,它已经全须全尾地在上头了,下面的列表里当然不能再重复放上它,所以要设个条件把它从查询里踢出去。这没什么不好理解的,只是你应该意识到,可怜的哆啦A梦又得被拆开,重新改造一番了。
2.模型
拆开哆啦A梦,不能简单地把$where仅当成数组了,它已经可以是字符串,所以我们不再预定义它为array(),把它的默认值改为null,然后让它学会新的判断:如果$where是字符串,就直接把字符串当成命令;如果$where是数组并且其键值对数量大于0,那么就按占位符的老方法,把条件循环加进去。
application/models/Page.php // 获取页面列表 public function getPages($where=null, $order=null, $limit=null) { $select = $this->select(); if (is_string($where)){ $select->where($where); } if(is_array($where) & count($where) > 0){ foreach($where as $key=>$value){ $select->where($key.'=?', $value); } } if($order){ $select->order($order); } if($limit){ $select->limit($limit); }
现在应该大功告成了!你肯定和我一样,希望不要拆可怜的哆啦A梦了。的确,有了刚开始的这些经验,以后我们设计模型时,会在开始时就考虑得越来越周全,不过模型也不怕拆拆装装啊,明白了原理也挺简单的,又不怕拆坏,因为Zend Framework的MVC耦合度很低,怎么折腾对其他页面影响都不大。
3.视图
在视图中渲染结果:
application/views/scripts/page/detail.phtml <?php echo "<h2>".$this->page->title."</h2>"; echo "<span>发表于:".date('Y-m-d',$this->page->createtime)."</span>"; echo "<span>更新于:".date('Y-m-d',$this->page->updatetime)."</span>"; echo "<hr />"; echo $this->page->body; echo "<h3>其他新闻</h3>"; if ($this->pages){ echo $this->partialLoop('partials/row-pages.phtml', $this->pages); }
记得前面说过,partialLoop视图助手可以帮我们省不少事儿,看到了吧,视图得到对象后,掂了掂分量直接把它扔到partialLoop里循环去了。
现在打开http://kehuan.edu/page/detail/id/3,可以看到在文章页面的下面又输出了其他新闻文章的列表。