My app is built on the 'advanced' Yii2 application template and my User
class is built on the Yii2-user module.
The app seems to use the custom User
model class dektrium\user\Module
to handle registration as the custom fields I've added are being stored in the database on signup, using the register()
method of the vendor User
class to do the database persistence operations.
When I access the account settings page, using the action /user/settings/account
the model class being used to display the User
data is actually common/model/User
, as shown by using get_class()
and I can't use any of the new methods defined in the custom model class.
Main config file.
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=DBNAME',
'username' => 'DBUSER',
'password' => 'DBPASS',
'charset' => 'utf8',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => false,
],
],
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
],
'rbac' => [
'class' => 'dektrium\rbac\Module'
],
],
];
And the SettingsForm
class which has a User
as a property.
<?php
/*
* This file is part of the Dektrium project.
*
* (c) Dektrium project <http://github.com/dektrium/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace dektrium\user\models;
use dektrium\user\helpers\Password;
use dektrium\user\Mailer;
use dektrium\user\Module;
use yii\base\Model;
use yii\base\NotSupportedException;
/**
* SettingsForm gets user's username, email and password and changes them.
*
* @property User $user
*
* @author Dmitry Erofeev <dmeroff@gmail.com>
*/
class SettingsForm extends Model
{
/** @var string */
public $email;
/** @var string */
// public $username;
/** @var string */
public $new_password;
/** @var string */
public $current_password;
/** @var Module */
protected $module;
/** @var Mailer */
protected $mailer;
/** @var User */
private $_user;
/** @return User */
public function getUser()
{
if ($this->_user == null) {
$this->_user = \Yii::$app->user->identity;
}
return $this->_user;
}
/** @inheritdoc */
public function __construct(Mailer $mailer, $config = [])
{
$this->mailer = $mailer;
$this->module = \Yii::$app->getModule('user');
$this->setAttributes([
//'username' => $this->user->username,
'email' => $this->user->unconfirmed_email ?: $this->user->email
], false);
parent::__construct($config);
}
/** @inheritdoc */
public function rules()
{
return [
// 'usernameRequired' => ['username', 'required'],
// 'usernameTrim' => ['username', 'filter', 'filter' => 'trim'],
// 'usernameLenth' => ['username', 'string', 'min' => 3, 'max' => 20],
// 'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'],
'emailRequired' => ['email', 'required'],
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
'emailPattern' => ['email', 'email'],
// 'emailUsernameUnique' => [['email', 'username'], 'unique', 'when' => function ($model, $attribute) {
// return $this->user->$attribute != $model->$attribute;
// }, 'targetClass' => $this->module->modelMap['User']],
'newPasswordLength' => ['new_password', 'string', 'min' => 6],
'currentPasswordRequired' => ['current_password', 'required'],
'currentPasswordValidate' => ['current_password', function ($attr) {
if (!Password::validate($this->$attr, $this->user->password_hash)) {
$this->addError($attr, \Yii::t('user', 'Current password is not valid'));
}
}]
];
}
/** @inheritdoc */
public function attributeLabels()
{
return [
'email' => \Yii::t('user', 'Email'),
'username' => \Yii::t('user', 'Username'),
'new_password' => \Yii::t('user', 'New password'),
'current_password' => \Yii::t('user', 'Current password')
];
}
/** @inheritdoc */
public function formName()
{
return 'settings-form';
}
/**
* Saves new account settings.
*
* @return bool
*/
public function save()
{
if ($this->validate()) {
// $this->user->scenario = 'settings';
// $this->user->username = $this->username;
$this->user->password = $this->new_password;
if ($this->email == $this->user->email && $this->user->unconfirmed_email != null) {
$this->user->unconfirmed_email = null;
} else if ($this->email != $this->user->email) {
switch ($this->module->emailChangeStrategy) {
case Module::STRATEGY_INSECURE:
$this->insecureEmailChange(); break;
case Module::STRATEGY_DEFAULT:
$this->defaultEmailChange(); break;
case Module::STRATEGY_SECURE:
$this->secureEmailChange(); break;
default:
throw new \OutOfBoundsException('Invalid email changing strategy');
}
}
return $this->user->save();
}
return false;
}
/**
* Changes user's email address to given without any confirmation.
*/
protected function insecureEmailChange()
{
$this->user->email = $this->email;
\Yii::$app->session->setFlash('success', \Yii::t('user', 'Your email address has been changed'));
}
/**
* Sends a confirmation message to user's email address with link to confirm changing of email.
*/
protected function defaultEmailChange()
{
$this->user->unconfirmed_email = $this->email;
/** @var Token $token */
$token = \Yii::createObject([
'class' => Token::className(),
'user_id' => $this->user->id,
'type' => Token::TYPE_CONFIRM_NEW_EMAIL
]);
$token->save(false);
$this->mailer->sendReconfirmationMessage($this->user, $token);
\Yii::$app->session->setFlash('info', \Yii::t('user', 'A confirmation message has been sent to your new email address'));
}
/**
* Sends a confirmation message to both old and new email addresses with link to confirm changing of email.
* @throws \yii\base\InvalidConfigException
*/
protected function secureEmailChange()
{
$this->defaultEmailChange();
/** @var Token $token */
$token = \Yii::createObject([
'class' => Token::className(),
'user_id' => $this->user->id,
'type' => Token::TYPE_CONFIRM_OLD_EMAIL
]);
$token->save(false);
$this->mailer->sendReconfirmationMessage($this->user, $token);
// unset flags if they exist
$this->user->flags &= ~User::NEW_EMAIL_CONFIRMED;
$this->user->flags &= ~User::OLD_EMAIL_CONFIRMED;
$this->user->save(false);
\Yii::$app->session->setFlash('info', \Yii::t('user', 'We have sent confirmation links to both old and new email addresses. You must click both links to complete your request'));
}
}
The module
property is showing the type to be the custom User
but the _user
is from the /common/models/User
.
Have I missed something to say that any User
objects should be of the custom class, so I can access the new properties/methods?
At the moment I have changed the common/models/User
class to simply extend
the User
in dektrium/user/models/User
with no actual code in the common User
class.
class User extends \dektrium\user\models\User {}
It has solved my problem for now, but it feels like a really bad solution. Any further input would be gratefully received...
Edit:
I'd forgotten about this Q&A...
in my common/config/main.php
where the user
module is declared, in the modelMap I'm able to specify to use my own custom User model, something like the following.
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
'modelMap' => [
'User' => 'common\models\User',
],
Where there is an entry for each model used by the dektrium user module.