翻了两篇,突然想起来,忘了提个醒。各位看官,我所翻的这个yii 指引手册早有中文版的,可以去找来看看。本人是闲来无聊,自己翻。

        对于一个web工程来说,最主要的工作就是通过HTML表单来搜集用户的输入数据。除了设计表单,程序员还需要设置已有数据或者是默认值,验证用户输入,正确并人性化的输出错误提示信息,保存数据到存储设备。Yii通过MVC架构,非常轻松的完成以上所述的工作流。

        以下是用Yii处理form时的经典步骤:

        1、为要搜集的数据创建一个模型。

        2、创建一个控制器的动作,用来相应表单提交信息。

        3、在视图文件中,创建一个表单,用来关联控制器的动作。

        接下来,我们详细的描述以上的每个步骤。

1、创建模型

        在写表单的HTML代码前,我们先要弄明白的一点:我们希望终端用户提供什么样的数据,以及这些数据必须符合什么规则。模型类就可以用来记录这些信息的,他就是用来保存用户输入信息,并且验证信息的。

        基于我们想让用户以何种方式输入,我们可以创建两种类型的模型。如果用户数据采集使用之后,是要丢弃的,那么我们就可以创建一个form model;如果用户数据采集之后是要保存到数据库的,我们就创建一个active record。这两种模型都是继承于相同的基类CModel的,这个基类定义了一些表单常用的接口。

1.1 定义模型类

        下面我们创建一个LoginForm的模型类来采集用户在登录时的信息。因为用户登录只是验证用户信息,不需要保存,所以采用form model。(本人认为,实际应用中,用户登录信息除了校验用户的信息,一般都还是需要记录一些信息的,具体依不同项目而定)

class LoginForm extends CFormModel
{
         public $username;
         public $password;
         public $rememberMe=false;

}

以上的代码,声明了LoginForm的3个属性:$username, $password and $rememberMe. 具体干嘛用的不需要翻译了,一目了然。这些属性就是用来保存用户输入的数据或者是数据库的数据。

1.2 声明验证规则

        一旦用户提交了数据,模型获取到了输入信息,我们要验证这些输入的合法性。这个工作是由一堆的规则来验证输入的信息。我们在方法rules()中来配置这一些验证规则。

class LoginForm extends CFormModel
{
        public $username;
        public $password;
        public $rememberMe=false;
        private $ identity;3.2CreatingModel55
        public function rules()
        {
                return array(
                        array('username,password', 'required'), //表明用户名,密码是必填项
                        array('rememberMe', 'boolean'),//布尔型
                        array('password', 'authenticate'),//需到authenticate验证
                );
        }
        public function authenticate($attribute,$params)
        {
                $this-> identity=new UserIdentity($this->username,$this->password);
                if(!$this-> identity->authenticate())
                $this->addError('password','Incorrectusernameorpassword.');
        }
}

        所有的规则,都必须符合以下的格式:

        array('AttributeList', 'Validator', 'on'=>'ScenarioList',...additional options)

        AttributeList:需要用这条规则来校验的属性列表,如果是多个属性,中间用, 隔开。

        Validator:验证器。也就是指定的这些属性列表,需要用哪个校验器来检验。

        on:可选项,用来指明在什么场景需要启用该规则。

        有三种方式来选择规则中的验证器。首先,验证器可以是自身模型类的一个方法,如上例中的authenticate。验证器必须符合以下格式:public function ValidatorName($attribute,$params) {...}。第二,这个验证器可以是某个验证器类的类名称。当规则启用的时候,这个验证器类就会创建一个实例并运行起来,执行他的验证功能。规则中的addtional options就是用来初始化这个实例属性的。第三,这个验证器也可以是某个验证器的别名。上例的规则中,'required'就是CRequiredValidator的别名,用来校验所有的属性值不为空。以下列出一份完整的别名名单,能背下来最后,目前我是还没背下来:

       boolean, captcha, email, date, default, exist, file, filter, in, length, match, numerical, required, type, unique, url

        样例示范:

        // username is required
        array('username', 'required'),
        // username must be between 3 and 12 characters
        array('username', 'length', 'min'=>3, 'max'=>12),
        // when in register scenario, password must match password2
        array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
        // when in login scenario, password must be authenticated
        array('password', 'authenticate', 'on'=>'login'),

1.3 安全的给属性赋值

        在模型实例化以后,我们通常都需要由终端用户来填充数据。可以简单的由以下代码实现集体赋值(massive assignment):

        $model=new LoginForm;
        if(isset($ POST['LoginForm']))
               $model->attributes=$ POST['LoginForm'];

上例中的最后一行就是集体赋值,把从$_POST['LoginFom']的数据赋值到相对应的模型属性中。作用等同于:

        foreach($ POST['LoginForm'] as $name=>$value)
        {
                if($name is a safe attribute)
                $model->$name=$value;
        }

他的关键之处在于指定哪些属性是安全的。假设我们把某个表的主键设置为安全类型,那么当黑客有机会修改该记录的主键值,并篡改数据,这些都是不合法的。

声明安全的属性

一个属性,如果在给定的场景下,符合验证规则,那么我们就认为这个属性是安全的。例如

array('username, password', 'required', 'on'=>'login, register'),
array('email', 'required', 'on'=>'register'),

在login, register的时候,用户名,密码是必填项,在register的时候,用户名,密码,email都是必填项。

所以,在用户登录的时候,只有用户名,密码这两个属性会被集体赋值(massive assignment), 因为在登录的时候,规则只有这两个属性;同样的,在注册新用户的时候,以上的三个属性都会被集体赋值。

// in login scenario
$model=new User('login');
if(isset($ POST['User']))
        $model->attributes=$ POST['User'];
// in register scenario
$model=new User('register');
if(isset($ POST['User']))
        $model->attributes=$ POST['User'];

好了,现在的问题,我们为什么要用这样的策略来决定一个属性是否是安全的呢?想想看,如果一个属性,已经被一条或者是N条的验证规则验证过了,那么我们还有什么好担心的呢?

必须谨记的一点,验证规则主要是用来验证用户的提交数据,而不是代码所生成的数据(例如时间戳,自动生成的主键ID)。所以,千万记住,不要为那些不是从终端用户提交的数据进行规则校验。  

有时候,我们想把某些属性设置为安全属性,即使我们并没有规则来校验他。例如一篇文章的内容,可以允许任何的内容输入。这时候我们就可以使用安全规则,来强制说明这个属性是安全的:

array('content', 'safe')

有强制说明安全,那就会有强制说明不安全的了:

array('permission', 'unsafe')

这个被注明为不安全的属性有什么用呢?他很有用,是之前所提到的安全属性的一个例外。

对于这些不安全的属性,我们必须亲自一一为他们赋值,例如:

$model->permission='admin';
$model->id=1;

1.4 触发式校验

一个模型在用户提交数据之后,我们可以调用CModel::validate()的方法来触发数据校验的线程。这个方法返回一个校验的结果,通过或者不通过。对于CActiveRecord的模型来说,在我们调用CActiveRecord::save()的时候,也会自动触发该方法。

我们可以设置一个场景的属性,以及一些验证规则来校验。

校验器是在一个基础的场景使用的,这个场景的属性确定了场景是用哪个模型,以及那些校验规则会被启用。例如,在用户登录(Login)的时候,我们只想校验用户名,密码;在注册新用户的场景时,我们需要验证更多的信息,例如emai,地址等。

// creates a User model in register scenario. It is equivalent to:
// $model=new User;
// $model->scenario='register';
        $model=new User('register');
// populates the input values into the model
        $model->attributes=$ POST['User'];
// performs the validation
        if($model->validate()) // if the inputs are valid
                ...
        else
                ...

在该场景中,规则是否适用取决于规则中的"on”选项。如果规则的on选项没有被设置,则意味着该规则适用于所有场景。例如:

public function rules()
{

        return array(
                array('username, password', 'required'),
                array('password repeat', 'required', 'on'=>'register'),
                array('password', 'compare', 'on'=>'register'),
        );
}

第一条规则适用于任何场景,而第二条规则只有在regster的场景时适用。

1.5 捕获校验器错误

在验证完成之后,任何错误都可能存在于模型的对象中。怎么才能获取这些错误信息呢?我们可以通过调用CModel::getErrors() 以及CModel::getError()。这两个的区别在于第一个方法会返回校验后所有的错误信息,而后者只返回第一个错误。

1.6 属性标签

在设计的时候,我们通常需要为要输入的属性设置一个标签,用来告诉终端用户,输入的是什么项目。当然,最原始的方法,我们可以自己在视图里用代码编写一个标签,但是,有更好的方法了。最好是在当前的模型中,提供一个标签,这样既方便又容易维护。

默认情况下,CModel只是简单的用该属性的名称来作为标签。这可以通过重载attributeLabels()这个方法来设置。在后续的章节中,我们会看到在模型中设置标签,会使我们的开发更快速,也更健壮。