开始创建 QeePHP 应用程序(4)
时间:2008-04-12 来源:qeeify
前面一篇教程里面我们一经创建好了数据结构,并且成功的从数据库中读出了用户信息。本篇教程,我们完成用户注册功能,下一篇教程则完成登录以及修改密码等功能。
3月19,天气晴,宜偷懒睡觉
正当俺对着屏幕神游时,突然感觉一股凉气从背后升起,然后廖老大的声音就飘了过来:教程后面的怎么没见发上去啊?
老大一句话有如醍醐灌顶,当时就让俺精神百倍。真是思如泉涌、汗如雨下啊 -_-#
MVC 之“控制器”无责任解释
首先,我们需要一个控制器来处理用户的登录、注销和修改密码。那什么叫做控制器呢?控制器嘛,就是 MVC 的控制器咯(嘭,头上一个大包冒了起来)。。。。。
好吧好吧,俺就不讲专业术语了。控制器在俺的理解里,就是一个用来响应用户操作的东西。用户点一下浏览器里面的连接、提交一个表单、发起一个 Ajax 操作,对于服务器上面的程序来说都算作一个请求。而控制器就是处理用户的请求,然后返回用户期望的东西(很黄很暴力的东西没有哦)。
以前,每一个用户操作都是对应到一个网址,而每一个网址都是一个 .php 文件。例如显示注册用户的页面就是 register.php,而提交注册表单后的处理页面就是 register_submit.php。现在我们说的控制器,你可以想象成类似的东西,只不过我们把以前需要几个页面分开处理的东西合并到了一起,放在一个控制器里面解决。
实际上,应用程序可以只有一个控制器。但显然应用程序的功能稍微多一点,这个控制器的代码就会变得很多。一个 .php 文件的代码变得很多后会怎么呢?
因为代码多,所以文件有很多行;因为有很多行,所以要更多的时间才能找到修改的地方,工作效率就下降鸟;工作效率一下将,资本家就不高兴鸟;资本家不高兴鸟,GDP 就下来 CPI 涨上去鸟。。。。。。。而且打开更大的文件要更多的内存,CPU 要进行更多的运算,所以消耗的能源更多,我们创建和谐社会的目标就更远鸟。。。扯远了,sorry。
回到正题,控制器不是什么神秘的东西,就是响应用户请求的代码,只不过把对多个请求的响应代码放到了一起来。放到一起的好处是逻辑上紧密相关的操作可以在一个地方处理,而属于不同范畴的操作则由不同的控制器处理。
对于我们要做的注册、登录和注销来说,就创建一个名为 users 的控制器,并写上几段代码来解决问题。
创建 users 控制器
还是进入命令行,在 digg 目录下输入命令:
php script\generate.php controller users
输出结果如下:
Create file 'D:\www\digg/app/controller/users_controller.php' successed.
Create directory 'D:\www\digg\app\view\users' successed.
可以看到在 app/controller 目录下创建了一个 users_controller.php 文件,以及 app/view/users 目录。先不管那个目录干啥的,我们先打开 users_controller.php 文件来看看。
?php
/**
* Controller_Users 是用于处理 __ 的控制器
*
* @package app
*/
class Controller_Users extends QController_Abstract
{
/**
* 默认动作
*/
function actionIndex()
{
/**
* 要传递到视图的数据,可以直接赋值给 $this->view。
*
* 为了便于在视图中使用这些数据,$this->view 应该是一个数组,键名对应视图中的变量名。
*/
$this->view = array('text' => 'Hello!');
}
}
除去注释,一共也只有几行代码而已。现在我们修改为如下的样子:
?php
class Controller_Users extends QController_Abstract
{
function actionIndex()
{
echo 'come on, baby !';
}
}
在浏览器里面输入地址:http://localhost/digg/public/?controller=users,就可以看到 "come on, baby !” 字样了。
注意看我们输入的地址,后面多出了一个 ?controller=users,这是什么意思呢?
聪明的你一定已经猜出来了,这是告诉程序我们要让刚刚建立那个名为 users 的控制器来处理请求。
(什么,没猜出来?那你得多吃点脑黄金了 :D)
?controller=users 是一个 URL 查询参数。controller 是参数名,而“=”后的 users 就是这个参数的值。通过这个特定的 controller 参数,我们可以实现让不同的控制器响应请求的要求。所以聪明的你,就不要在自己写的代码里面用 controller 传递其他内容了。
现在我们继续修改 users_controller.php 文件为如下的样子:
?php
class Controller_Users extends QController_Abstract
{
function actionIndex()
{
echo 'come on, baby !';
}
function actionLogin()
{
echo 'oh, yeah!';
}
}
在把浏览器地址栏的内容改为:http://localhost/digg/public/?controller=users&action=login
现在就算不聪明的你也知道了吧,controller 参数是控制要访问哪一个控制器,而 action 参数则是控制要访问这个控制器中的哪一个函数。因为 action 参数的值是 login,所以对应的函数名就是 actionLogin()。
简单总结一下:
通过 URL 传递的 controller 参数指定要访问的控制器,而 action 参数由该控制器中的哪一个函数来响应请求。如果没有指定 action 参数,则访问控制器的 actionIndex() 函数。
MVC 之“视图”
刚刚我们已经创建了一个控制器。虽然可以输出文字了,可怎么显示一张完整页面呢?难道把页面代码写在控制器中,那岂不是退回原始社会了。放心,MVC 中还有一种叫做“视图”的东西(MVC 是什么就不要考虑了,反正就一名词)就是专门用来处理页面的。
现在我们在 app/view/users/ 目录下创建一个名为 login.php 的文件,内容如下:
form id="form1" name="form1" method="post" action="url->make('users', 'login'); ?>">
p>用户名:
input type="text" name="username" id="username" value="" />
/p>
p>密 码:
input name="password" type="password" id="password" />
/p>
p>
input type="submit" name="button" id="button" value=" 登录 " />
/p>
p style="color: red">
?php echo h($error); ?>
/p>
/form>
另外再将 users_controller.php 修改为:
function actionLogin()
{
// 如果当前请求是一个 POST 请求,则说明用户提交了一个表单
if ($this->request->isPOST()) {
// 从数据库查找指定用户名的对象
$username = $this->request->username;
$user = User::find('username = ?', $username)->query();
if ($user && $user->checkPassword($this->request->password)) {
// 如果用户名正确,则 $user 不为空,而是一个 User 对象
// 再通过对象的 checkPassword() 方法判断用户输入的密码是否正确
// 登录成功
}
// 登录失败,将用户名和错误信息传递到视图
$this->view['username'] = $username;
$this->view['error'] = '您输入的用户名或密码不正确';
} else {
// 指定视图变量,避免视图显示时出现 Notice: Undefined variable 错误
$this->view['username'] = '';
$this->view['error'] = '';
}
}
通过浏览器访问:http://localhost/digg/public/?controller=users&action=login,就可以看到登录表单啦。
现在我们随便输入一些内容并提交,就可以看到错误信息了。
暂时不急着进行后面的工作,我们先来看看表单是怎么显示出来的,已经怎么从控制器传递要显示的数据到视图。
控制器和视图
前面我们已经说了,用户操作会传递给控制器执行。正因为如此,我们才可以指定访问 users 控制器。但 users 控制器又是怎么和刚刚创建的 app/view/users/login.php 文件关联起来的呢?
仔细看看目录和文件名你就明白了,users 控制器的 actionLogin() 函数对应的视图文件就是 users/login.php(再次表扬猜出来了的聪明家伙,大家鼓掌)。
当然,我们是可以指定要使用哪一个视图的。指定方法很简单:
function actionLogin()
{
.....
$this->viewname = 'other_view';
.....
}
这样就指定了使用 users/other_view.php 视图文件。
类似的,在控制器中通过下面这样的代码可以指定视图中用到的数据:
function actionLogin()
{
.....
$this->view['username'] = ...
$this->view['error'] = ...
.....
}
这里指定了 username 和 error 两个视图变量。所以在 app/view/users/login.php 视图文件中可以直接使用这两个变量了。要是使用了没指定的变量,会出现“Notice: Undefined variable”错误。
MVC 之“模型”
要简单的解释“模型”是什么,以及模型和控制器、视图之间的关系,显得有点困难,所以我们用一个小故事来描述一下。
王大爷的儿女在外地工作,老大爷每逢节气什么的,就琢磨着给儿女寄点东西去。这不,老大爷今儿个又跑到邮局去了。邮局的大厅经理一看王大爷来了,立马热情的招呼大爷,毕竟大家都一个地儿的人,低头不见抬头见的。
大厅经理让老大爷先坐着,问清楚了哪一包是寄给哪个孩子的,就把东西一股脑送到柜台,告诉工作人员寄送地点。工作人员称好重量,算出价格。大厅经理又帮老大爷交了钱。最后把填写好的寄送单交到老大爷手里。王大爷今儿个寄东西的事儿就算完成了。
在这个过程中,王大爷显然是“用户”,他发起了一个请求:要完成包裹的投递任务。而大厅经理就是“控制器”,负责处理王大爷发起的请求。至于“柜台的工作人员”就是“模型”了,他只负责称重、收钱、填单。最后,填好的单子就是返回给用户的“视图”。
这个例子不是很准确,但是我们可以很清楚的区分流程中各个部分的角色及其任务。总结而言:模型只负责一个业务的实现,而不负责和用户的交互。
这种“隔离”,可以获得一些明显的好处:
- 模型的职责更单纯,这样模型的代码就会更少
- 可以在不同的地方重复使用一个模型(称为复用),例如控制器可以调用模型,模型还可以调用模型
- 模型内部的改动可以不影响到其他部分(前提是保持同样的接口)
这里“接口”又是一个新名词,不过我们把接口暂时当成一组函数的集合就行了。比如函数 checkPostCode($postcode) 就是一个接口的一部分。只要一个接口中所有函数的命名和参数列表不发生变化,就表示接口没有发生变化。
在 QeePHP 应用程序中,模型通常对应一个数据表。这个数据表的一条记录是一个模型实例。因此获得一个模型实例就有两个主要的途径:
- 通过 new 关键词构造一个新的模型实例
- 通过查询方法从数据库中查找一个现有的模型实例
在前面的代码中:
$user = User::find('username = ?', $username)->query();
就是查询一个模型实例。如果查询成功,$user 中会包含一个 User 对象。查询失败,则 $user 为 null。对于这行代码有疑问没关系,后面我们会深入讨论这个问题。
原文地址:
http://qeeify.com/index.php/2008/03/22/begin-app-4.html
更多信息,请访问 FleaPHP/QeePHP 开源开发框架官方网站:
http://www.fleaphp.org/
。
相关阅读 更多 +
排行榜 更多 +