从Yii2 的uniq 校验器和getOldPrimaryKey() 方法谈起

技巧库 · wy1272086709 · 于 2年前 发布 · 2615 次阅读
	public function actionIndex4()
    {
        header('Content-Type:text/html;charset=UTF-8');
        $id = 3;
        $user = \app\models\UserForm::findOne($id);
        $user->id = '4';
        $user->save();


        $user1 = new \app\models\UserForm;
        
        $data = [
            'username' => 'yonghu3',
            'area_code' => '440507',
            'password'  => '123456',
            'verifyPassword' => '123456',
            'roles' => 'juese222',
            'login_time' => '2017-04-10 10:39:35',
        ];
        $user1->load($data,'');
        $re = $user1->save();
    

        var_dump($re);
        var_dump($user->getOldPrimaryKey());
        var_dump($user->getPrimaryKey());

        var_dump($user1->getOldPrimaryKey());
        var_dump($user1->getPrimaryKey());
        exit;
    }

由以上代码可以大略知道,当主键的值发生变化的时候,getOldPrimaryKey()方法会保存一个副本。
再看php UniqueValidator 类中的代码:
 /**
     * @inheritdoc
     */
    public function validateAttribute($model, $attribute)
    {
        /* @var $targetClass ActiveRecordInterface */
        $targetClass = $this->targetClass === null ? get_class($model) : $this->targetClass;
        $targetAttribute = $this->targetAttribute === null ? $attribute : $this->targetAttribute;

        if (is_array($targetAttribute)) {
            $params = [];
            foreach ($targetAttribute as $k => $v) {
                $params[$v] = is_int($k) ? $model->$v : $model->$k;
            }
        } else {
            $params = [$targetAttribute => $model->$attribute];
        }

        foreach ($params as $value) {
            if (is_array($value)) {
                $this->addError($model, $attribute, Yii::t('yii', '{attribute} is invalid.'));

                return;
            }
        }

        $query = $targetClass::find();
        $query->andWhere($params);

        if ($this->filter instanceof \Closure) {
            call_user_func($this->filter, $query);
        } elseif ($this->filter !== null) {
            $query->andWhere($this->filter);
        }

        if (!$model instanceof ActiveRecordInterface || $model->getIsNewRecord() || $model->className() !== $targetClass::className()) {
            // if current $model isn't in the database yet then it's OK just to call exists()
            // also there's no need to run check based on primary keys, when $targetClass is not the same as $model's class
            $exists = $query->exists();
        } else {
            // if current $model is in the database already we can't use exists()
            /* @var $models ActiveRecordInterface[] */
            $models = $query->limit(2)->all();
            $n = count($models);
            if ($n === 1) {
                $keys = array_keys($params);
                $pks = $targetClass::primaryKey();
                sort($keys);
                sort($pks);
                if ($keys === $pks) {
                    // primary key is modified and not unique
                    $exists = $model->getOldPrimaryKey() != $model->getPrimaryKey();
                } else {
                    // non-primary key, need to exclude the current record based on PK
                    $exists = $models[0]->getPrimaryKey() != $model->getOldPrimaryKey();
                }
            } else {
                $exists = $n > 1;
            }
        }

        if ($exists) {
            $this->addError($model, $attribute, $this->message);
        }
    }
由以上代码可以看出,当UniqueValidator 所在的模型类不继承ActiveRecordInterface 接口,或者对应模型在新增记录,或者设置了targetClass 属性,但与模型类对应的targetClass 属性不相等,就会简单的判断属性和对应的值在数据表中是否存在。若存在,就不是唯一,验证通不过。当主键被修改了,或者对应的属性值有多条记录,就会被当作不唯一,校验失败。
共收到 0 条回复
没有找到数据。
添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册