2016-07-14 12:02:03 3063次浏览 3条回答 0 悬赏 40 金钱
 ['password', 'required', 'on' => 'create'],
 ['password', 'string', 'min' => 6],
 ['password', 'check'],

上面是rules()里面的规则, password字段不是数据库自带的,我添加进去的. 按理来说第三行check方法会在所有场景下都验证,但为什么只在create时候执行, update时跳过了呢?

而且我在调用之前也设置了 $model->scenario = 'update';

scenarios()也设置了

    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['update'] = ['username', 'email', 'status'];
        return $scenarios;
    }

最佳答案

  • wwwyii 发布于 2016-07-14 12:39 举报

    附上一段代码,是在insert/update之前调用的validate函数,如下;注意其中的

    if ($attributeNames === null) {
                $attributeNames = $this->activeAttributes();
            }
    

    这里的activeAttributes是当前的scenario所包含的属性,即 ['username', 'email', 'status'],接下来的校验之针对这几个属性做教研,不会针对password做校验。

    public function validate($attributeNames = null, $clearErrors = true)
        {
            if ($clearErrors) {
                $this->clearErrors();
            }
    
            if (!$this->beforeValidate()) {
                return false;
            }
    
            $scenarios = $this->scenarios();
            $scenario = $this->getScenario();
            if (!isset($scenarios[$scenario])) {
                throw new InvalidParamException("Unknown scenario: $scenario");
            }
    
            if ($attributeNames === null) {
                $attributeNames = $this->activeAttributes();
            }
    
            foreach ($this->getActiveValidators() as $validator) {
                $validator->validateAttributes($this, $attributeNames);
            }
            $this->afterValidate();
    
            return !$this->hasErrors();
        }
    

    其中 $validator->validateAttributes($this, $attributeNames);是获取当前scneriao的所有validator,然后利用这些validator对scenario包含的属性进行校验;根据你的设置,当前的validator是包含['password','check']的,但是validator检验属性的时候是要检验validator指定的属性(password)和scnario属性(email,username...)的交集;所以实际上该validator啥也没做。
    修改一下update需要检验的属性就可以了:$scenarios['update'] = ['username', 'email', 'status','password'];这样update场景下会执行pssword check和min validator

    3 条回复
    回复于 2016-07-15 09:58 回复

    这个password字段不是我数据库里面的, 而是我添加的一个模型属性, model里面代码如下:

    public function attributes()
    {
    	return array_merge(parent::attributes(),['password']);
    }
    

    在修改时数据库报错了,
    UPDATE user SET password_hash='$2y$13$Q4kI0bfeom3ELz7scyCBcuGWt05.IDmmcC6Mu52feLdfVTvtvoom6', status=10, updated_at=1468547596, password='2156795608899' WHERE id=28

    我压根没有password这个字段,如何去掉呢?

    回复于 2016-07-15 16:13 回复


    如果你是要在model中增加辅助属性,不要操作attributes函数,直接在model里面声明一个属性就可以了,这个属性和其他的attribute用法一样,但是在操作数据库的时候不会使用该属性。例如

    public UserModel extends extends ActiveRecord implements IdentityInterface{
    
        public $confirmPassword;
        public $newPassword;
        public $password;
        //以上三个属性你可以任意使用,但是和数据库没有任何关系,在更新数据表的时候不会涉及。
    
    
        public function rules(){
    
         // change password
                [['newPassword', 'confirmPassword'], 'required'],
                [['newPassword', 'confirmPassword'], 'string', 'min' => 8],
                [['confirmPassword'], 'compare', 'compareAttribute' => 'newPassword'],
         }
    }
    
    回复于 2016-07-17 09:41 回复

    恩恩,非常感谢.

  • 回答于 2016-07-14 14:11 举报

    假如
    scenarios 沒有設置
    你的寫法會讓所有的欄位被驗證

    但你
    override scenarios 的方法, 也設置了情境如下
    $scenarios['update'] = ['username', 'email', 'status']; // 當你情境為 update 時, 指驗證後方指定的欄位

    你後方尚未加入 password 所以會跳過阿~~~

    1 条回复
    回复于 2016-07-15 10:19 回复

    请看一楼评论,不知道如何解决,谢谢!

  • 回答于 2016-07-15 09:34 举报

    按你现在的配置,只是在create时才是必须的呀,别的场景下略过也不算错误吧。

您需要登录后才可以回答。登录 | 立即注册
tw1996
见习主管

tw1996

注册时间:2016-03-13
最后登录:2020-03-25
在线时长:37小时2分
  • 粉丝3
  • 金钱0
  • 威望0
  • 积分370

热门问题