MVC 设计
通常,在这个阶段会根据应用程序所需的功能着手编写代码。一个登录页面、一个数据库、注册表单
—— 搞定!多么简单!通常也就是这么简单。除非您希望更改外观、改变与数据库交互的方法、更改检验规则或在根本上更改应用程序的某些重要方面时,事情才会开始变得复杂起来。
CakePHP 的设计目的是尽可能轻松地编写应用程序,同时提供可以长期维护的应用程序。本教程将告诉您怎样使用
MVC 设计模式构建 Tor。CakePHP 将向您展示这个过程会是多么轻松。您自己会体会到使用 CakePHP
的意义。
MVC 设计模式将应用程序分为三个不同的层,分别是数据处理、UI 和逻辑。Design
Patterns: Elements of Reusable Object-Oriented Software
一书(也称为 “Gang Of Four”)首次介绍了 MVC。全面讨论设计模式和 MVC 超出了本教程的范围,但它对了解这三个部分的含义是很有帮助的
—— 尤其是在 CakePHP 领域中。
模型
用户、产品、价格、消息 —— 从本质上看,它们都仅仅是数据。确保数据是您所需要的,让数据进入数据库,然后再从数据库中取出数据。很有必要将
Tor 的所有数据处理功能都放在一个位置。这就是模型的作用。
模型主要考虑的是处理数据。从数据库中获取数据、将数据插入数据库、检验数据
—— 所有这些操作都是在模型内进行的。
一个单独的模型通常用于访问数据库中特定的表。通常,如果表名是模型名称的复数形式,则模型将与这个数据库表相关联。例如,product
模型在默认情况下将与 products 表相关联。用户定义的所有模型都将扩展 CakePHP AppModel
类。
user 模型
在为 Tor 创建了 users 表后,需要一个 user 模型与该表进行交互。user
模型将保存用户数据,替您从表中取回数据,并检验用户数据是否是可接受的格式。目前,这个模型可以是一个存根。它应当作为
app/models/user.php 创建,内容可能类似于清单 10。
清单 10. user 模型
<?php class User extends AppModel { var $name = 'User'; } ?> |
请注意 var $name = 'User'; 行。在 $name 中指定模型的名称是公认的最佳实践。
视图
如果不能显示数据,那么保存、获取和检验数据就没多大用处。通过将所有显示和表示代码放在同一个位置,可以方便地更改应用程序的外观和感觉,而无需修改与应用程序逻辑和数据相关的代码。
视图主要考虑的是格式化显示给用户的数据。视图用于表示所有 UI 结果,包括所有模板和 HTML。CakePHP
的视图文件是嵌入了 PHP 代码的常规 HTML 文件。
最后,视图就是一个页面模板。通常,视图都根据与之相关联的操作来命名。例如,display() 操作通常会有一个
display 视图。
返回到示例应用程序,我们已经创建一个 users 表和与此表进行交互的 user 模型。现在我们需要一些视图。用户需要注册帐户并登录到应用程序中。这将需要
register 视图和 login 视图。
register 视图
用户需要先注册一个帐户,然后才能使用 Tor 应用程序。这将需要一个 register 视图,这个视图将向用户显示注册表单。您应当已经知道
Tor 需要哪些用户数据了。具体地说,需要收集用户名、密码、电子邮件地址、名字和姓氏。
register 视图应当被创建为 app/views/users/register.ctp,内容可能类似于清单
11。
清单 11. register 视图
<form action="/users/register" method="post"> <p>Please fill out the form below to register an account.</p> <label>Username:</label><input name="username" size="40" />
<label>Password:</label><input
type="password" name="password"
size="40"
/>
<label>Email Address:</label><input
name="email" size="40"
maxlength="255" />
<label>First Name:</label><input
name="first_name" size="40"
/>
<label>Last Name:</label><input
name="last_name" size="40"
/>
<input type="submit" value="register"
/>
</form> |
切记,字段名要与数据库中的列名相同,遵循此原则在处理 users 控制器时会有用。在后面讨论 Cake
的更多信息和 Cake helper 的工作原理时,将完全重写这个页面,但是这个页面目前仅仅是常规的 HTML。
控制器
现在,数据处理全都包含在模型内,表示层全都包含在视图内,应用程序的其余部分将全都包含在控制器中。在控制器中,执行逻辑、决策、工作流及应用程序所涉及的其他操作。模型管理数据,视图显示数据,控制器执行其他所有操作。
控制器管理服务器请求。它接受用户输入(URL 请求、表单 POST、GET 请求等等),在必要时应用逻辑,在需要数据处理时调用模型,并通过适当的视图发送输出。
通常,一个控制器将管理一个模型的逻辑。控制器包含任意数目的函数(也称为操作)。在典型情况下,操作会应用逻辑并显示视图。用户定义的所有控制器都需要扩展
CakePHP AppController 类。
在 Tor 中,已创建了一个 users 表、一个与该表进行交互的 user 模型以及向用户显示注册表单和登录表单的视图。这些表单将提交到
users 控制器,分别调用 register 和 login 操作。users 控制器应当创建为 app/controllers/users_controller.php,最初的内容应当类似于清单
12。
清单 12. users 控制器
<?php class UsersController extends AppController { } ?> |
register 操作
现在已经有了一个控制器。但它还不做任何事情。在让它为您服务之前,必须先给它定义一些要执行的操作。
现在将深入探讨具体细节。用户已经填好了表单并将其提交给应用程序。稍后将介绍数据检验。现在,我们只将数据交给数据库,这需要将
register 操作添加到 users 控制器中(见清单 13)。
清单 13. register 操作
<?php class UsersController extends AppController { function register() { if (!empty($this->params['form'])) { if ($this->User->save($this->params['form'])) { $this->flash('Your registration information was accepted.', '/users/register'); } else { $this->flash('There was a problem with your registration', '/users/register'); } } } } ?> |
register 操作先查看表单 ($this->params['form']),检查它是否已提交。如果表单尚未提交,则不进行任何处理。当知道表单提交了数据之后,控制器将对
user 模型调用 save 方法(该模型是 AppModel 的扩展)。在默认情况下,save 方法将查找表名是模型名的复数的表。在这个示例中,它将查找与
user 模型相对应的 users 表。如果找到该表,则 save 方法将把传递的数组 ($this->params['form'])
转换为一个 INSERT 语句,这个语句使用数组键作为列名,使用数组值作为 INSERT 值。
带数据的表单被提交之后,控制器将调用 user 模型上的 save 方法,该方法是 AppModel
的扩展。默认情况下,save 方法将查找模型复数的表。在这里,它将查找与 user 模型对应的 users
表。如果找到该表,save 将把传递的 ($this->params['form']) 数组转换为
INSERT 语句,其中使用数组键作为列名,使用数组值作为 INSERT 值。在这里,$this->params['form']
将类似于清单 14。
清单 14. $this->params['form'] 数组
清单 14. $this->params['form'] 数组 Array ( [username] => zaphod [password] => secret [email] => beeblebrox@heartofgold.hhg [first_name] => zaphod [last_name] => beeblebrox ) |
save 方法将根据其余部分构建一个 INSERT 语句。这个语句将类似于清单 15。
清单 15. INSERT 语句
INSERT INTO users (username, password, email, first_name, last_name) VALUES ('zaphod', 'secret', 'beeblebrox@heartofgold.hhg', 'zaphod', 'beeblebrox') |
为什么要在 register 视图中使用数据库列名作为注册表单字段名,原因现在就很明显了。通过这样做,显著地简化了保存数据的过程。
接下来,如果数据成功地插入了,则 register 操作将调用 Flash 方法。Flash 向用户显示一条基本消息(在本例中,为一条成功或失败消息)和一个离开此消息的链接(在本例中,返回到
register 视图,因为尚未定义任何其他内容)。
现在已经有了一个与 users 表进行交互的 user 模型,一个用于显示注册表单的 register
视图,以及配有 register 操作的 users 控制器,可以实际看看应用程序的运行情况了。
试运行
所有组件都已整合到了一起。该让 Tor 活动起来了。打开浏览器。访问 http://localhost/users/register
装载 register 视图。您将看到类似图 4 的内容。
图 4. 装载 register 视图
装载 register 视图
填写并提交表单。应当会看到成功消息(见图 5)。
图 5. 成功消息
成功消息
如果查看数据库,应当会看到一条与表单提交相对应的记录,此过程使用明文密码(非常糟糕的做法,稍后解决这个问题)。尝试使用相同的信息重新填写表单。应当会看到失败消息(见图
6)。
图 6. 注册失败
注册失败
如果使用的是支持 UNIQUE 字段约束的数据库,则注册将失败。在创建 users 表的过程中,用户名和电子邮件字段被定义为
UNIQUE ,这意味着这些字段的值不能重复。当数据库抛出这个错误时,CakePHP 会识别出该错误并显示错误。
|