1.1  登录用户校验

在登录页面,输入用户名密码后,Yii2是如何完成用户名和密码的校验的?

1.1.1  代码流程

根据Yii的规则,用户校验的入口是从Action开始的:

SiteController->actionLogin()

  LoginForm->login()

    LoginForm->validate()

     LoginForm->validatePassword()

        User->validatePassword()

 

上面的代码流程把框架内的处理给隐藏起来了,从业务上来说,就是按照上述流程处理的,最终是在User->validatePassword()函数中完成密码的校验。

1.1.2  LoginForm和User

在上述代码流程中,有两个Model

  • LoginForm

这个是登录页面的Model,按照Yii的思路,在这个Model中主要是完成输入参数的检查,譬如是否输入了用户名、密码,记住密码的数据类型是否为布尔类型等,这个Model没有跟一个实际的表关联起来。

  • User

这个是跟user表对应的Model,用来实际完成用户名和密码的校验。

 

以后如果想实现自己的登录操作,可对上面两个Model进行扩展,不过LoginForm没什么好扩展的,因为输入参数也还就是那么些,User倒是可以扩展,主要是使用自己的用户名、密码的校验算法。

1.1.3  Model的场景

LoginForm中对参数进行检查,是通过Scenario来进行的,这个词被翻译为“场景”,为什么需要场景呢?

 

模型可能在多个场景下使用,例如 User 模块可能会在收集用户登录输入,也可能会在用户注册时使用。在不同的场景下,模型可能会使用不同的业务规则和逻辑,例如 email 属性在注册时强制要求有,但在登陆时不需要。

 

所以,简单的说,就是为不同的使用情况配置不同的检查范围。因此,在这一点上来说,场景跟控制器中的过滤器有类似的作用。

 

场景和属性校验规则的关系。

 

Model中可以为属性设置校验规则,然后可以设定这些属性的校验值在哪些场景下起作用。默认是在全部场景下起作用。

 

参考文档:

1、http://www.yiichina.com/doc/guide/2.0/structure-models

2、http://blog.csdn.net/xiaoyangxiaodong/article/details/45022019

1.1.4  Model的校验器

对输入数据的校验规则多种多样,但是每个校验规则都可能被不同的Model属性所使用,譬如要求判断某个属性必须输入等,因此现在通用的方法是为每一种规则写一个校验器,然后为Model的属性配置要使用哪一个校验器,这样就实现了校验器的复用。

 

Yii中有两种校验器,一个是内置校验器,一个是Inline校验器,内置校验器就是Yii已经写好了一些常用的校验器,我们直接使用即可,而内置校验器在某些时候并不能满足需要,而且有些校验处理也并不会被复用,因此这时可以使用Inline校验器。

 

使用Inline校验器,只要在配置时,指定一个本Model的函数作为校验器函数,以LoginForm的密码属性为例:

public function rules()
 {
    
return [
        
// username and password are both required
        
[['username', 'password'], 'required'],
        
// rememberMe must be a boolean value
        
['rememberMe', 'boolean'],
        
// password is validated by  validatePassword()
        
['password', 'validatePassword'],
    
];
 
}
 
 
public function validatePassword($attribute, $params)
 {
    
if (!$this->hasErrors()) {
        
$user = $this->getUser();
         if
(!$user || !$user->validatePassword($this->password)) {
            
$this->addError($attribute, 'Incorrect username or password.');
        
}
     }
 }

 

rules()函数里配置了password的校验器为validatePassword,但是内置校验器中是没有这个的,于是在Model->load()函数中,载入属性数据并为属性创建校验器时,检查到本Model具有validatePassword接口,则就为password属性创建一个Inline校验器,执行本ModelvalidatePassword接口完成校验。