portal.mkgtu.ru/common/modules/abiturient/models/chat/ChatUserBase.php

776 lines
16 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace common\modules\abiturient\models\chat;
use backend\models\RBACAuthAssignment;
use common\components\LikeQueryManager;
use common\models\EmptyCheck;
use common\models\errors\RecordNotValid;
use common\models\traits\HtmlPropsEncoder;
use common\models\User;
use common\modules\abiturient\models\bachelor\ApplicationType;
use Throwable;
use Yii;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\db\Query;
use yii\helpers\StringHelper;
class ChatUserBase extends ActiveRecord
{
use HtmlPropsEncoder;
public static function tableName()
{
return '{{%chat_user}}';
}
public function behaviors()
{
return [TimestampBehavior::class];
}
public function rules()
{
return [
[
[
'user_id',
'chat_id'
],
'required'
],
[
[
'user_id',
'chat_id',
'avatar_id',
'created_at',
'updated_at',
'status',
],
'integer'
],
[
'archive',
'default',
'value' => false
],
[
[
'archive',
'online_status',
],
'boolean'
],
[
[
'first_name',
'second_name',
'last_name',
'nickname',
'email'
],
'string',
'max' => 255
],
[
['chat_id'],
'exist',
'skipOnError' => true,
'targetClass' => ChatBase::class,
'targetAttribute' => ['chat_id' => 'id']
],
[
['user_id'],
'exist',
'skipOnError' => true,
'targetClass' => User::class,
'targetAttribute' => ['user_id' => 'id']
],
];
}
public function attributeLabels()
{
return [];
}
public static function getUserRoles(): array
{
return [];
}
public function beforeDelete()
{
if (!parent::beforeDelete()) {
return false;
}
foreach ($this->getChatMessages()->all() as $dataToDelete) {
if (!$dataToDelete->delete()) {
$errorFrom = "{$dataToDelete->tableName()} -> {$dataToDelete->id}\n";
Yii::error("Ошибка при удалении данных с портала. В таблице: {$errorFrom}");
return false;
}
}
foreach ($this->getChatFiles()->all() as $chatFile) {
$chatFile->deleteAttachedFile();
}
$tnChatUsers = ChatUserBase::tableName();
$inChatHasOtherUsers = ChatBase::find()
->joinWith('chatUsers')
->andWhere(["{$tnChatUsers}.chat_id" => $this->chat_id])
->andWhere(['!=', "{$tnChatUsers}.user_id", $this->user_id])
->exists();
if (!$inChatHasOtherUsers) {
foreach ($this->getChat()->all() as $dataToDelete) {
if (!$dataToDelete->delete()) {
$errorFrom = "{$dataToDelete->tableName()} -> {$dataToDelete->id}\n";
Yii::error("Ошибка при удалении данных с портала. В таблице: {$errorFrom}");
return false;
}
}
}
return true;
}
public function getChatMessages(): ActiveQuery
{
return $this->hasMany(ChatMessageBase::class, ['author_id' => 'id']);
}
public function getChatFiles(): ActiveQuery
{
return $this->hasMany(ChatFileBase::class, ['author_id' => 'id']);
}
public function getChat(): ActiveQuery
{
return $this->hasOne(ChatBase::class, ['id' => 'chat_id']);
}
public static function hasActiveChatByUserId(int $userId): bool
{
return static::hasChatByUserIdWithStatus($userId, [ChatBase::STATUS_ACTIVE, ChatBase::STATUS_OPEN_AGAIN]);
}
public static function hasEndedChatByUserId(int $userId): bool
{
return static::hasChatByUserIdWithStatus($userId, [ChatBase::STATUS_ENDING]);
}
public static function hasChatByUserIdWithStatus(int $userId, array $statuses): bool
{
$tnChatBase = ChatBase::tableName();
$tnThatChatUsers = 'thatChatUsers';
$tnThisChatUser = 'thisChatUser';
$tnUser = User::tableName();
$subQuery = static::getAvailableUsersQuery()->select("{$tnUser}.id");
return ChatBase::find()
->joinWith('chatUsers thatChatUsers')
->joinWith('chatUsers thisChatUser')
->andWhere([
"{$tnThisChatUser}.archive" => false,
"{$tnThisChatUser}.user_id" => $userId,
])
->andWhere(['IN', "{$tnChatBase}.status", $statuses])
->andWhere(['IN', "{$tnThatChatUsers}.user_id", $subQuery])
->exists();
}
public function getUser(): ActiveQuery
{
return $this->hasOne(User::class, ['id' => 'user_id']);
}
public static function find(): ActiveQuery
{
$tnRbacAuthAssignment = RBACAuthAssignment::tableName();
$query = parent::find();
if (static::getUserRoles()) {
$query->joinWith('user.rbacAuthAssignment')
->andWhere(['IN', "{$tnRbacAuthAssignment}.item_name", static::getUserRoles()]);
}
return $query;
}
public static function getAvailableUsersQuery(): ActiveQuery
{
$tnRbacAuthAssignment = RBACAuthAssignment::tableName();
$users = User::find();
if (static::getUserRoles()) {
$users->joinWith('rbacAuthAssignment')
->andWhere(['IN', "{$tnRbacAuthAssignment}.item_name", static::getUserRoles()]);
}
return $users;
}
public static function getAvailableUsersWithChatsQuery(User $user): ActiveQuery
{
$tnChatUser = static::tableName();
$allChats = ChatUserBase::find()
->select("{$tnChatUser}.chat_id")
->andWhere([
"{$tnChatUser}.archive" => false,
"{$tnChatUser}.user_id" => $user->id
]);
return static::find()
->andWhere(["{$tnChatUser}.archive" => false])
->andWhere(['IN', "{$tnChatUser}.chat_id", $allChats]);
}
public static function getAvailableUsersWithChats(User $user): array
{
return static::getAvailableUsersWithChatsQuery($user)->all();
}
public static function getAvailableUsersWithEndingChatsQuery(User $user): ActiveQuery
{
$tnChatUser = static::tableName();
$tnChatBase = ChatBase::tableName();
$allChats = ChatUserBase::find()
->select("{$tnChatUser}.chat_id")
->joinWith('chat')
->andWhere([
"{$tnChatUser}.user_id" => $user->id,
"{$tnChatBase}.status" => ChatBase::STATUS_ENDING,
]);
return static::find()
->andWhere(['IN', "{$tnChatUser}.chat_id", $allChats]);
}
public static function getAvailableUsersWithEndingChats(User $user): array
{
return static::getAvailableUsersWithEndingChatsQuery($user)->all();
}
public static function getAvailableUsersWithoutChatsQuery(User $user): ActiveQuery
{
$tnUser = User::tableName();
$tnChatUser = static::tableName();
$availableChatsIdForCurrentUser = static::getAvailableUsersWithChatsQuery($user)
->select("{$tnChatUser}.user_id")
->column();
return static::getAvailableUsersQuery()
->andWhere(['!=', "{$tnUser}.id", $user->id])
->andWhere(['NOT IN', "{$tnUser}.id", $availableChatsIdForCurrentUser]);
}
public static function getAvailableUsersWithoutChats(User $user): array
{
return static::getAvailableUsersWithoutChatsQuery($user)->all();
}
public static function buildNewUser(User $user): ChatUserBase
{
$chatUser = new static();
$chatUser->user_id = $user->id;
return $chatUser;
}
public static function getOrCreateUser($chat, User $user): ChatUserBase
{
if (!$chat || ($chat && $chat instanceof ChatPersonToEmpty)) {
return static::buildNewUser($user);
}
$tnUser = static::tableName();
$tnChat = ChatBase::tableName();
$chatUser = static::find()
->joinWith('chat')
->andWhere([
'or',
["{$tnUser}.archive" => false],
[
'and',
["{$tnUser}.archive" => true],
["{$tnChat}.status" => ChatBase::STATUS_ENDING]
],
])
->andWhere([
"{$tnUser}.chat_id" => $chat->id,
"{$tnUser}.user_id" => $user->id,
])
->one();
if (!$chatUser) {
$chatUser = static::buildNewUser($user);
$chatUser->chat_id = $chat->id;
if (!$chatUser->save()) {
throw new RecordNotValid($chatUser);
}
}
return $chatUser;
}
public function getOnlineStatusForHuman(): string
{
return $this->online_status ?
Yii::t(
'abiturient/chat/chat-user-base',
'Подпись статуса "Онлайн", модели пользователя чата: `Онлайн`'
) :
Yii::t(
'abiturient/chat/chat-user-base',
'Подпись статуса "Оффлайн", модели пользователя чата: `Оффлайн`'
);
}
public function getOnlineStatus(): string
{
return $this->online_status ? 'online' : 'offline';
}
public function renderHeader($controller): string
{
return $controller->renderPartial(
'@chatHeaderView',
$this->processDataForRenderHeader()
);
}
public function processDataForRenderHeader(): array
{
return [
'nickname' => $this->nickname,
'destinationUserId' => $this->user_id,
'totalMessagesCount' => $this->totalMessagesCount,
];
}
public function getTotalMessagesCount(): int
{
$chat = $this->chat;
if (!$chat) {
return 0;
}
return ChatMessageBase::getTotalMessagesCount($chat) + ChatFileBase::getTotalFilesCount($chat);
}
public function getNotReadMessagesCount(): int
{
$chat = $this->chat;
if (!$chat) {
return 0;
}
return ChatMessageBase::getNotReadMessagesCountByUser($chat, $this) + ChatFileBase::getNotReadFilesCountByUser($chat, $this);
}
public static function getOtherUsersIds(int $chatId, int $userId): array
{
$chatUsers = static::find()
->andWhere(['archive' => false])
->andWhere(['chat_id' => $chatId])
->andWhere(['!=', 'id', $userId])
->all();
$usersIds = [];
foreach ($chatUsers as $chatUser) {
$usersIds[] = $chatUser->user_id;
}
return $usersIds;
}
public function makeArchive(): bool
{
$this->archive = true;
return $this->save();
}
public function makeActive(): bool
{
$this->archive = false;
return $this->save();
}
public static function filteringChatUserBySearchModel(ActiveQuery $chatUserQuery, ChatSearchModel $searchModel): ActiveQuery
{
$tnUser = User::tableName();
$tnChatUserBase = ChatUserBase::tableName();
$userSubQuery = User::find()->select("{$tnUser}.id");
if (!EmptyCheck::isEmpty($searchModel->email)) {
$userSubQuery = static::filteringChatUserByEmail($userSubQuery, $searchModel->email);
}
if (!EmptyCheck::isEmpty($searchModel->full_name)) {
$userSubQuery = static::filteringChatUserByFullName($userSubQuery, $searchModel->full_name);
}
if (!EmptyCheck::isEmpty($searchModel->applications)) {
$userSubQuery = static::filteringChatUserByApplications($userSubQuery, $searchModel->applications);
}
return $chatUserQuery->andWhere(['IN', "{$tnChatUserBase}.user_id", $userSubQuery]);
}
private static function filteringChatUserByEmail(ActiveQuery $userQuery, string $email): ActiveQuery
{
$tnUser = User::tableName();
return $userQuery->andWhere([LikeQueryManager::getActionName(), "{$tnUser}.email", $email]);
}
private static function filteringChatUserByFullName(ActiveQuery $userQuery, string $fullName): ActiveQuery
{
$tnFio = 'fio';
$tnUser = User::tableName();
$fioTable = (new Query())
->select([
'user_id AS id',
"CONCAT(lastname, ' ', firstname, ' ', middlename) AS user_fio"
])
->from('user_profile');
return $userQuery->innerJoin(
[$tnFio => $fioTable],
"{$tnFio}.id = {$tnUser}.id"
)
->andWhere([LikeQueryManager::getActionName(), "{$tnFio}.user_fio", $fullName]);
}
private static function filteringChatUserByApplications(ActiveQuery $userQuery, string $applications): ActiveQuery
{
$tnApplicationType = ApplicationType::tableName();
if ($applications == ApplicationType::ALIAS_FOR_EMPTY_APPLICATION) {
return $userQuery
->joinWith('applications.type')
->andWhere(['IN', "{$tnApplicationType}.id", [null, 0]]);
} else {
return $userQuery
->joinWith('applications.type')
->andWhere(["{$tnApplicationType}.id" => $applications]);
}
}
public static function updateUserAccount(int $chatUserId, ?string $nickname): void
{
$tnChatUserBase = ChatUserBase::tableName();
$chatUsers = ChatUserBase::find()
->andWhere(["{$tnChatUserBase}.user_id" => $chatUserId])
->all();
if (!$chatUsers) {
return;
}
$transaction = Yii::$app->db->beginTransaction();
try {
foreach ($chatUsers as $chatUser) {
$chatUser->nickname = $nickname;
if (!$chatUser->save()) {
throw new RecordNotValid($chatUser);
}
}
$transaction->commit();
} catch (Throwable $th) {
Yii::error(
"Ошибка обновления аккаунта модератора: {$th->getMessage()}",
'ChatUserBase.updateUserAccount'
);
$transaction->rollBack();
}
}
public function getShortNickNameForContactList(): string
{
$nick = $this->nickNameForContactList;
$maxNickLen = 27;
$nickEndingChars = ' ...';
return StringHelper::truncate($nick, $maxNickLen, $nickEndingChars);
}
public function getNickNameForContactList(): string
{
return $this->nickname;
}
}