用户
 找回密码
 入住 CI 中国社区
搜索
查看: 18389|回复: 11
收起左侧

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

  [复制链接]
发表于 2010-1-25 14:29:24 | 显示全部楼层 |阅读模式
本帖最后由 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
HTML复制代码
 
<!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">assword: </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


在浏览器上查看源文件:
HTML复制代码
 
<!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
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[type=text],input[type=password] {
    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[type=submit] {
    display: block;
    margin: auto;
    width: 200px;
    font-size: 18px;
    background-color: #FFF;
    border: 1px solid #BBB;
}
#signup_form form input[type=submit]:hover {
    border-color: #000;
}
#signup_form .error {
    font-size: 13px;
    color: #690C07;
    font-style: italic;
}
 
复制代码

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

添加高亮显示的行:
HTML复制代码
 
<!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, 看到:



表单验证

如果你现在点击submit按钮,你将收到一个404错误:



因为submit() 方法不存在.
编辑: system/application/controllers/signup.php
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[6]|max_length[12]');
        $this->form_validation->set_rules('password', 'Password',
            'required|min_length[6]|max_length[12]');
        $this->form_validation->set_rules('passconf', 'Confirm Password',
            'required|matches[password]');
        $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)。
我们来看看表单验证是如何工作的。
当我们一开始载入表单验证类库时,
首先设置规则:
PHP复制代码
 
$this->form_validation->set_rules('username', 'Username','required|alpha_numeric|min_length[6]|max_length[12]');
复制代码


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

显示验证错误

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

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">assword: </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
HTML复制代码
 
Success!
复制代码


测试表单
在表单里输入一些无效的数据并提交。


http://localhost/ci_doctrine/signup

如果你输入的信息是正确的,你应该能看到Success!消息。

保存用户

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

编辑system/application/controllers/signup.php下的submit()函数。
PHP复制代码
<?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, 输入合适的值提交.
检查数据表的内容:

运行正常,但我们还没完全完成。


一个小问题
试试以同样的用户名和e-mail提交表单。你将看到:
HTML复制代码
<br />
<b>Fatal error</b>:  Uncaught exception 'Doctrine_Connection_Mysql_Exception' with message 'SQLSTATE[23000]: 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 />
 
复制代码

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

处理重复

我们可以像这样简单的检查重复:
PHP复制代码
 
$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复制代码
 
<?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[model.field]。你一会儿会看到。
第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复制代码
 
<?php
class Signup extends Controller {
    // ...
    private function _submit_validate() {
 
        // validation rules
        $this->form_validation->set_rules('username', 'Username',
            'required|alpha_numeric|min_length[6]|max_length[12]|unique[User.username]');
        // ...
 
        $this->form_validation->set_rules('email', 'E-mail',
            'required|valid_email|unique[User.email]');
 
        // ...
    }
    // ...
}
 
复制代码

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

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

以同样的输入尝试注册两次。
你会看到两个错误:




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

评分

参与人数 1威望 +5 收起 理由
Hex + 5 精品文章

查看全部评分

发表于 2010-1-25 14:40:52 | 显示全部楼层
baiyuxiong 翻译的此本书必火。。。先留下买路钱。。
期待baiyuxiong 翻译发布单机版。。
 楼主| 发表于 2010-1-25 15:10:46 | 显示全部楼层
过奖了。
好些地方,翻译的比较烂。呵呵

baiyuxiong 翻译的此本书必火。。。先留下买路钱。。
期待baiyuxiong 翻译发布单机版。。 ...
smallrong 发表于 2010-1-25 14:40
发表于 2010-3-12 15:11:17 | 显示全部楼层
什么也不说了。顶了。
发表于 2010-4-15 10:35:10 | 显示全部楼层
还行 挺详细的
发表于 2010-7-8 19:14:04 | 显示全部楼层
作者翻译的很不错
发表于 2010-7-23 11:35:24 | 显示全部楼层
学习
发表于 2010-10-27 17:06:12 | 显示全部楼层
回复 1# baiyuxiong


    lz, 我按照你的做法,做了重复处理的扩展库,但是好像有问题,不能查重复,而且原来好用的页面没有显示。文件名和类名都是一样的,而且也以MY_开始,我看 了 config文件,是对的。这是什么原因呢?
发表于 2010-12-2 01:25:59 | 显示全部楼层
学习了~
发表于 2011-7-4 14:32:55 | 显示全部楼层
是ci那个版本写的啊,急急急急急急急急急急急

本版积分规则