363 lines
10 KiB
PHP
363 lines
10 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace common\components\user\models;
|
||
|
|
||
|
use Yii;
|
||
|
use yii\db\ActiveQuery;
|
||
|
use yii\db\ActiveRecord;
|
||
|
use common\helpers\UserHelper;
|
||
|
use yii\web\IdentityInterface;
|
||
|
use yii\base\NotSupportedException;
|
||
|
use yii\behaviors\AttributeBehavior;
|
||
|
use yii\behaviors\TimestampBehavior;
|
||
|
use yii\web\BadRequestHttpException;
|
||
|
|
||
|
/**
|
||
|
* @property integer $id
|
||
|
* @property string $username
|
||
|
* @property string $password_hash
|
||
|
* @property string $password_reset_token
|
||
|
* @property string $verification_token
|
||
|
* @property string $email
|
||
|
* @property string $auth_key
|
||
|
* @property integer $status
|
||
|
* @property integer $created_at
|
||
|
* @property integer $updated_at
|
||
|
* @property string $password write-only password
|
||
|
* @property integer $type
|
||
|
* @property string $role
|
||
|
* @property string $roles
|
||
|
* @property string $typeName (admin|employee|customer)
|
||
|
*
|
||
|
* @property UserAdmin $userAdmin
|
||
|
* @property UserCustomer $userCustomer
|
||
|
* @property UserEmployee $userEmployee
|
||
|
* @property UserAdmin|UserEmployee|UserCustomer $meta
|
||
|
* @property integer $quizCount
|
||
|
* @property void $quizFailed
|
||
|
*/
|
||
|
class User extends ActiveRecord implements IdentityInterface
|
||
|
{
|
||
|
const SCENARIO_USER_CREATE = 'user-create';
|
||
|
const SCENARIO_USER_ADMIN_UPDATE = 'user-admin-update';
|
||
|
const SCENARIO_USER_EMPLOYEE_UPDATE = 'user-employee-update';
|
||
|
const SCENARIO_USER_CUSTOMER_UPDATE = 'user-customer-update';
|
||
|
|
||
|
const EVENT_USER_CREATE = 'userCreateEvent';
|
||
|
const EVENT_USER_UPDATE = 'userUpdateEvent';
|
||
|
|
||
|
const EVENT_USER_STATUS_CHANGED = 'userStatusChanged';
|
||
|
const EVENT_USER_PASSWORD_CHANGED = 'userPasswordChanged';
|
||
|
|
||
|
public $agree;
|
||
|
public $role;
|
||
|
public $admin;
|
||
|
public $employee;
|
||
|
public $customer;
|
||
|
|
||
|
public $payment_bank;
|
||
|
|
||
|
public static function tableName(): string
|
||
|
{
|
||
|
return '{{%user}}';
|
||
|
}
|
||
|
|
||
|
public function rules(): array
|
||
|
{
|
||
|
return [
|
||
|
[['email'], 'unique', 'message' => Yii::t('app', 'Почта уже занята')],
|
||
|
[['username'], 'unique', 'message' => Yii::t('app', 'Логин уже занят')],
|
||
|
[['email'], 'required'],
|
||
|
[['role', 'email'], 'string'],
|
||
|
['status', 'in', 'range' => UserHelper::statusList()],
|
||
|
['type', 'in', 'range' => UserHelper::typeList()],
|
||
|
['role', 'in', 'range' => UserHelper::roleList()],
|
||
|
[['agree', 'payment_bank'], 'safe'],
|
||
|
['role', 'required', 'on' => self::SCENARIO_USER_CREATE],
|
||
|
[['employee', 'customer', 'admin'], 'safe'],
|
||
|
];
|
||
|
}
|
||
|
|
||
|
public function behaviors(): array
|
||
|
{
|
||
|
return [
|
||
|
TimestampBehavior::class,
|
||
|
[
|
||
|
'class' => AttributeBehavior::class,
|
||
|
'attributes' => [
|
||
|
ActiveRecord::EVENT_BEFORE_INSERT => 'username',
|
||
|
ActiveRecord::EVENT_BEFORE_UPDATE => 'username',
|
||
|
],
|
||
|
'value' => function ($event) {
|
||
|
return $this->email;
|
||
|
},
|
||
|
],
|
||
|
];
|
||
|
}
|
||
|
|
||
|
public function afterSave($insert, $changedAttributes)
|
||
|
{
|
||
|
if ($insert) {
|
||
|
if ($this->scenario === self::SCENARIO_USER_CREATE) {
|
||
|
$this->trigger(self::EVENT_USER_CREATE);
|
||
|
}
|
||
|
|
||
|
//todo add scenario user status change
|
||
|
}
|
||
|
|
||
|
parent::afterSave($insert, $changedAttributes);
|
||
|
}
|
||
|
|
||
|
public function scenarios()
|
||
|
{
|
||
|
$scenarios = parent::scenarios();
|
||
|
$scenarios[self::SCENARIO_USER_CREATE] = ['type', 'status', 'email', 'agree', 'role'];
|
||
|
$scenarios[self::SCENARIO_USER_ADMIN_UPDATE] = ['type', 'status', 'email', 'role', 'admin'];
|
||
|
$scenarios[self::SCENARIO_USER_EMPLOYEE_UPDATE] = ['type', 'status', 'email', 'role', 'employee'];
|
||
|
$scenarios[self::SCENARIO_USER_CUSTOMER_UPDATE] = ['type', 'status', 'email', 'role', 'customer'];
|
||
|
return $scenarios;
|
||
|
}
|
||
|
|
||
|
public function attributeLabels(): array
|
||
|
{
|
||
|
return [
|
||
|
'id' => Yii::t('user', 'ID'),
|
||
|
'email' => Yii::t('user', 'Email'),
|
||
|
'name' => Yii::t('user', 'Имя'),
|
||
|
'username' => Yii::t('user', 'Логин'),
|
||
|
'status' => Yii::t('user', 'Статус'),
|
||
|
'type' => Yii::t('user', 'Тип'),
|
||
|
'role' => Yii::t('user', 'Роль'),
|
||
|
'created_at' => Yii::t('user', 'Создан'),
|
||
|
'updated_at' => Yii::t('user', 'Обновлён'),
|
||
|
];
|
||
|
}
|
||
|
|
||
|
public function setRole($role): void
|
||
|
{
|
||
|
if (!isset($role)) {
|
||
|
throw new BadRequestHttpException();
|
||
|
}
|
||
|
$auth = Yii::$app->authManager;
|
||
|
$role = $auth->getRole($role);
|
||
|
if ($role) {
|
||
|
$auth->revokeAll($this->id);
|
||
|
$auth->assign($role, $this->id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function getRole()
|
||
|
{
|
||
|
$role = Yii::$app->authManager->getRolesByUser($this->id);
|
||
|
if ($role) {
|
||
|
return $role;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public function getTypeName(): string
|
||
|
{
|
||
|
return match ($this->type) {
|
||
|
UserHelper::TYPE_CUSTOMER => 'customer',
|
||
|
UserHelper::TYPE_EMPLOYEE => 'employee',
|
||
|
UserHelper::TYPE_ADMIN => 'admin',
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public function getUserAdmin(): ActiveQuery
|
||
|
{
|
||
|
return $this->hasOne(UserAdmin::class, ['user_id' => 'id']);
|
||
|
}
|
||
|
|
||
|
public function getUserCustomer(): ActiveQuery
|
||
|
{
|
||
|
return $this->hasOne(UserCustomer::class, ['user_id' => 'id']);
|
||
|
}
|
||
|
|
||
|
public function getUserEmployee(): ActiveQuery
|
||
|
{
|
||
|
return $this->hasOne(UserEmployee::class, ['user_id' => 'id']);
|
||
|
}
|
||
|
|
||
|
public function getMeta(): UserAdmin|UserEmployee|UserCustomer
|
||
|
{
|
||
|
return match ($this->type) {
|
||
|
UserHelper::TYPE_ADMIN => $this->userAdmin,
|
||
|
UserHelper::TYPE_EMPLOYEE => $this->userEmployee,
|
||
|
default => $this->userCustomer,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
static public function current(): User|IdentityInterface|null
|
||
|
{
|
||
|
return Yii::$app->user->identity;
|
||
|
}
|
||
|
|
||
|
public static function findIdentity($id): User|IdentityInterface|null
|
||
|
{
|
||
|
return static::findOne(['and',
|
||
|
['id' => $id],
|
||
|
['>=', 'status', UserHelper::STATUS_NEW],
|
||
|
]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static function findIdentityByAccessToken($token, $type = null): ?IdentityInterface
|
||
|
{
|
||
|
//todo translate
|
||
|
throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
|
||
|
}
|
||
|
|
||
|
public static function findByUsername(string $email)
|
||
|
{
|
||
|
$user = User::find()->where(['and',
|
||
|
['or',
|
||
|
['email' => $email],
|
||
|
['username' => $email],
|
||
|
],
|
||
|
['>=', 'status', UserHelper::STATUS_NEW],
|
||
|
])->one();
|
||
|
|
||
|
return $user ?? null;
|
||
|
}
|
||
|
|
||
|
public static function findByPasswordResetToken($token): array|ActiveRecord|null
|
||
|
{
|
||
|
if (!static::isPasswordResetTokenValid($token)) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
return static::find()->where(['and',
|
||
|
['password_reset_token' => $token],
|
||
|
['>=', 'status', UserHelper::STATUS_NEW],
|
||
|
])->one();
|
||
|
}
|
||
|
|
||
|
public static function findByVerificationToken($token): array|ActiveRecord|null
|
||
|
{
|
||
|
return static::find()->where(['and',
|
||
|
['verification_token' => $token],
|
||
|
['>=', 'status', UserHelper::STATUS_NEW],
|
||
|
])->one();
|
||
|
}
|
||
|
|
||
|
public static function isPasswordResetTokenValid($token): bool
|
||
|
{
|
||
|
if (empty($token)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$timestamp = (int)substr($token, strrpos($token, '_') + 1);
|
||
|
$expire = Yii::$app->params['user.passwordResetTokenExpire'];
|
||
|
|
||
|
return $timestamp + $expire >= time();
|
||
|
}
|
||
|
|
||
|
public function getId()
|
||
|
{
|
||
|
return $this->getPrimaryKey();
|
||
|
}
|
||
|
|
||
|
public function getAuthKey(): ?string
|
||
|
{
|
||
|
return $this->auth_key;
|
||
|
}
|
||
|
|
||
|
public function validatePhone(string $phone): bool
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public function validateAuthKey($authKey): bool
|
||
|
{
|
||
|
return $this->getAuthKey() === $authKey;
|
||
|
}
|
||
|
|
||
|
public function validatePassword(string $password): bool
|
||
|
{
|
||
|
return Yii::$app->security->validatePassword($password, $this->password_hash);
|
||
|
}
|
||
|
|
||
|
public function setPassword(string $password)
|
||
|
{
|
||
|
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
|
||
|
}
|
||
|
|
||
|
public function generateAuthKey()
|
||
|
{
|
||
|
$this->auth_key = Yii::$app->security->generateRandomString();
|
||
|
}
|
||
|
|
||
|
public function generatePasswordResetToken()
|
||
|
{
|
||
|
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
|
||
|
}
|
||
|
|
||
|
public function generateEmailVerificationToken()
|
||
|
{
|
||
|
$this->verification_token = Yii::$app->security->generateRandomString() . '_' . time();
|
||
|
}
|
||
|
|
||
|
public function removePasswordResetToken()
|
||
|
{
|
||
|
$this->password_reset_token = null;
|
||
|
}
|
||
|
|
||
|
public function quizStart($count, $time): void
|
||
|
{
|
||
|
if (UserHelper::TYPE_EMPLOYEE == $this->type) {
|
||
|
$user = UserEmployee::find()->where(['user_id' => $this->id])->one();
|
||
|
if ($user) {
|
||
|
$user->test_try_count = $count;
|
||
|
$user->test_at = $time;
|
||
|
$user->test_result = null;
|
||
|
$user->save(false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function quizFailed(): void
|
||
|
{
|
||
|
if (UserHelper::TYPE_EMPLOYEE == $this->type) {
|
||
|
$this->status = UserHelper::STATUS_BLOCKED_AUTO;
|
||
|
$this->save(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function setTestResult(bool $result): void
|
||
|
{
|
||
|
if (UserHelper::TYPE_EMPLOYEE == $this->type) {
|
||
|
if ($result) {
|
||
|
$this->status = UserHelper::STATUS_TEST;
|
||
|
$this->save(false);
|
||
|
}
|
||
|
$this->meta->test_result = time();
|
||
|
$this->meta->save(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function testAt(): int|null
|
||
|
{
|
||
|
if (UserHelper::TYPE_EMPLOYEE == $this->type) {
|
||
|
return $this->meta->test_at;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public function testTryCount(): int
|
||
|
{
|
||
|
if (UserHelper::TYPE_EMPLOYEE == $this->type) {
|
||
|
return $this->meta->test_try_count ?? 0;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public function getTestResult(): int|null
|
||
|
{
|
||
|
if (UserHelper::TYPE_EMPLOYEE == $this->type) {
|
||
|
return $this->meta->test_result ?? null;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
}
|