wwwyii
- wwwyii 赞了回答
asArray返回的是一个数组不是object,当然会提示 on a non-object
登录后,
$id=Yii::$app->user->identity->id
通过这个就可以获取到你用户模型的id了,然后通过User::findOne($id)就能获得你用户资料了,只是举例,原理就是这样哦~
如我前面的回答,你需要在User中实现findIdentity($id)这个函数,返回一个User实例。和是否使用数据库保存没有关系。
我看你使用的client是通过username/password来获取信息的,但是yii\web\user仅在session/cookie中保存了id信息。你需要么让client提供一个接口,通过id获取用户数据,或者将username/password也保存到session里面,以便在findIdentiy的时候获取这两个值,通过client获取信息。你的User需要实现
findIdentity($id)
这个函数,返回一个User实例。
Yii里面的登录逻辑是这样的:在密码校验通过后,会调用Yii::$app->getUser->login($identify,$duration)
来保存登录的用户的信息;以便下次访问直接获取用户的信息,不要再次输入密码等信息。
问题1:如何保存用户的信息(/site/login)
当然是保存到session和cookie中,这里和配置信息有关。yii\web\User.php中有两个参数$enableAutoLogin, $enableSession;
$enableSession将用户信息保存在session中, $enableAutoLogin将信息进一步保存到cookie中,参考login的一段代码if ($identity) { $session->set($this->idParam, $identity->getId()); if ($this->authTimeout !== null) { $session->set($this->authTimeoutParam, time() + $this->authTimeout); } if ($this->absoluteAuthTimeout !== null) { $session->set($this->absoluteAuthTimeoutParam, time() + $this->absoluteAuthTimeout); } if ($duration > 0 && $this->enableAutoLogin) { $this->sendIdentityCookie($identity, $duration); }
问题2, 用户下次访问的时候,如何获取用户的信息(访问/site/index)
既然在问题1中保存到了session/cookie中,那么自然要从这个里面取出来。我们访问用户的信息的时候一般采用的方式是Yii::$app->getUser->getIdentity(),这个函数的功能就是从session/cookie中取出用户的数据并重构identiy实例。其中重构的关键代码如下,里面的 $class::findIdentity($id)使用来重新构建identity实例的,你的User恰好没有实现这个,所以导致啥也没有啊。protected function renewAuthStatus() { $session = Yii::$app->getSession(); $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null; if ($id === null) { $identity = null; } else { /* @var $class IdentityInterface */ $class = $this->identityClass; **_ $identity = $class::findIdentity($id);_** } $this->setIdentity($identity);
附上一段代码,是在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@tw1996 ,
如果你是要在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'], } }
最好是使用php_ini来设置这些属性,不然部署一次环境就要修改一下环境,容易出错。
- wwwyii 回答了问题 不同场景下验证规则失效
附上一段代码,是在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 - wwwyii 赞了回复
坚决不推荐第一种方法,我之前试过,TMD后期维护是个大工程
- wwwyii 赞了回复
如果每个城市的业务彼此独立,同时,城市之间的业务都非常相似,建议直接分库,这样便于后期根据城市的特点各自单独维护。
建议你采用同一份代码,部署同一个服务器,根据不同的子域名调用不同的数据库。等后期业务成长起来了,再单独部署。