cakephp发布2.0版本,使用方法有许多不同按照1.3.4的教程会遇到很多不顺之处,而在网络上找不到合适的全面的教程,故我基于lupa开源社区的cakephp1.3.4在线教程的改编一个适合2.0以上版本的教程。我的cakephp版本为2.4.1.
环境的搭建请点击:http://my.oschina.net/u/1272301/blog/164660
cakephp安装请点击:http://my.oschina.net/u/1272301/blog/164672
现在我们来从头创建一个应用程序吧
(如你发现本文有什么错误的地方,请指正,谢谢。)
创建应用程序表
现在,CakePHP、Web 服务器和数据库都关联到一起了。开始动手实践吧!Tor 需要一个 users 表。
在数据库中创建表User,这个表将包含识别用户和与用户交互所需的基本信息。简单的用户名和密码字段可能就够了,但其他信息也可能有用,例如电子邮件地址(用于发送密码重置请求)、名字和姓氏(用于个性化服务)以及最后一次登录的日期(用于帮助跟踪不活动的帐户)。您可能希望用户名和电子邮件字段是唯一的。另外,不要忘记主键 ID 字段。创建表的 SQL 可能类似于清单 9。
清单 9. 创建表的 SQL
CREATE TABLE `users` ( `id` INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY , `username` VARCHAR( 40 ) NOT NULL , `password` VARCHAR( 40 ) NOT NULL , `email` VARCHAR( 255 ) NOT NULL , `first_name` VARCHAR( 40 ) NOT NULL , `last_name` VARCHAR( 40 ) NOT NULL , UNIQUE (`username`,`email`) ) engine=myisam; |
注意,username、password、first_name 和 last_name 字段最多包含 40 个字符。在 user 模型中将强制要求不超过这个字符长度。在本例中,40 个字符的最大长度完全是任意设定的。
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->request->data)) { if ($this->User->save($this->request->data)) { $this->flash('Your registration information was accepted.', '/users/register'); } else { $this->flash('There was a problem with your registration', '/users/register'); } } } } ?> |
register 操作先查看数据 ($this->requst->data),以检查它是否为空来判断表单是否提交。如果表单尚未提交,则不进行任何处理。当知道表单提交了数据之后,控制器将对 user 模型调用 save 方法(该模型是 AppModel 的扩展)。在默认情况下,save 方法将查找表名是模型名的复数的表。在这个示例中,它将查找与 user 模型相对应的 users 表。如果找到该表,则 save 方法将把传递的数组 ($this->request->data) 转换为一个 INSERT 语句,这个语句使用数组键作为列名,使用数组值作为 INSERT 值。(你还可以使用$this->request->is('post')来判断参数传递方式是否为post)
在这里,$this->request->data 将类似于清单 14。
清单 14. $this->params['form'] 数组
Array ( [username] => zaphod [password] => secret [email] => [email protected] [first_name] => zaphod [last_name] => beeblebrox ) |
save 方法将根据其余部分构建一个 INSERT 语句。这个语句将类似于清单 15。
清单 15. INSERT 语句
INSERT INTO users (username, password, email, first_name, last_name) VALUES ('zaphod', 'secret', '[email protected]', 'zaphod', 'beeblebrox') |
为什么要在 register 视图中使用数据库列名作为注册表单字段名,原因现在就很明显了。通过这样做,显著地简化了保存数据的过程。
接下来,如果数据成功地插入了,则 register 操作将调用 Flash 方法。Flash 向用户显示一条基本消息(在本例中,为一条成功或失败消息)和一个离开此消息的链接(在本例中,返回到 register 视图,因为尚未定义任何其他内容)。
现在已经有了一个与 users 表进行交互的 user 模型,一个用于显示注册表单的 register 视图,以及配有 register 操作的 users 控制器,可以实际看看应用程序的运行情况了。
试运行
所有组件都已整合到了一起。该让 Tor 活动起来了。打开浏览器。访问 http://localhost/users/register 装载 register 视图。您将看到类似图 4 的内容。
填写并提交表单。应当会看到成功消息(见图 5)。
如果查看数据库,应当会看到一条与表单提交相对应的记录,此过程使用明文密码(非常糟糕的做法,稍后解决这个问题)。尝试使用相同的信息重新填写表单。应当会看到失败消息(见图 6)。
如果使用的是支持 UNIQUE 字段约束的数据库,则注册将失败。在创建 users 表的过程中,用户名和电子邮件字段被定义为 UNIQUE ,这意味着这些字段的值不能重复。当数据库抛出这个错误时,CakePHP 会识别出该错误并显示错误。
helper
CakePHP 中的 helper 主要用于帮助提高视图的开发速度。HTML、Ajax、JavaScript 等等都有 helper。通过使用 helper,可以更轻松地插入要多次编写的 HTML 代码片段。
修改 users_controller.php 文件
为了使用 helper,需要修改前面创建的 users_controller.php 文件。应该给控制器命名,并告诉它希望使用一些 helper(在这个示例中,是 HTML 和 Form helper)。编辑这个文件,添加 $name 和 $helpers 类变量(见清单 16)。
清单 16. users 控制器
<?php class UsersController extends AppController { var $name = 'Users'; var $helpers = array('Html', 'Form' ); function register() { ... |
现在已经在控制器中包含了 helper,可以开始使用它们了。
更轻松地创建表
Tor 的用户应当能够查看注册使用该应用程序的其他用户。CakePHP 有大量 helper 可用于帮助创建表。这些 helper 包括很多有用的功能,其中一些功能您可能不止一次编写过。为了演示此功能,将创建一个用于显示注册用户的视图。
首先,在 users 控制器中创建 knownusers 操作(见清单 17)。
清单 17. 创建 knownusers 操作
function knownusers() { $this->set('knownusers', $this->User->find( 'all', array( 'fields' => array('id','username', 'first_name', 'last_name'), 'order' => 'id DESC' ) )); } |
这将调用 user 模型中的内置函数 find。find 函数接受许多参数,比如匹配条件(在本例中,传递的是 all 而不是一些匹配条件)、要返回的字段数组(不需要所有用户信息,只需要希望所有人都看到的信息),以及一个排序字段和顺序(在本例中,用 id DESC 按 ID 降序排序)。还可以指定限制(返回的最大行数)、分页(如果要给数据分页)以及可用于指定返回与数据关联的模型的递归选项(例如,查询一个 groups 表和属于每个组的若干个用户)。
find 的输出被放入 knownusers 变量。现在就可以从视图访问数据了。
创建 knownusers 视图
在文本编辑器中创建文件 app/views/users/knownusers.ctp。要查看 findAll 返回的数据,应该使用 var_dump 输出 knownusers 变量(见清单 18)。
清单 18. 使用 var_dump 输出 knownusers 变量
<pre> <?php var_dump($knownusers) ?> </pre> |
访问位于 http://localhost/users/knownusers 的视图。应当会看到一个用户数据数组,如图 7 所示。
如果只列出了一个用户,请返回到 http://localhost/users/register,然后多注册一些用户。最终的结果将会更令人印象深刻。
获得足够大的用户数组了吗?很好!现在就将它转换为一个表。使用清单 19 中的内容替换 knownusers.ctp 的内容。
清单 19. 创建表
<table> <?php echo $this->html->tableHeaders(array_keys($knownusers[0]['User'])); foreach ($knownusers as $thisuser) { echo $this->html->tableCells($thisuser['User']); } ?> </table> |
第一个 helper 将从数据数组(本例中为用户的键列表)创建一组表标题。第二个 helper 将从数据数组(本例中为每个用户的值)创建一组包围在表行标记中的表单元格。
好的!保存它,然后访问 http://localhost/users/knownusers 来查看结果(见图 8)。
图 8. 结果
通过使用 tableCells helper,不必再编写循环遍历用户数据数组的代码。这仅仅是通过 helper 更轻松地在 CakePHP 中使用 HTML 的一个示例。
生成表单
构建不使用表单的 Web 应用程序就像给小鸡喂奶一样:极为复杂,而且基本上是白费工夫。良好的可维护的表单是任何良好的应用程序的基础。如果需要经常构建表单,自然会希望找到能更轻松地完成此过程的方法。
在注册表单中使用 helper
在生成表单时 helper 尤为有用。可以使用它们为输入字段生成 HTML,以及生成占位符来保存检验错误消息。使用 helper 为 Tor 生成表单字段和错误消息占位符,register 视图可能类似于清单 20。
清单 20. 使用 helper 生成注册表单
<p>Please fill out the form below to register an account.</p> <?php echo $this->form->create('User', array('action' => 'register'));?> <?php echo $this->form->input('first_name'); echo $this->form->input('last_name'); echo $this->form->input('username'); echo $this->form->input('email'); echo $this->form->input('password'); ?> <?php echo $this->form->end('Register');?> |
如您所见,使用 CakePHP 的 helper 可以节省编写基本表单元素所需的大量时间。现在来看看如何更充分地利用 helper。
充分利用 helper
要想通过 helper 获得更多的收益,需要做两件事:更新 users 控制器并引入一小段数据检验。打开 controllers/users_controller.php,然后将 register 函数改为清单 21 所示的内容。
清单 21. 更新 users 控制器
function register() { if (!empty($this->request->data)) { if ($this->User->save($this->request->data)) { $this->Session->setFlash('Your registration information was accepted.'); } } } |
注意,在register()中,if ($this->User->save($this->request->data))
后的else()错误处理不能跳转页面,否则将无消息提示。
现在,打开 user 模型并添加一小段数据检验(稍后详细说明)。现在,按照清单 22 修改 user 模型。
清单 22. 修改 user 模型
<?php class User extends AppModel { var $name = 'User'; var $validate = array ( 'username' => array ( 'rule' => 'notEmpty', 'message' => 'This field cannot be left blank.' ), 'password' => array ( 'rule' => 'notEmpty', 'message' => 'This field cannot be left blank.' ), 'email' => array( 'rule' => 'email', 'message' => 'Please supply a valid email address.' ) ); } ?> |
简单解释一下,$validate 数组包含用于检验的条目,由键(表单字段名)和用于评估数据的正则表达式组成。没必要检验所有表单字段。在清单 20 中,last_name 和 first_name 是可选的。CakePHP 附带了若干个预定义的用于数据检验的正则表达式。notEmpty规则仅用于确保字段不为空,而 email 规则用于检验字符串像不像电子邮件地址。还有许多其他预定义的检验规则。
现在来试着运行一下。尝试提交没有数据的表单,将一个或两个必填字段留空,提供无效的电子邮件地址(见图 9)。您看到了什么?
现在,再来尝试一次,这次缺少不同的数据(见图 10)。
应当注意的一件事是,CakePHP 会自动显示和关闭错误消息。还应当注意,CakePHP 会记住并填充表单字段的值,无需您执行任何操作。
这就是最大的收益。您不必做哪些操作呢?一方面,不必告诉表单字段重新填充来自 _POST 数组的信息。CakePHP 替您执行了此操作。不必检查每个字段以查找错误,并有条件地单独显示每个消息。CakePHP 替您执行了此操作。不必确保将标记设置为有效的 xhtml。CakePHP 也替您执行了此操作。
helper 说明
本教程只涉及了 helper 的皮毛。这个主题非常广泛,可以针对它撰写一个完整的教程。了解如何更好地使用 helper 将会帮助您进一步加快 CakePHP 开发。CakePHP 包含用于 Ajax(使用 prototype.js)、JavaScript、数字转换、文本处理、日期、时间等方面的 helper。要了解这些 helper 的更多信息,请查看手册(请参阅 参考资料)。
CakePHP 数据检验
通过引入基于正则表达式的基本用户检验,您现在应该已经简要了解了 CakePHP 数据检验。通过定义自己的正则表达式来执行数据检验,可以在 Tor 内练习进一步控制各个表单字段的成功/失败条件。
Tor user 模型
再来看一看 user 模型(见清单 23)。
清单 23. user 模型
<?php class User extends AppModel { var $name = 'User'; var $name = 'User'; var $validate = array ( 'username' => array ( 'rule' => 'notEmpty', 'message' => 'This field cannot be left blank.' ), 'password' => array ( 'rule' => 'notEmpty', 'message' => 'This field cannot be left blank.' ), 'email' => array( 'rule' => 'email', 'message' => 'Please supply a valid email address.' ) } ?> |
这是一个好的开始,但还不够。需要确保字段长度不超出限制并且这个用户名尚不存在。这需要定义自己的用于检验的正则表达式,并定义在保存用户前在 users 表中查找用户名的函数。
正则表达式(简要介绍)
全面讨论正则表达式超出了本教程的范围。PHP Manual 包含 PHP 正则表达式的相关信息,在编写自己的数据检验正则表达式之前应当先参考一下(见 参考资料)。
基本上,正则表达式 是在对一个字符串与另一个字符串进行比较时使用的字符模式。例如,正则表达式中的字符 * 将匹配任意字符任意次数。如果不了解正则表达式,请不必担心。下面的示例应当能帮助您入门。
定义自己的检验
对于用户名和密码字段,需要确认提交的数据长度不超过 40 个字符。检验用户名和密码的长度不少于 6 个字符也会有帮助。此外,我们还将使用的字符限定为数字和字母。用于匹配长度在 6 至 40 个字符之间的字符串的正则表达式类似于 /^[a-z0-9]{6,40}$/i。从左至右阅读这个正则表达式:
/ — 表示正则表达式的开头
^ — 表示字符串的开头
[a-z0-9] — 表示 a~z 或 0~9 之间的任意字符之一
{6,40} — 表示至少 6 个字符,但不能超过 40 个字符
$ — 表示字符串结束
/ — 表示正则表达式结束
i — 忽略任意字母的大小写
因此,连在一起读,这个正则表达式的意思就是 “从字符串的开头开始,有至少 6 个但不超过 40 个字母或数字,然后字符串结束,并忽略大小写”。
要使用这个正则表达式(见清单 24),请将出现 notEmpty 的地方替换为用单引号包围的正则表达式(为了阻止 PHP 尝试解释任何特殊字符)。
清单 24. PHP 脚本中的正则表达式
<?php class User extends AppModel { var $name = 'User'; var $validate = array ( 'username' => array ( 'rule' => '/^[a-z0-9]{6,40}$/i', 'message' => 'This field must have between 6 and 40 alphanumeric characters.' ), 'password' => array ( 'rule' => '/^[a-z0-9]{6,40}$/i', 'message' => 'This field must have between 6 and 40 alphanumeric characters.' ), 'email' => array( 'rule' => 'email', 'message' => 'Please supply a valid email address.' ) ); } ?> |
确保保存所有文件,返回到 http://localhost/users/register,然后尝试用一个具有 4 个字符的用户名注册用户。应当会看到类似图 11 的内容。
正则表达式可以实现许多功能,但不能执行检查用户名是否已注册之类的操作。
进一步检验
有时,无法仅仅查看数据就判断出它是否有效。例如,用户名可能在 6 至 40 个字符之间,但还必须检查数据库来查看这个用户名是否已被占用。 清单 25 中的 beforeValidate 方法是CakePHP1.0的方法 。这个方法在2.0中已经不适用。
清单 25. 检验用户名
function beforeValidate() { if (!$this->id) { if ($this->findByUsername($this->data['User']['username'])) { $this->invalidate('username_unique'); return false; } } return true; } |
在2.0中,只需在user模型的$validate更改username的验证即可如清单26所示
清单 26. 检验用户名
'username' => array ( 'rule' => 'isunique', 'message' => 'must be unique' ),
保存文件,然后尝试操作。首先,访问 http://localhost/user/knownusers 以获取现有用户列表。然后访问 http://localhost/user/register,随后尝试创建一个具有相同用户名的用户。应当会看到以下内容,如图 12 所示。
图 12. 数据检验成功
(此图为2.4.1版本所得,教程仍保留了大部分1.3.4的图片,视图表现有所差异,但不影响学习)
良好的数据检验是创建任何安全应用程序的重要步骤。在构建 Tor 应用程序的过程中,要寻找改进数据检验的机会。不要害怕引入比本教程更多的数据检验。决不要假定用户会把所需的数据发送给您。检验一切内容。CakePHP 可以帮助您轻松完成。
补充功能
到目前为止,用户可以向应用程序注册并查看已经注册的其他用户。这个应用程序需要补充一些功能。使用迄今为止您学到的技巧,尝试补充更多功能。
登录
login 视图应当收集用户登录信息并将其提交给 users 控制器。users 控制器应当查看这个用户是否已在数据库中,并检验密码是否正确。如果用户已经正确地登录,则把用户名写入会话并把用户发送到 index 操作。
提示:
使用内置的 $this->User->findByUsername($your_username_variable_here) 在数据库中搜索用户
用 $this->Session->write('user', $your_username_variable_here) 把用户的名称写到 Session 中
Index 操作
index 操作应当查看用户的名称是否已被写入会话。如果用户的名称已被写入会话,则将该信息从数据库中取出,并向用户显示一条定制的欢迎词。如果用户尚未登录,则让用户执行 login 操作。
注销
logout 操作应当从会话中删除用户的用户名,并将用户转发到 login 操作。
其他
修改 register 操作,把用户自动登录到系统中,并把用户转到 index 操作。修改 register 和 login 操作以使用散列的密码,而不是将密码作为明文保存到数据库中。
编程愉快!
教程的第二部分:http://my.oschina.net/jiangchike/blog/165046
想要断续看1.0版本的第3、4部分教程请进: http://www.ibm.com/developerworks/cn/opensource/tutorials/os-php-cake2/