baiyuxiong 发表于 2010-1-25 14:29:24

从头学CodeIgniter和Doctrine 第三天 用户注册【翻译】下

本帖最后由 baiyuxiong 于 2010-1-25 15:18 编辑

从头学CodeIgniter和Doctrine 第三天 用户注册【翻译】下
英文原文:http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-3-user-signup-form翻译:http://baiyuxiong.com/article/123.htm


超过字数限制了,只好发两篇。
接上篇:http://codeigniter.org.cn/forums/thread-4632-1-1.html

表单辅助函数

我们已经载入了表单辅助函数,现在来使用它。
编辑: system/application/views/signup_form.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Signup Form</title>
</head>
<body>
<div id="signup_form">
    <p class="heading">New User Signup</p>
    <?php echo form_open('signup/submit'); ?>
    <p>
      <label for="username">Username: </label>
      <?php echo form_input('username'); ?>
    </p>
    <p>
      <label for="password">;Password: </label>
       <?php echo form_password('password'); ?>
    </p>
    <p>
      <label for="passconf">Confirm Password: </label>
      <?php echo form_password('passconf'); ?>
    </p>
    <p>
      <label for="email">E-mail: </label>
       <?php echo form_input('email'); ?>
    </p>
    <p>
       <?php echo form_submit('submit','Create my account'); ?>
    </p>
    <?php echo form_close(); ?>
</div>
</body>
</html>

我突出显示了调用的不同函数。这些函数为我们的表单标签和元素创建html。

打开http://localhost/ci_doctrine/signup
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_2.png
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_2.png
在浏览器上查看源文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Signup Form</title>
</head>
<body>
<div id="signup_form">
    <p class="heading">New User Signup</p>
    <form action="http://localhost/ci_doctrine/signup/submit" method="post">
    <p>
      <label for="username">Username: </label>
      <input type="text" name="username" value=""/>   </p>
    <p>
      <label for="password">Password: </label>
      <input type="password" name="password" value=""/>   </p>
    <p>
      <label for="passconf">Confirm Password: </label>
      <input type="password" name="passconf" value=""/>   </p>
    <p>
      <label for="email">E-mail: </label>
      <input type="text" name="email" value=""/></p>
    <p>
       <input type="submit" name="submit" value="Create my account"/></p>
    </form>
</div>
</body>
</html>

给它设计一下样式。
在工程目录ci_doctrine下创建一个名为css的目录。
创建文件: css/style.css

body {
    font-family: "Trebuchet MS",Arial;
    font-size: 14px;
    background-color: #212426;
    color: #11151E;
}

input, textarea, select {
    font-family:inherit;
    font-size:inherit;
    font-weight:inherit;
}
#signup_form {
    margin-left: auto;
    margin-right: auto;
    width: 360px;
    font-size: 16px;
}
#signup_form .heading {
    text-align: center;
    font-size: 22px;
    font-weight: bold;
    color: #B9AA81;
}
#signup_form form {
    background-color: #B9AA81;
    padding: 10px;
    border-radius: 8px;
    -moz-border-radius: 8px;
    -webkit-border-radius: 8px;
}
#signup_form form label {
    font-weight: bold;
}
#signup_form form input,input {
    width: 316px;
    font-weight: bold;
    padding: 8px;
    border: 1px solid #FFF;
    border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
}

#signup_form form input {
    display: block;
    margin: auto;
    width: 200px;
    font-size: 18px;
    background-color: #FFF;
    border: 1px solid #BBB;
}
#signup_form form input:hover {
    border-color: #000;
}
#signup_form .error {
    font-size: 13px;
    color: #690C07;
    font-style: italic;
}

这个教程不是关于CSS的,所以这里不做太多解释。
再次编辑:system/application/views/signup_form.php

添加高亮显示的行:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Signup Form</title>
<link rel="stylesheet" href="<?php echo base_url(); ?>css/style.css"
      type="text/css" media="all">
</head>

<body>

我们调用了base_url()函数,在这个例子中,返回http://localhost/ci_doctrine/ 。这个函数是辅助函数的一部分。
访问: http://localhost/ci_doctrine/signup, 看到:
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_3.png
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_3.png
表单验证

如果你现在点击submit按钮,你将收到一个404错误:
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_4.png
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_4.png
因为submit() 方法不存在.
编辑: system/application/controllers/signup.php

<?php

class Signup extends Controller {
    public function __construct() {
      parent::Controller();
      $this->load->helper(array('form','url'));
      $this->load->library('form_validation');
    }
    public function index() {
      $this->load->view('signup_form');
    }
    public function submit() {
      if ($this->_submit_validate() === FALSE) {
            $this->index();
            return;
      }
      $this->load->view('submit_success');
    }
private function _submit_validate() {
      // validation rules
      $this->form_validation->set_rules('username', 'Username',
            'required|alpha_numeric|min_length|max_length');
      $this->form_validation->set_rules('password', 'Password',
            'required|min_length|max_length');
      $this->form_validation->set_rules('passconf', 'Confirm Password',
            'required|matches');
      $this->form_validation->set_rules('email', 'E-mail',
            'required|valid_email');
      return $this->form_validation->run();
    }
}

解释一下我刚添加的代码:
[*]我添加了2个方法:submit()和_submit_validate()。[*]表单提交的时候调用submit()方法。[*]首先它验证输入。如果验证失败,调用index()方法再次显示注册表单。[*]如果没有错误,我们载入名为submit_success的view。我们一会儿再创建这个view。[*]_submit_validate()是我创建的一个私有函数。包含表单验证的内容。[*]返回验证的结果(true or false)。我们来看看表单验证是如何工作的。
当我们一开始载入表单验证类库时,
首先设置规则:

$this->form_validation->set_rules('username', 'Username','required|alpha_numeric|min_length|max_length');

第一个参数是表单域的名称。
第二个参数是它的字面名称。用来显示表单域的作用。
第三个参数是验证规则的列表,用"|"分开。
在这里:http://codeigniter.com/user_guid ... .html#rulereference,你可以看到很多验证规则。
最后,我们调用run()进行验证,如果用户输入不正确将返回FALSE。

显示验证错误

接下来要做的是向用户显示错误信息。
编辑: system/application/views/signup_form.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Signup Form</title>
    <link rel="stylesheet" href="<?php echo base_url(); ?>css/style.css"
      type="text/css" media="all">
</head>
<body>
<div id="signup_form">
    <p class="heading">New User Signup</p>
    <?php echo form_open('signup/submit'); ?>
   <?php echo validation_errors('<p class="error">','</p>'); ?>
    <p>
      <label for="username">Username: </label>
      <?php echo form_input('username',set_value('username')); ?>
    </p>
    <p>
      <label for="password">Password: </label>
      <?php echo form_password('password'); ?>
    </p>
    <p>
      <label for="passconf">Confirm Password: </label>
      <?php echo form_password('passconf'); ?>
    </p>
    <p>
      <label for="email">E-mail: </label>
      <?php echo form_input('email',set_value('email')); ?>
    </p>
    <p>
      <?php echo form_submit('submit','Create my account'); ?>
    </p>
    <?php echo form_close(); ?>
</div>
</body>

</html>

validation_errors() 显示表单验证返回的错误列表(17行)。
第一个和第二个参数是用来包住错误输出的html代码。
在21行和33行,我传递第二个参数给form_input()函数。这样做,当表单再次显示的时候,它将被上次输入的值填充。用户就不需要从头开始输入了。

提交成功View

先做一个简单点儿的。
创建: system/application/views/submit_success.php

Success!

测试表单
在表单里输入一些无效的数据并提交。
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_5.png
http://localhost/ci_doctrine/signup
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_5.png
如果你输入的信息是正确的,你应该能看到Success!消息。

保存用户

现在,表单工作正常,我们要用Doctrine模型把用户保存到数据库。

编辑system/application/controllers/signup.php下的submit()函数。
<?php
class Signup extends Controller {
    // ...
    public function submit() {
      if ($this->_submit_validate() === FALSE) {
            $this->index();
            return;
      }
      $u = new User();
      $u->username = $this->input->post('username');
      $u->password = $this->input->post('password');
      $u->email = $this->input->post('email');
      $u->save();
      $this->load->view('submit_success');
    }
    // ...
}

正如你看到的,我们做的所有工作就是创建一个User对象,给参数附值并调用save()函数。Doctrine就会把新记录保存到数据库!如些简单!

注意:我们使用$this->input->post()得到输入表单的值。使用CodeIgniter时,我们不直接使用全局变量如$_POST。这提供额外的安全方面的好处。
注意2:把用户输入附值给Doctrine模型时,我们不使用任何sql过滤,如mysql_real_escape_string()。因为Doctrine会帮我们搞定。

测试表单
访问: http://localhost/ci_doctrine/signup, 输入合适的值提交.
检查数据表的内容:
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_6.png
运行正常,但我们还没完全完成。

一个小问题
试试以同样的用户名和e-mail提交表单。你将看到:
<br />
<b>Fatal error</b>:Uncaught exception 'Doctrine_Connection_Mysql_Exception' with message 'SQLSTATE: Integrity constraint violation: 1062 Duplicate entry 'testing' for key 'username'' in C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine\Connection.php:1084
Stack trace:
#0 C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine\Connection\Statement.php(253): Doctrine_Connection->rethrowException(Object(PDOException), Object(Doctrine_Connection_Statement))
#1 C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine\Connection.php(1049): Doctrine_Connection_Statement->execute(Array)
#2 C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine\Connection.php(693): Doctrine_Connection->exec('Insert INTO use...', Array)
#3 C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine\Connection\UnitOfWork.php(595): Doctrine_Connection->insert(Object(Doctrine_Table), Array)
#4 C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine in <b>C:\wamp\www\ci_doctrine\system\application\plugins\doctrine\lib\Doctrine\Connection.php</b> on line <b>1084</b><br />

出错是因为,我们尝试将同样的值插入到表唯一索引的字段中。

处理重复

我们可以像这样简单的检查重复:

$user_table = Doctrine::getTable('User');
if ($user_table->findOneByUsername($username)) {
    // ... username already exists!
}

这是第一次涉及到用Doctrine来获取数据记录。
在第一行,为我们的User模型获得表对象。传递的名称是模型的名称。而不是表的名称。当你的模型名称和表名称不一样的时候,知道这点很重要。
然后我们调用了一个魔术函数:findOneBy*()。只所以说它魔术,是因为它可以在其它属性上调用。例如:findOneByEmail()。你只需要在后面添加属性名称(可以是驼峰格式)。
我们可以同时为用户名和密码,把这个代码添加到_submit_validate()函数。不过这不是我想做的。

扩展CodeIgniter类库

因为我们使用Doctrine来节省时间和避免代码重复。在这里,我们以同样的想法进行才是合适的。
我们可能需要检查其它模型或来自其它控制器的重复记录。所以我们通过扩展表单验证类创建一个可重用的验证规则,

利用这种方式,其它表单将具有同样的功能而不需要有重复的代码。
创建: system/application/libraries/MY_Form_validation.php

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
    function unique($value, $params)
    {
      $CI =& get_instance();
      $CI->form_validation->set_message('unique',
            'The %s is already being used.');
      list($model, $field) = explode(".", $params, 2);
      $find = "findOneBy".$field;
      if (Doctrine::getTable($model)->$find($value)) {
            return false;
      } else {
            return true;
      }
    }
}

我们看一下代码:
第3行:新类需要有前缀MY_,并继承核心类CI_Form_validation。
第5行:我们将创建名为unique的验证规则。在form_validation类里,方法名称和规则名称是匹配的,这取决与父类是怎么样设置的。
第5行:第一个参数$value是输入表单域的值。
第5行:第二个参数$params是传送给规则的参数名称。我们的验证规则使用这样的结构:unique。你一会儿会看到。
第7-9行:我们需要得到CodeIgniter的超级对象。这样才能访问form_validation实例和设置出错信息。
第12+行:提取model.field中的值,组建findOneBy函数的名称,检查记录是否存在。


你可以在文档中阅读关于创建类库的知识。
http://codeigniter.com/user_guide/general/creating_libraries.html
http://codeigniter.org.cn/user_guide/general/creating_libraries.html

使用新的表单验证规则
编辑system/application/controllers/signup.php第二行:

<?php
class Signup extends Controller {
    // ...
    private function _submit_validate() {

      // validation rules
      $this->form_validation->set_rules('username', 'Username',
            'required|alpha_numeric|min_length|max_length|unique');
      // ...

      $this->form_validation->set_rules('email', 'E-mail',
            'required|valid_email|unique');

      // ...
    }
    // ...
}

我们使用了新的表单验证规则unique,在方括号内提供了模型的名称和表单域的名称。

再次测试表单
访问: http://localhost/ci_doctrine/signup

以同样的输入尝试注册两次。
你会看到两个错误:
http://www.phpandstuff.com/wp-content/uploads/2009/11/ci_doctrine_day3_7.png



耐心等等
这是今天的内容. 我们讨论了不少新的话题,希望你喜欢.下一部分,我们将创建一个用户登录系统。
下次见!

smallrong 发表于 2010-1-25 14:40:52

baiyuxiong 翻译的此本书必火。。。先留下买路钱。。
期待baiyuxiong 翻译发布单机版。。

baiyuxiong 发表于 2010-1-25 15:10:46

过奖了。
好些地方,翻译的比较烂。呵呵

baiyuxiong 翻译的此本书必火。。。先留下买路钱。。
期待baiyuxiong 翻译发布单机版。。 ...
smallrong 发表于 2010-1-25 14:40 http://codeigniter.org.cn/forums/images/common/back.gif

xiaokaizhi 发表于 2010-3-12 15:11:17

什么也不说了。顶了。

63606052 发表于 2010-4-15 10:35:10

还行 挺详细的

thfei1982 发表于 2010-7-8 19:14:04

作者翻译的很不错

zhangkewang 发表于 2010-7-23 11:35:24

学习

zhanglistar 发表于 2010-10-27 17:06:12

回复 1# baiyuxiong


    lz, 我按照你的做法,做了重复处理的扩展库,但是好像有问题,不能查重复,而且原来好用的页面没有显示。文件名和类名都是一样的,而且也以MY_开始,我看 了 config文件,是对的。这是什么原因呢?

jiekii 发表于 2010-12-2 01:25:59

学习了~

bluegaint 发表于 2011-7-4 14:32:55

是ci那个版本写的啊,急急急急急急急急急急急
页: [1] 2
查看完整版本: 从头学CodeIgniter和Doctrine 第三天 用户注册【翻译】下