编者按:本系列最初发表于 2006 年,并在 2007 年和 2008 年进行了更新。由于最后一版的发布,CakePHP 开发人员,
自从上次发布之后,CakePHP 开发人员对它进行了多次修改,并产生了本系列的多个修改版本。本修改版用的是 V1.3.4。
“使用 CakePHP 快速打造 Web 站点” 系列教程是专为 PHP 应用程序开发人员而设计的,使用 CakePHP 可以使他们的生活变得轻松。在本系列的最后这篇文章中,您将学习如何安装和配置 CakePHP、Model-View-Controller(MVC)设计基本概念、如何在 CakePHP 中检验用户数据、如何使用 CakePHP 帮助函数、如何使用 CakePHP 快速建立并运行应用程序。听起来好像有很多东西要学习,但不必担心 — CakePHP 会替您完成其中的大部分工作。
本文假设您已经学习了 使用 CakePHP 快速打造 Web 站点,第 1 部分:入门、使用 CakePHP 快速打造 Web 站点,第 2 部分:用 CakePHP 打造更大更好的站点、使用 CakePHP 快速打造 Web 站点,第 3 部分: 使用 Sanitize 进行保护、使用 CakePHP 快速打造 Web 站点,第 4 部分:使用 CakePHP 的 Session 和 Request Handler 组件,并仍保留为这些教程设置的工作环境。如果尚未安装 CakePHP,则应当回顾第 1 部分和第 2 部分,然后再继续学习。
本教程假设您熟悉 PHP 编程语言,基本掌握数据库设计且喜欢动手实践。
开始之前,需要具备一个工作环境。CakePHP 的最低服务器需求为:
- 支持会话(并且最好支持
mod_rewrite)的 HTTP 服务器。本教程采用的是支持mod_rewrite的 Apache V2.2.4。 - PHP V4.3.2 或更高版本(包括 PHP V5)。本教程采用的是 PHP V2.3。
- 一个受支持的数据库引擎。本教程采用的是 MySQL V5.0.4。
还需要准备好一个数据库以供应用程序使用。本教程将提供在 MySQL 中创建任何必需的表的语法。
下载 CakePHP 的最简单方法是访问 CakeForge.org,并从“下载” 部分下载最新的稳定版本。本教程采用的是 V1.2.812.0。还可以直接使用来自 Subversion 的每日构建和拷贝。CakePHP Manual 中有更详细的信息(见 参考资料)。
在 使用 CakePHP 快速打造 Web 站点,第 4 部分:使用 CakePHP 的 Session 和 Request Handler 组件 中,您有机会使 Tor 更加流线化。您是如何做的呢?
要查看收藏列表,需要将 favorites 操作添加到 users 控制器中。它可能类似于清单 1。
清单 1. 将 favorites 操作添加到 users 控制器中
function favorites () {
$username = $this->Session->read('user');
$favorites = array();
if ($username)
{
$this->User->recursive = 2;
$results = $this->User->findByUsername($username);
foreach($results['Product'] as $product)
{
$favorites[] = array('Product' => $product, 'Dealer' => $product['Dealer']);
}
$this->set('products', $favorites);
} else {
$this->redirect(array('controller' => 'users', 'action' => 'login'));
}
}
|
注意,如果用户未登录则会重定向。这将使用户在未登录的情况下查看页面时不会看到错误。
还需要在 app/views/users/ 目录中编写 favorites.ctp 文件。它可能类似于以下清单。
清单 2. Favorites.ctp
<div class='favorites'>
<h2>Favorites</h2>
<table cellpadding="0" cellspacing="0">
<tr>
<th>Id</th>
<th>Title</th>
<th>Dealer</th>
<th>Description</th>
<th class="actions">Actions</th>
</tr>
<?php
$i = 0;
foreach ($products as $product):
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="altrow"';
}
?>
<tr<?php echo $class;?>>
<td>
<?php echo $product['Product']['id'] ?>
</td>
<td>
<?php echo $product['Product']['title'] ?>
</td>
<td>
<?php echo $html->link($product['Dealer']
['title'], array('controller'=> 'dealers',
'action'=>'view', $product
['Dealer']['id'])); ?>
</td>
<td>
<?php echo $product['Product']['description'] ?>
</td>
<td class="actions">
<?php echo $html->link('View', array
('controller' => 'products',
'action'=>'view', $product['Product']
['id'])); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
|
视图实际需要做的全部操作是显示产品表。但是,目前无法从收藏列表中删除产品。
另一项任务是将 Remove From Favorites 链接插入产品表并设置它,以便当产品位于用户的收藏列表中时用户会看到 Remove 链接,当产品不在收藏列表中时用户会看到 Add 链接。再来看一看产品的 View 视图,以下部分是最重要的。
清单 3. 产品表
<?php
if ( isset($ajax) ) {
echo $ajax->link('Add to Favorites', array('action' =>
'addToFavorites/' . $product['Product']['id']), array('update' =>
'favMessage'));
} else {
echo $html->link('Add to Favorites', array('action' =>
'addToFavorites/' . $product['Product']['id']));
}
?>
|
Remove From Favorites 链接很可能与如下所示的清单相同。
清单 4. Remove From Favorites 链接
echo $ajax->link('Remove From Favorites', array('action' =>
'removeFromFavorites/' . $product['Product']['id']), array('update' =>
'favMessage'));
|
您还需要在 users 控制器中添加 JavaScript 和 Ajax 帮助程序,并在产品控制器中添加 removeFromFavorites 操作。
清单 5.
removeFromFavorites 操作
function removeFromFavorites($id) {
$username = $this->Session->read('user');
$success = false;
$user = $this->Product->User->findByUsername
($username, 'User.id');
$this->Product->User->id = $user['User']['id'];
$success = $this->Product->User->removeFavorite($id);
if ( $this->RequestHandler->isAjax() ) {
echo 'Removed product from favorites';
exit;
} else {
if ( $success ) {
$this->Session->setFlash('Removed
product from favorites');
$this->redirect('/users/favorites');
} else {
$this->Session->setFlash('Access denied');
$this->redirect('/products/index');
}
}
}
|
同样,您需要在用户模型中添加 removeFavorite 方法。
清单 6. 创建
removeFavorite 方法
function removeFavorite($product_id) {
if($this->exists()) {
$user = $this->read();
$fav = array();
foreach($user['Product'] as $product) {
if ($product_id != $product['id']) {
$fav[] = $product['id'];
}
}
$user['Product'] = array('Product'=> $fav);
if($this->save($user)) {
return true;
} else {
return false;
}
}
return false;
}
|
正如您所注意到的,在测试时,如果您查看产品,系统总是显示 Add to Favorites。相反,用户可以看到已经添加到收藏列表中的产品的 Remove From Favorites 链接。您是如何实现的呢?
您的解决方案可能很不一样。这很好。现在我们来讨论本系列中的下一个主题:缓存。
在概念方面,缓存有时可能会造成混淆。缓存有多种类型,并且每种缓存都有一些挑战和优点。因此很有必要了解在这种环境下缓存的具体含义。
通常,如果发出请求,且应用程序响应 “我没必要再去获取数据。我已经获得了数据”,那么就是发生了缓存。在大多数情况下,当计算机用户听到 “缓存” 一词时,都会想到浏览器的缓存。通常,为了加快响应速度,浏览器会保留它认为是静态文件的拷贝 — 通常包括图片、样式表、静态 HTML 和脚本文件。虽然此类缓存有时可能会给 Web 应用程序开发人员造成麻烦,但此类缓存不是本文所关注的缓存。
当浏览器向 Web 应用程序发出请求以获得一些内容时,可能会发生另一种缓存。如果 Web 应用程序使用缓存,它可能用以前生成内容的拷贝来响应请求,这会免除第二次生成内容所涉及的资源开销。这才是本文所关注的缓存类型。
通常,在应用程序中使用缓存有两个原因。第一,缓存帮助减少服务器上的资源开销。虽然在大多数情况下节省的资源开销可能很少,但是对于处理大量请求的高流量站点来说,这些小节省可以迅速地累积为明显的性能优势。第二个原因通常是速度。由于应用程序无需执行为请求重新生成内容的过程,因此可以更快速地提供内容。同样,虽然在大多数情况下节省的时间可能很少,但是通过使用缓存,高流量站点可以快速地获得速度优势。
OK — 理解了缓存之后,就可以准备缓存任何内容了。那么,如何才能进行缓存呢?CakePHP 提供了哪些功能使您可以轻松地执行此操作?
首先,需要启用缓存。默认情况下,该特性处于禁用状态。可以在 app/config/core.php 中启用缓存。查找以下内容://Configure::write('Cache.check', true);,然后取消注释。
通过将 Cache.check 设置为 true,可以通知 CakePHP 缓存现在已启用。来吧现在就开始,稍后对缓存进行设置。仅仅启用缓存还不够,还必须准确地告诉 CakePHP 需要缓存的内容以及缓存多久。
启用了缓存后,必须指定您想缓存的内容。首先,在需要缓存视图的控制器中,将 Cache 添加到 helpers 数组中。例如,如果需要缓存产品视图,则必须在产品控制器的 helpers 数组中包含 Cache。在为 Tor 构建产品控制器时,已指定了要使用 HTML 和表单 helpers。在这个列表中添加 Cache,helpers 数组将类似于:var $helpers = array('Html', 'Form', 'Javascript', 'Ajax', 'Cache' );。
既然已经使用了缓存帮助程序,就需要准确地指定需要缓存的内容。有多种方法可以执行此操作,但是所有这些方法都依赖于 $cacheAction 数组。
假定您需要缓存一个特定请求。假定有 3、4 种产品在 view 操作上遇到高流量,您希望为这些产品缓存 View 视图。在这种情况下,您需要把希望缓存的请求指定为 $cacheAction 的数组键并把时间长度指定为键值。与 $helpers 数组一样,$cacheAction 数组是一个类变量。要缓存这些特定视图,$cacheAction 可能类似于清单 7。
清单 7.
$cacheAction
<?php
class ProductsController extends AppController {
...
var $cacheAction = array (
'view/1/' => 3600,
'view/2/' => 3600,
'view/3/' => 3600
);
|
这个 $cacheAction 告知 CakePHP 把产品 1 至产品 3 的 View 视图缓存 3,600 秒(一小时)。指定的时间长度可以是 strtotime() 能够解释的任意格式。可以简单地指定 1 hour。
只缓存某些产品可能还不够。可能还需要缓存特定操作的所有视图。假定需要对 edit 操作的视图使用缓存。为此,把这个操作指定为数组键并指定在缓存中保留视图的时间长度,像上面一样。
var $cacheAction = array (
'edit/' => '+1 hour'
);
|
您可以混合搭配这两种方法。
清单 8. 混合搭配
var $cacheAction = array (
'view/1/' => 3600,
'view/2/' => 3600,
'view/3/' => 3600,
'edit/' => '+1 hour'
);
|
这会帮助节省一些时间。现在已经缓存了最常查看的产品的 View 视图和所有 edit 视图。但您可能还想做更多事情。
您可能希望缓存控制器执行的所有操作。如果是这样,则没必要在 $cacheAction 数组中指定每个操作。只需将 $cacheAction 的值设为一个时间长度: var $cacheAction = "+1 hour";,保证全部被缓存。
这个值必须是 strtotime() 可以解释的字符串。通过将 $cacheAction 设置为一个单一值,就让 CakePHP 知道要缓存控制器的所有视图。
由于 $cacheAction 是一个类变量,因此也可以从操作内访问这个变量。假定需要从操作内修改 $cacheAction,可以使用与修改任何类变量一样的语法。
function foo() {
$this->cacheAction = array()...
}
|
通常,不必这么做,但是可能会遇到确实需要这么做的情况。如果是这样,您现在知道该怎么做了。CakePHP 提供了几种缓存视图的方法。这是很简单的部分。了解何时进行缓存 — 或者更具体地说,何时不缓存 — 才可能有点儿麻烦。
缓存的好处可能很吸引人。而且,在大多数情况下,缓存都会完全按照您的要求执行。那么,究竟在何时不需要缓存视图呢?
在大多数情况下,不希望完全缓存那些经常更新的数据。例如,假定 Tor 的用户要在一分钟内多次添加产品。在这种情况下,缓存索引视图可能会弊大于利。如果内容更新得过于频繁,以至于缓存的页面从未被实际使用过,则所做的操作无谓地增加了以下开销:保存缓存的页面和对于每个请求查看缓存的页面是否已更新。
但是,这不意味着无法使用缓存。只需具体告诉 CakePHP 需要缓存哪些内容。
查看 <cake:nocache></cake:nocache> 标记
在视图或布局内,CakePHP 允许您明确地从缓存的范围中排除一些内容,方法为将内容放在 <cake:nocache></cake:nocache> 标记中。正确地使用此标记将让 CakePHP 缓存视图或布局的静态部分,同时确保对于每个请求都检索页面的动态部分。
并非所有内容都可以放在 <cake:nocache></cake:nocache> 标记中。具体地说,不能只将变量放在 <cake:nocache></cake:nocache> 标记中以使其保持动态。一般而言,可以放在 <cake:nocache></cake:nocache> 标记中的内容是 CakePHP 结构,如帮助程序和元素调用。
清单 9. 默认布局
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
...
<div id="header">
<h1><?php echo $html->link('Tor', '/') ?> : Welcome <?php echo
$session->read('user') ?></h1>
...
|
如果启用了缓存,在首次装载使用默认布局的任何页面时,Welcome <?php echo $session->read('user')
?> 就会被替换为诸如 Welcome 或 Welcome wrestler 之类的内容 — 这意味着无论哪个用户登录,都会看到一个缓存用户名。
为了指定不应当缓存的用户名,需要把 <?php echo $session->read('user') ?> 行放在 <cake:nocache></cake:nocache> 标记中。最终的结果类似于以下清单:
清单 10. 指定不应当缓存用户名
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
...
<div id="header">
<h1><?php echo $html->link('Tor', '/') ?> : Welcome
<cake:nocache><?php echo $session->read('user')
?></cake:nocache></h1>
...
|
您可以通过指定产品控制器对 view 操作使用缓存来测试这段代码。将 Cache 添加到帮助程序列表中并在 $cacheAction 中指定一个视图。
清单 11. 指定 products 控制器对
view 操作使用缓存
<?php
class ProductsController extends AppController
{
var $name = 'Products';
var $helpers = array('Html', 'Form', 'Javascript', 'Ajax', 'Cache' );
var $components = array('Acl','Security','RequestHandler');
var $cacheAction = array(
'view/' => '+1 hour'
);
...
|
现在,请查看一个产品。应当会看到在 app/tmp/cache/views 中创建了一个与所查看产品对应的文件。以另一个用户的身份登录并查看同一个产品。您将发现自己的用户名并未被缓存。编辑该产品。您将发现 CakePHP 知道应该删除缓存的视图。这真是太棒了。
使用 <cake:nocache></cake:nocache> 标记可以帮助您在对视图进行缓存和让内容保持最新之间取得平衡。有时这还不够。有时需要自己清除缓存。
即使您在缓存与不缓存哪些内容方面的决策充满智慧,有时仍然有必要手工清除缓存。您可能会想到,在数据已经被更新后显然需要这么做。例如,如果编辑了一个产品,则该产品的 view 和 edit 视图以及产品 index 视图都必须从缓存中清除。您是正确的。确实需要清除这些视图。
但您 不必亲自这样做。CakePHP 会替您完成此操作。CakePHP 知道在插入、更新或删除数据时,如果影响到缓存的视图,就需要清除该视图的缓存。这将避免大量工作。
但是有时也可能有必要显式地清除缓存。例如,如果一个外部进程(例如安排好的批处理脚本)要直接更新数据库中的数据,而不是通过应用程序,则需要手工清除缓存。这可以使用全局函数 clearCache 来完成。
您通常不需要清理缓存,因为当对这些文件的数据进行 INSERT、UPDATE 或 DELETE 操作时,CakePHP 会清理相关缓存文件。
如果需要彻底清理整个缓存,您可以在一个指定缓存清理操作中调用函数 Cache::clear(),或者您也可以创建一个控制器来实现这一目的。如果您需要自动化进程也是非常方便。
祝贺您!您已经完成了 “使用 CakePHP 快速打造 Web 站点” 教程的学习。现在,您可能很兴奋,迫不及待地想构建自己的应用程序。
但在这样做之前,请在 app/config/core.php 中将 DEBUG 设置为 2。这将让 CakePHP 在视图底部显示一些 SQL 调试信息。可以在 app/tmp/cache/views 中找到缓存的页面。打开其中一个来看一下缓存页面的样子。删除缓存的文件并查看一个产品。记下运行了多少个查询及其花费的时间。现在重新装载。对视图进行缓存。这次运行了多少个查询?花了多少时间?通过练习逐渐熟悉缓存,寻找在 Tor 中使用缓存的方法。完成后,抛开这些,全身心地投入到您自己的应用程序中。
您已经在这个系列教程中学到了很多知识,但这还远远不够,若要加深对 CakePHP 的理解,最好的方法是在 CakePHP 中从头开始编写自己的应用程序。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 第 5 部分源代码 | os-php-cake5.source.zip | 14KB | HTTP |
学习
- 访问 CakePHP.org 了解更多信息。
-
CakePHP API 已有全面的文档。访问此处可获取 CakePHP 的最新文档。
-
Bakery 中有大量可用信息,它是 CakePHP 用户社区。
-
CakePHP Data Validation 使用与 PHP Perl 兼容的正则表达式。
- 阅读标题为 “How to use regular expressions in PHP” 的教程。
- 想要了解关于设计模式的更多信息吗?请查阅 Design Patterns: Elements of Reusable Object-Oriented Software, 也称为 “Gang Of Four”。
- 查阅一些 用于创建用户的原始资料。
- 查阅 Wikipedia 的 Model-View-Controller。
- 这里有关于 Model-View-Controller 的有用背景信息。
- 查阅 软件设计模式 列表。
- 了解 设计模式。
-
PHP.net 是为 PHP 开发人员提供参考资料的主要站点。
- 查阅 “推荐 PHP 读物列表”。
- 浏览 developerWorks 上的所有 PHP 内容。
- 通过 IBM developerWorks 的 PHP 项目资源 提高您的 PHP 技能。
- 要想收听针对软件开发人员有趣的访谈和讨论,请查阅 developerWorks 播客。
- 要将数据库与 PHP 结合使用吗?请查看 Zend Core for
IBM,它是一个开箱即用的无缝 PHP 开发和生产环境,易于安装并且支持 IBM DB2 V9。
- 查看免费的 developerWorks 演示中心,观看并了解 IBM 及开源技术和产品功能。
- 随时关注 developerWorks 技术活动和网络广播。
- 访问 developerWorks Open source 专区获得丰富的 how-to 信息、工具和项目更新以及最受欢迎的文章和教程,帮助您用开放源码技术进行开发,并将它们与 IBM 产品结合使用。
获得产品和技术
- 使用 IBM 产品评估试用版软件,改进您的下一个开放源码开发项目,这些软件可以下载获得。
- 下载 IBM 产品评估试用版软件 或 IBM SOA Sandbox for People,并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
讨论
- 参与 developerWorks PHP 论坛:使用 IBM Information Management 产品(DB2,IDS)开发 PHP 应用程序。
- 欢迎加入 developerWorks 中文社区。