IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Open source  >

PHP 框架,第 4 部分: Ajax 支持

Zend 框架、CakePHP 和 symfony 如何处理本机代码和第三方库

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 中级

Duane O'Brien (d@duaneobrien.com), PHP 开发人员, 自由撰稿人

2008 年 3 月 03 日

对 PHP 早期版本的常见批评之一是不支持模型-视图-控制器(Model-View-Controller,MVC)样式的架构。现在,开发人员可以在许多 PHP 框架中做出选择。“PHP 框架” 系列将介绍三个广泛使用的 PHP 框架 —— Zend、symfony 和 CakePHP —— 通过在三个框架中构建和扩展样例应用程序来检验这三个框架的类似之处和不同之处。第 1 部分列出了本系列涵盖的内容并满足了先决条件。在第 2 部分中,您分别在三个框架中构建了样例应用程序。在第 3 部分中,您扩展了应用程序并处理不符合一般规律的例外情况。在本文中,您将了解如何在三个框架中支持 Ajax。

关于本系列

本系列专门针对那些想要开始使用框架、但又没有机会详细检验可用框架的 PHP 开发人员。在学完本系列后,您将了解选择这三个框架的原因、如何安装每个框架,并且充分运用将在三个框架中扩展的测试应用程序。听起来要学习的内容很多,但是不必担心。内容虽然多,但是我们已经把内容细分为多个便于管理的部分。

本系列的 第 1 部分 将列出本系列涵盖的内容,介绍将进行考察的框架以及说明如何安装,并查看将构建的第一个测试应用程序。

第 2 部分 将指导您在三个框架中构建样例应用程序,着重说明了它们的类似之处和不同之处。

第 3 部分 从扩展测试应用程序开始,然后处理不符合一般规律的例外情况。所有框架都能很好地完成份内的任务。每个项目中都需要完成一些框架设定工作之外的事情。第 3 部分就介绍了那些情况。

第 4 部分主要介绍了 Ajax 支持。使用本机代码和第三方库检验了 Ajax 的使用 —— 特别介绍了每个框架如何运行及接受具体的常用库。

第 5 部分将处理如何在框架外部工作。设定一项任务(每晚更新脚本),并在每个框架中检验完成此项任务的过程。





回页首


关于本文

本文将查看每个框架如何支持 Ajax。我们将对 Blahg 进行扩展,使用每个框架的 Ajax 支持添加基本的 post 等级,从而得到一些实际体验。

您应当已经查阅了 第 1 部分第 2 部分第 3 部分,这几部分分别介绍了每个框架的安装、先决条件、初始应用程序构建和扩展。如果您还没有阅读,则应当首先查阅这几篇文章。





回页首


Zend 框架中的 Ajax

Zend 框架目前还不包括任何类型的集成 Ajax 支持。Zend 框架中有很多可用于把 Ajax 添加到应用程序中的库,例如 Zend_Json 和 Zend_XmlRpc。Zend 框架中还有一些库有助于利用流行应用程序的现有 Web API,例如 Flickr。但是如果需要在 Zend 中把一些 Ajax 添加到应用程序中,则需要您自己来完成。

不幸的是,您必须编写更多代码才能达到目的。好消息是,如果不与特定的与 Ajax 相关的库集成,您可以选择喜欢的库(或者根本不选择任何库)并以您认为合适的任何方式来构建 Ajax 功能。





回页首


symfony 中的 Ajax

symfony 框架附带了 Prototype 库和 script.aculo.us 库。在 第 2 部分 中,在初始化项目并把 Web 目录的内容复制到 /column/protected/symfony 中时,就是把这些库的副本移到了在应用程序中使用这些库的位置(您必须确认这一点;它应当位于 /column/htdocs/symfony/sf/prototype/js/ 目录中)。

通过提供与 Prototype 的集成,symfony 可以提供一些 helper 来减少把某个 Ajax 添加到 Blahg 中所需的代码量。但是反过来说:如果需要使用 Prototype 以外的内容,则全部需要您自己来完成。





回页首


CakePHP 中的 Ajax

CakePHP 提供了与 Prototype 库和 script.aculo.us 库的集成。我们需要下载想要使用的所有库(把它们放在 /column/htdocs/cakephp/js 中)。要使用 Ajax helper,实际上只需要 Prototype 库。script.aculo.us 库只起美化的作用。

跟 symfony 一样,通过提供与 Prototype 的集成,在构建 Blahg 的 Ajax 功能时,CakePHP 可以让您更轻松地完成工作。同样,反过来说:如果需要使用 Prototype 以外的内容,则全部需要您自己来完成。Ajax helper 不会提供帮助。

注:如果您的首选库是 JQuery,请使用 CakePHP 的 JavaScript helper 来获得帮助。如果加以正确使用,这样做可以得到一些非常整洁的代码,但是这超出本文的范围。





回页首


设置数据库

首先创建一个表来保存等级。使用同一条 SQL 分别在三个数据库中创建这个表。


清单 1. 创建一个表来保存等级
                
CREATE TABLE 'ranks' ( 
'id' INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
'post_id' INT( 10 ) NOT NULL ,
'rank' INT( 10 ) NOT NULL 
) ENGINE = MYISAM ;

注:只保存 post 的等级不需要使用完整的表。如果更改更新已修改列的方式,可以在 post 表的另一列中处理等级。我们不希望每次有人对 post 评级时就修改 post 数据,并且在设计 Blahg 时,MySQL 或框架都将这样做。此外,如果需要对等级进行更多操作,如记录提交的 post 的数量或最后一次对 post 评级的时间,那么把这些信息放到单独的表中才有意义。





回页首


在 Zend 中把 post 等级添加到 Blahg 中

需要决定处理 Ajax 请求的组件。虽然给出我们自己的解决方案一点都不困难,但是考虑到本文的目的,每个框架都将使用 Prototype 库(请参阅 参考资料)。需要创建一个保存库的目录 —— 该目录可以通过浏览器访问,例如 /column/htdocs/zend/scripts/(这是 代码归档 中使用的目录)。

需要创建一个名为 Ranks.php 的基本 ranks 模型。它应当只是一个模型 shell,就像我们为 posts 和 comments 所做的。当然,需要创建 ranks 控制器。我们将不为此模型创建任何视图 —— 该控制器将只回传(echo out)所有等级请求的结果。需要两个操作:readAction 将查找 post 的等级,而 writeAction 将接受提交的等级并查看表中是否有针对该 post 的行。如果有,则用新值更新该等级;否则,将插入一个新的等级行。无论怎样都将输出新等级,因此可以更新视图中的等级。这些内容非常简单并且可以在 代码归档 中找到。现在需要把一些 Ajax 添加到视图中。

记住,在这里不添加任何特定于等级的视图。但是需要修改 posts read 视图来包括 Ajax 代码。打开 /column/protected/zend/views/scripts/post/read.php 文件。这是完成所有工作的位置。对于初学者,需要在文件头中包括 Prototype 库:<script type="text/javascript" src="/zend/scripts/prototype.js"></script>

在编写任何 JavaScript 之前,请把所需的其他部分准备好。需要一些内容来显示当前等级。在等级中,需要带有固定 ID 的等级跨度,以便可以在请求时更新等级值。post 下面可能有如下所示的内容:<h4>Rank: <span id="rank"></span></h4>

接下来,需要一对按钮(链接也可以),用户可以单击这些按钮来指出是否喜欢某个 post。给它们提供良好的初始名。您应当把下面的代码放到等级下:<input type='button' onclick='rankUp();' value='Hot' /><input type='button' onclick='rankDown()' value='Not' />

要使 Prototype 可以更轻松地使用隐藏的 post_id 输入字段,确保字段具有 ID post_id

而且最后,向代码体中添加 onLoad 事件来获得当前等级:<body onload='fetchRank();'>

正如预期一样,需要编写三个 JavaScript 函数:rankUprankDownfetchRank。这些函数将执行实际的 Ajax 请求。它们非常简单并且看上去与在其他框架中完全相同。把这些函数放在文件头的 <script> 部分中。


清单 2. 三个 JavaScript 函数
                
        function fetchRank() {
                var ajax = new Ajax.Request(
                        '/zend/rank/read',
                        {
                                method : 'get',
                                parameters : {'post_id' : $('post_id').value},
                                onComplete: parseRank
                        }
                );
        }
        function rankUp() {
                var ajax = new Ajax.Request(
                        '/zend/rank/write',
                        {
                            method : 'get',
                            parameters : {'post_id' : $('post_id').value, 'rank' : '1'},
                            onComplete: parseRank
                        }
                );
        }
        function rankDown() {
                var ajax = new Ajax.Request(
                        '/zend/rank/write',
                        {
                           method : 'get',
                           parameters : {'post_id' : $('post_id').value, 'rank' : '-1'},
                           onComplete: parseRank
                        }
                );
        }

您会注意到每个函数在结束时都调用 parseRank。该函数将只获取 Ajax 请求的响应并把它放到先前创建的等级跨度内。


清单 3. 调用 parseRank 函数
                
        function parseRank(trans) {
                $('rank').innerHTML = trans.responseText;
        }

当做出所有这些更改或从 代码归档 中导入更改后,应当能够在 Blahg 中阅读 post 并设定该 post 的等级。您甚至可以耍些花样来多次设置 post 的等级。这些就是我们在 Zend 中执行的操作。但是如何在 symfony 中完成相同操作?

注:用 Ajax.Updater 而不用 Ajax.Request 来完成该操作可能更有意义。如果您刚开始使用 Ajax,请动手尝试重构。





回页首


在 symfony 中把 post 等级添加到 Blahg 中

要在 symfony 中添加 post 等级,请从 schema.yml(它应当位于 /column/protected/sf_column/config 中)开始并定义 ranks 表。


清单 4. 在 symfony 中添加 post 等级
                
  ranks :
    _attributes: {phpName: Rank }
    id:
    post_id:
    rank:    integer

记住:在 ranks 前加两个空格的缩进,在字段定义前加四个空格的缩进。

接下来做什么?构建 propel 模型并清空缓存。记住 symfony 从 /column/protected/sf_column 目录(应用程序的根目录)发出命令。


清单 5. 构建 propel 模型并清空缓存
                
php /column/src/symfony/data/bin/symfony propel-build-model

php /column/src/symfony/data/bin/symfony clear-cache

运行这些命令后,我们将在 /column/protected/sf_column/lib/model 目录中看到 Rank.php 和 RankPeer.php 文件。现在继续并用 init 初始化 ranks 模块:php /column/src/symfony/data/bin/symfony init-module blahg rank

rank actions 类 (/column/protected/sf_column/apps/blahg/modules/rank/actions/actions.class.php) 包含两个操作:executeReadexecuteWrite。在读取或更新等级后,我们将回传等级,在每个操作结束时调用退出(这将使 symfony 免于查找不需要构建的与此相关的视图模板)。在 代码归档 中查看这些操作是如何编写的。

最后,需要更新 post readSuccess 模板 (/column/protected/sf_column/apps/blahg/modules/post/templates/readSuccess.php) 来使用 symfony JavaScript helper 并包括一些 Ajax 链接。首先把下面这一行添加到文件的顶部:<?php use_helper('Javascript') ?>。该行将包括 Prototype 库并给我们提供各种 Ajax helper 的访问。可以使用一个 helper 来创建装载初始等级的调用和提交等级的一对链接。请不要忘记添加一个跨度来显示当前等级。


清单 6. 创建装载初始等级的调用
                
<h4>Rank: <span id="rank"></span></h4>
<?php echo javascript_tag(remote_function(array('update' => 'rank', 
                                   'url' => 'rank/read?post_id=' . $id))) ?>
<?php echo link_to_remote('Hot', array('update' => 'rank', 
                    'url' => 'rank/write?post_id=' . $id . '&rank=1')) ?> or
<?php echo link_to_remote('Not', array('update' => 'rank', 
                       'url' => 'rank/write?post_id=' . $id . '&rank=-1')) ?>

这就是需要完成的全部工作。或者,换言之,不必实际编写任何 JavaScript。symfony 框架的 helper 已经为我们完成了这些操作。您不相信?那么设置所有内容(或者从 代码归档 安装代码)并在 symfony 版本的 Blahg 中读取 post,然后查看源代码。您有编写过任何 JavaScript 么?





回页首


把 post 等级添加到 CakePHP 中

在开始向 Blahg 的 CakePHP 版本中添加 post 等级之前,确保已经把 Prototype 下载到 /column/htdocs/cakephp/js 目录中。您需要修改该默认布局模板以在文件头中包括 Prototype 库。那是 /column/protected/cakephp/app/views/layouts/ 目录中的 default.ctp 文件。把下列行添加到文件头中:<?php echo $javascript->link('prototype') ?>

在使用之前,必须先创建一个基本的 AppController,它包括您绝对需要的 JavaScript helper 和 Ajax helper。在 /column/protected/cakephp/app 目录中创建 app_controller.php 文件。它应当类似清单 7。


清单 7. 创建 app_controller.php 文件
                
<?php

class AppController extends Controller {
        var $helpers = array('Html', 'Form', 'Javascript', 'Ajax');
}
?>

注:从技术上讲,这并不准确。我们可以只在 posts 控制器和 ranks 控制器中使用这些 helper,但是创建基本的 app 控制器让我们能够在所有控制器中使用这些 helper,而不必将其添加到 helper 列表中。这是重载基本 AppController 对象的正确方法。

现在需要创建基本的 ranks 模型和 ranks 控制器。这些组件将或多或少地类似已经构建的模型和控制器。在创建 rank 模型时,应当在 rank 模型与 post 模型之间设置模型关联。除非稍后决定添加更健壮的 ranks 功能,否则实在没必要添加模型关联。在 代码归档 中,照例设置了两个关联。

在 ranks 控制器中,需要有一些新内容来帮助确保健壮。包括使用 RequestHandler 组件和添加 beforeFilter 函数。在 beforeFilter 函数中,查看 RequestHandler,而且如果请求是通过 Ajax 处理的,则关闭调试代码。除此之外,控制器现在可能会按照预期操作。read 和 write 这两个方法将查找 post_id 并输出等级。

注: 代码归档 中的控制器代码将仅返回等级,但是如果要处理更复杂的 Ajax 调用,则可以创建模板(例如 views/ranks/viewrank.ctp)并使用 $this->render('viewrank', 'ajax'); 呈现视图。但是由于我们只需要当前等级,因此不需要那样做。

现在只需要向 posts read 视图中添加等级跨度和一对 Ajax 链接,然后就大功告成了。


清单 8. 添加等级跨度
                
<h4>Rank: <span id="rank"><?php echo (int) $post['Rank']['rank'] ?></span></h4>
<?php echo $ajax->link('Hot', '/ranks/write/' . $post['Post']['id'] . '/1', array
('update' => 'rank')); ?> or
<?php echo $ajax->link('Not', '/ranks/write/' . $post['Post']['id'] . '/-1', array
('update' => 'rank')); ?>

这些 Ajax 链接的基本含义是 “通过 Ajax 调用该 URL 并用返回内容更新 DOM 元素等级”(还好我们关闭了调试消息)。所有内容就绪后,继续并装入 post 并进行各种尝试。查看源代码并回想所有未编写的 JavaScript。这是不是很好呢?





回页首


结束语

分享这篇文章……

digg 提交到 Digg
del.icio.us 发布到 del.icio.us
Slashdot Slashdot 一下!

您应当已经基本了解了每个框架如何提供(或者不提供)Ajax 支持。请动手尝试使用更复杂的 Ajax 控制,但是阅读过本文后应当能够让您应对自如。






回页首


下载

描述名字大小下载方法
第 4 部分的样例代码os-php-fwk4.zip30KBHTTP
关于下载方法的信息


参考资料

学习

获得产品和技术
  • Prototype 是一个 JavaScript 框架,使用它可以简化动态 Web 应用程序的开发。

  • 下载 PHP V5.2.3

  • 使用 IBM 试用软件 改进您的下一个开发项目,这些软件可以通过下载或从 DVD 中获得。

  • 下载 IBM 产品评估版,并开始使用 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。


讨论


关于作者

Duane O'Brien 从 Oregon Trail 还只是文本的时候开始,就一直在技术方面游刃有余。他喜欢的食物是寿司。他还不曾去过月球。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款