代码: ...
Zend_Loader::loadClass('Zend_Controller_Front'); Zend_Loader::loadClass('Zend_Config_Ini'); Zend_Loader::loadClass('Zend_Registry'); Zend_Loader::loadClass('Zend_Db');
Zend_Loader::loadClass('Zend_Db_Table'); // 加载配置
$config = new Zend_Config_Ini('./application/config.ini', 'general'); $registry = Zend_Registry::getInstance(); $registry->set('config', $config); // 设置数据库
$db = Zend_Db::factory($config->db->adapter, $config->db->config->asArray());
Zend_Db_Table::setDefaultAdapter($db); // 设置控制器 ... 建表
我打算用MySQL,所以建表SQL 语句如下:引用:
代码: CREATE TABLE album (
id int(11) NOT NULL auto_increment, artist varchar(100) NOT NULL, title varchar(100) NOT NULL, PRIMARY KEY (id) )
在MySQL 的客户端运行这个语句,例如phpMyAdmin 或者标准的MySQL 命令行客户端。
插入测试 Albums
我们还要给表中插入一些记录来测试主页中的检索功能。我打算用Amazon.co.uk 中”Hot100”CD 中的头两条:引用:
引用: INSERT INTO album (artist, title) VALUES
('James Morrison', 'Undiscovered'), ('Snow Patrol', 'Eyes Open');
模型
Zend_Db_Table 是一个abstract 类,所以我们派生一个专门管理album 的类。如何命名类无关紧要,但类名和表名用同样的名字比较有意义。这样,类名就叫做Album 因为表名是album。为了告诉Zend_Db_Table 它将管理的表名,我们必须设置保护属性$_name 为表名。
并且,Zend_Db_Table 假定表有一个主键叫做id,它能够自动增长。如果需要的话,这个字段可以更改。
我们将保存我们的Album 表到模型目录:
zf-tutorial/application/models/Album.php复制PHP内容到剪贴板PHP代码:
11
代码:
class Album extends Zend_Db_Table {
protected $_name = 'album'; }
不是很复杂吧?!我们很幸运,我们的需求非常简单并且Zend_Db_Table 提供了所有我们需要的函数。然而,如果你需要特殊的函数管理你的模型,你可以把它们放到这个类里。一般来说,附加的函数将是附加的”find”类型方法,它使你要寻找的精确数据的集合有效。你也可以告诉Zend_Db_Table 关于相关的表并且它也可以获取相关的数据。
列表Albums
我们设置了配置和数据库信息,程序应该可以列出一些album。 这些在IndexController 类里完成。
很清楚,在IndexController 里,每个action 将用Album 类来处理album 数据库。当控制器实例化的时候来加载album 类是很有意义的。这个在init()函数里完成:
zf-tutorial/application/controllers /IndexController.php复制PHP内容到剪贴板PHP代码: ...
function init() {
$this->initView();
$this->view->baseUrl = $this->_request->getBaseUrl(); Zend_Loader::loadClass('Album'); }
...注:这是一个用Zend_Loader::loadClass()来加载我们自己的类并且能够工作的例子,因为我们已经在index.php 中把模型路径放到include path 里。 我们打算在indexAction()里的表里列出album:
zf-tutorial/application/controllers/IndexController.php复制PHP内容到剪贴板PHP代码: ...
function indexAction() {
$this->view->title = \$album = new Album();
$this->view->albums = $album->fetchAll(); $this->render(); }
...函数Zend_Db_Table::fetchAll()返回一个Zend_Db_Table_Rowset,它允许我们通过返回的记录在视图模板文件里重复使用:
zf-tutorial/application/views/scripts/index/index.phtml复制PHP内容到剪贴板PHP代码: render('header.phtml'); ?>
escape($this->title); ?>
baseUrl; ?>/index/add\ Title
Artist
albums as $album) : ?>
escape($album->title);?>
12
escape($album->artist);?>
baseUrl; ?>/index/edit/id/id;?>\
baseUrl; ?>/index/delete/id/id;?>\
render('footer.phtml'); ?>http://localhost/zf-tutorial/ (或任何你使用的地址)应该可以列出一个很好的(两行)album 列 表。
添加新的 Albums
我们现在就可以做添加新的album 的函数。有两点:
显示一个表单让用户提供信息
处理这个表单的提交并把数据保存到数据库里
这个在 addAction()里完成:
zf-tutorial/application/controllers/IndexController.php复制PHP内容到剪贴板PHP代码: ...
function addAction() {
$this->view->title = \
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') { Zend_Loader::loadClass('Zend_Filter_StripTags'); $filter = new Zend_Filter_StripTags();
$artist = $filter->filter($this->_request->getPost('artist')); $artist = trim($artist);
$title = trim($filter->filter($this->_request->getPost('title'))); if ($artist != '' && $title != '') { $data = array( 'artist' => $artist, 'title' => $title, );
$album = new Album(); $album->insert($data); $this->_redirect('/'); return; } }
// set up an \
$this->view->album = new stdClass(); $this->view->album->id = null; $this->view->album->artist = ''; $this->view->album->title = '';
// additional view fields required by form $this->view->action = 'add';
$this->view->buttonText = 'Add'; $this->render(); }
...注意我们如何检查变量$_SERVER['REQUEST_METHOD']来看表单是否被提交。如果表单被提交,我们就从用Zend_Filter_StripTags 类产生的post 数组里提取artist 和title,以确保里面没有html 代码。接着,假定它们已经被填入,我们用模型类,album(),把信息插入到数据库的表里。
在添加了一个album 之后,我们用控制器的_redirect()方法重定向来返回到程序的根(root)。终于,我们建立了我们将在模板里使用的视图表单。进一步看,我们能预计到编
13
辑action 的表单和这个非常类似,所以我们将使用共同的模板文件(_form.phtml),模板文件将被add.phtml 和edit.phtml 调用。 用于添加album 的模板如下:
zf-tutorial/application/views/scripts/index/add.phtml复制PHP内容到剪贴板PHP代码: render('header.phtml'); ?>
escape($this->title); ?>
render('index/_form.phtml'); ?> render('footer.phtml'); ?>
zf-tutorial/application/views/scripts/index/_form.phtml
baseUrl ?>/index/action; ?>\
Artist
value=\ Title
value=\
album->id; ?>\
这是相当简单的代码。我们打算在编辑action 里也用_form.phtml,用$this->action 比hard coding 要好些。相似地,我们在提交按钮里显示的文字也使用变量。
编辑一个 Album
编辑一个album 几乎和添加一个album 相同, 所以代码非常类似:
zf-tutorial/application/controllers/IndexController.php复制PHP内容到剪贴板PHP代码: ...
function editAction() {
$this->view->title = \$album = new Album();
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') { Zend_Loader::loadClass('Zend_Filter_StripTags'); $filter = new Zend_Filter_StripTags(); $id = (int)$this->_request->getPost('id');
$artist = $filter->filter($this->_request->getPost('artist')); $artist = trim($artist);
$title = trim($filter->filter($this->_request->getPost('title'))); Page 16 of 18 if ($id !== false) {
if ($artist != '' && $title != '') { $data = array( 'artist' => $artist, 'title' => $title, );
$where = 'id = ' . $id;
$album->update($data, $where); $this->_redirect('/'); return;
14
} else {
$this->view->album = $album->fetchRow('id='.$id); } }
} else {
// album id should be $params['id']
$id = (int)$this->_request->getParam('id', 0); if ($id > 0) {
$this->view->album = $album->fetchRow('id='.$id); } }
// additional view fields required by form $this->view->action = 'edit';
$this->view->buttonText = 'Update'; $this->render(); }
...注意程序不在 “post” 模式, 我们使用getParam()从请求的params 属性中读取id 参数。 模板如下:
zf-tutorial/application/views/scripts/index/edit.phtml复制PHP内容到剪贴板PHP代码: render('header.phtml'); ?>
escape($this->title); ?>
render('index/_form.phtml'); ?> render('footer.phtml'); ?>改进!
你可能已经注意到AddAction() 和 EditAction() 非常类似并且添加和编辑使用同一个模板,看来需要改进一下。这个就留给你,亲爱的读者… …
删除一个 Album
为了使我们的程序完整,需要一个删除的功能。在列表页里,每个album 旁边有个删除链接,这是个非常朴素的办法让你去点击删除。这可能错了。记得我们的HTTP spec,不能使用不可以撤回动作的GET,作为代替,要使用POST。Google 的最近的加速器beta 把这点带给许多人。
我们要用一个确认表单,当用户点”yes”,我们将做删除动作。 这段代码看起来还是和添加、编辑的action 有点象:
zf-tutorial/application/controllers/IndexController.php复制PHP内容到剪贴板PHP代码: ...
function deleteAction() {
$this->view->title = \$album = new Album();
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') { Zend_Loader::loadClass('Zend_Filter_Alpha'); $filter = new Zend_Filter_Alpha();
$id = (int)$this->_request->getPost('id');
$del = $filter->filter($this->_request->getPost('del')); if ($del == 'Yes' && $id > 0) { $where = 'id = ' . $id;
$rows_affected = $album->delete($where); }
} else {
$id = (int)$this->_request->getParam('id'); if ($id > 0) {
// only render if we have an id and can find the album. $this->view->album = $album->fetchRow('id='.$id); if ($this->view->album->id > 0) {
15
$this->render(); return; } } }
// redirect back to the album list unless we have rendered the view $this->_redirect('/'); }
...再一次,我们使用同样的计策去检查请求方法来决定我们要显示确认表单还是应该删除。通过Album()类,就像插入和更新,实际的删除动作通过调用Zend_Db_Table::delete()来完成。
注意,我们在设置响应body 后立即返回。这就是为什么我们在函数的最后能重定向到album列表。这样,任何不同的健全的检查失败,我们就返回到album 列表而不需要在这个函数里调用_redirect()多次。 模板是一个简单的表单:
zf-tutorial/application/views/indexDelete.tpl.php复制PHP内容到剪贴板PHP代码: render('header.phtml'); ?>
escape($this->title); ?> album) :?>
baseUrl ?>/index/delete\
Are you sure that you want to delete 'escape($this->album->title); ?>' by 'escape($this->album->artist); ?>'?
album->id; ?>\
Cannot find album.
render('footer.phtml'); ?>故障排除
如果除了index/index 能工作外,你发现其他控制模块不能如你所愿,最有可能的问题是路由不能确定你的网站在那个子目录下。就目前来看,通常发生的情况是你网站的url 不同于web-root 的目录。
如果这个缺省代码不适用,你应该自行设置适合你的服务器的$baseURL 的值:
zf-tutorial/index.php复制PHP内容到剪贴板PHP代码: ...
// setup controller
$frontController = Zend_Controller_Front::getInstance(); $frontController->throwExceptions(true);
$frontController->setBaseUrl('/mysubdir/zf-tutorial');
$frontController->setControllerDirectory('./application/controllers');
...你应当用正确的URL 指向index.php 的路径来替换'/mysubdir/zf-tutorial/'。例如:如果你的指向index.php 的URL 是http://localhost/~ralle/zf_tutorial/index.php,正确的$baseUrl 的值就是'/~ralle/zf_tutorial/'。 结论
本教程使用Zend Framwork 开发了一个简单但功能齐全的MVC 应用例程,我希望你能感兴趣和觉得有用。如果你发现任何错误,请给我发邮件到 rob@akrabat.com! 本教程只涉及到Zend Framework 的最节本的用法,你应该去看看手册(http://framework.zend.com/manual)那里有更多的类可以使用,还有wiki(http://framework.zend.com/wiki) 中更多的内幕 !
16