new-support.webeffector.ru/common/components/user/models/User.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;
}
}