Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/im/lib/V2/ |
Upload File : |
<?php namespace Bitrix\Im\V2; use Bitrix\Im\V2\Chat\Copilot\CopilotPopupItem; use Bitrix\Im\V2\Chat\ChannelChat; use Bitrix\Im\V2\Chat\Comment\CommentPopupItem; use Bitrix\Im\V2\Chat\Copilot\Entity; use Bitrix\Im\V2\Entity\File\FilePopupItem; use Bitrix\Im\V2\Entity\Url\UrlCollection; use Bitrix\Im\V2\Entity\User\UserPopupItem; use Bitrix\Im\V2\Integration\AI\RoleManager; use Bitrix\Im\V2\Link\Pin\PinService; use Bitrix\Im\V2\Message\AdditionalMessagePopupItem; use Bitrix\Im\V2\Message\Param; use Bitrix\Im\V2\Message\Reaction\ReactionMessages; use Bitrix\Im\V2\Message\Reaction\ReactionPopupItem; use Bitrix\Im\V2\Message\ReadService; use Bitrix\Im\V2\TariffLimit\DateFilterable; use Bitrix\Im\V2\TariffLimit\FilterResult; use Bitrix\Imbot\Bot\CopilotChatBot; use Bitrix\Main\Loader; use Bitrix\Main\ORM\Query\Query; use Bitrix\Main\ORM\Fields\ExpressionField; use Bitrix\Im\Model\MessageTable; use Bitrix\Im\Model\MessageParamTable; use Bitrix\Im\Model\MessageUuidTable; use Bitrix\Im\V2\Common\ContextCustomer; use Bitrix\Im\V2\Entity\File\FileCollection; use Bitrix\Im\V2\Link\Reminder\ReminderCollection; use Bitrix\Im\V2\Rest\PopupData; use Bitrix\Im\V2\Rest\PopupDataAggregatable; use Bitrix\Im\V2\Rest\RestConvertible; use Bitrix\Im\V2\Service\Context; use Bitrix\Im\V2\Message\Params; use Bitrix\Main\Type\DateTime; /** * @extends Collection<Message> * @method self filter(callable $predicate) * @method Message offsetGet($key) */ class MessageCollection extends Collection implements RestConvertible, PopupDataAggregatable, DateFilterable { use ContextCustomer; protected bool $isFileFilled = false; protected bool $isParamsFilled = false; protected bool $isUuidFilled = false; protected bool $isUrlsFilled = false; protected bool $isUnreadFilled = false; protected bool $isViewedFilled = false; protected bool $isReactionsFilled = false; //region Collection /** * @inheritdoc * @return string */ public static function getCollectionElementClass(): string { return Message::class; } /** * @inheritdoc */ public static function find(array $filter, array $order, ?int $limit = null, ?Context $context = null, array $select = []): self { //$context = $context ?? Locator::getContext(); $query = MessageTable::query(); $query->setSelect(['ID']); if (isset($limit)) { $query->setLimit($limit); } $messageOrder = ['DATE_CREATE' => $order['ID'] ?? 'DESC', 'ID' => $order['ID'] ?? 'DESC']; $query->setOrder($messageOrder); static::processFilters($query, $filter, $messageOrder); $messageIds = $query->fetchCollection()->getIdList(); if (empty($messageIds)) { return new static(); } if (empty($select)) { $select = ['*']; } return new static(MessageTable::query()->whereIn('ID', $messageIds)->setOrder($messageOrder)->setSelect($select)->fetchCollection()); } /** * @return int[] */ public function getIds(): array { return $this->getPrimaryIds(); } /** * @return array<int, int[]> */ public function getFileIds(): array { $this->fillParams(); $ids = []; foreach ($this as $message) { if ($message->getParams()->isSet(Params::FILE_ID)) { $ids[$message->getId()] = $message->getParams()->get(Params::FILE_ID)->getValue(); } } return $ids; } public function getCommonChatId(): ?int { $id = null; foreach ($this as $message) { if (isset($id) && $message->getChatId() !== $id) { return null; } if (!isset($id)) { $id = $message->getChatId(); } } return $id; } public function getCommonChat(): ?Chat { $chatId = $this->getCommonChatId(); return $chatId ? Chat::getInstance($chatId) : null; } //endregion //region Rest public function toRestFormat(array $option = []): array { $this->fillAllForRest($option['MESSAGE_SHORT_INFO'] ?? false, $option['MESSAGE_ONLY_COMMON_FIELDS'] ?? false); $messagesForRest = []; foreach ($this as $message) { $messagesForRest[] = $message->toRestFormat($option); } return $messagesForRest; } public static function getRestEntityName(): string { return 'messages'; } /** * @param DateTime $date * @return FilterResult<static> */ public function filterByDate(DateTime $date): FilterResult { $filtered = $this->filter(static fn (Message $message) => $message->getDateCreate()?->getTimestamp() > $date->getTimestamp()); return (new FilterResult())->setResult($filtered)->setFiltered($this->count() !== $filtered->count()); } public function getRelatedChatId(): ?int { return $this->getCommonChatId(); } //endregion //region Fillers /** * @return self */ public function fillFiles(): self { if (!$this->isFileFilled) { $fileIdsByMessages = $this->getFileIds(); $fileIds = []; foreach ($fileIdsByMessages as $fileIdsByMessage) { foreach ($fileIdsByMessage as $fileId) { $fileIds[] = $fileId; } } $files = FileCollection::initByDiskFilesIds($fileIds); foreach ($this as $message) { $messagesFiles = new FileCollection(); foreach ($fileIdsByMessages[$message->getId()] ?? [] as $fileId) { $file = $files->getById($fileId); if ($file !== null) { $messagesFiles[] = $file->setChatId($message->getChatId()); } } $message->fillFiles($messagesFiles); } $this->isFileFilled = true; } return $this; } /** * @return self */ public function fillParams(): self { if ($this->isParamsFilled) { return $this; } $messageIds = $this->getIds(); if (!empty($messageIds)) { foreach ($this as $message) { $message->getParams(true)->load([]); } $paramsCollection = MessageParamTable::query() ->setSelect(['*']) ->whereIn('MESSAGE_ID', $this->getIds()) ->whereNot('PARAM_NAME', 'LIKE') ->fetchCollection() ; foreach ($paramsCollection as $paramRow) { $this[$paramRow->getMessageId()]->getParams(true)->load($paramRow); } $this->isParamsFilled = true; } return $this; } public function isParamsFilled(): bool { return $this->isParamsFilled; } public function deleteParams(): self { if (!empty($this->getIds())) { $filter = [ '=MESSAGE_ID' => $this->getIds(), ]; MessageParamTable::deleteBatch($filter); } foreach ($this as $message) { $message->getParams(true)->clear(); } $this->isParamsFilled = true; return $this; } /** * @param array $params * @return self */ public function resetParams($params): self { if (empty($this->getIds())) { return $this; } return $this ->deleteParams() ->multiAddParams($params) ; } protected function multiAddParams($params): self { $rows = $this->getParamsFieldsForMultiAdd($params); if (empty($rows)) { return $this; } $result = Param::getDataClass()::addMulti($rows, true); if (!$result->isSuccess()) { return $this; } $this->isParamsFilled = false; $this->fillParams(); return $this; } protected function getParamsFieldsForMultiAdd(array $params): array { $fields = []; foreach ($this as $message) { foreach ($params as $paramName => $paramValue) { $fields[] = [ 'MESSAGE_ID' => $message->getId(), 'PARAM_NAME' => $paramName, 'PARAM_VALUE' => $paramValue, ]; } } return $fields; } /** * @param array $params * @return self */ public function setParams($params): self { foreach ($this as $message) { $message->setParams($params); } return $this; } /** * @return self */ public function fillUuid(): self { $messageIds = $this->getIds(); if (!$this->isUuidFilled && !empty($messageIds)) { $uuids = MessageUuidTable::query() ->setSelect(['UUID', 'MESSAGE_ID']) ->whereIn('MESSAGE_ID', $this->getIds()) ->fetchAll() ; $uuidsByMessageId = []; foreach ($uuids as $uuid) { $uuidsByMessageId[$uuid['MESSAGE_ID']] = $uuid['UUID']; } foreach ($this as $message) { $message->setUuid($uuidsByMessageId[$message->getId()] ?? null); } $this->isUuidFilled = true; } return $this; } /** * @return self */ public function fillUrls(): self { if ($this->isUrlsFilled) { return $this; } $this->fillParams(); $urlIdByMessageIds = []; foreach ($this as $message) { $urlId = $message->getParams()->get(Params::URL_ID)->getValue()[0] ?? null; if (isset($urlId)) { $urlIdByMessageIds[$message->getId()] = $urlId; } } $urlCollection = UrlCollection::initByPreviewUrlsIds($urlIdByMessageIds, false); foreach ($this as $message) { if (isset($urlIdByMessageIds[$message->getId()])) { $urlId = $urlIdByMessageIds[$message->getId()]; $message->setUrl($urlCollection->getById($urlId)); } } $this->isUrlsFilled = true; return $this; } /** * @return self */ public function fillUnread(): self { if ($this->isUnreadFilled) { return $this; } $readStatuses = (new ReadService())->getReadStatusesByMessageIds($this->getIds()); foreach ($this as $message) { $message->setUnread(!($readStatuses[$message->getMessageId()])); } $this->isUnreadFilled = true; return $this; } public function fillViewed(): self { if ($this->isViewedFilled) { return $this; } $notOwnMessages = []; foreach ($this as $message) { if ($message->getAuthorId() === $this->getContext()->getUserId()) { $message->setViewed(true); continue; } $notOwnMessages[] = $message->getMessageId(); } $viewStatuses = (new ReadService())->getViewStatusesByMessageIds($notOwnMessages); foreach ($notOwnMessages as $notOwnMessageId) { $this[$notOwnMessageId]->setViewed($viewStatuses[$notOwnMessageId]); } $this->isViewedFilled = true; return $this; } public function fillReactions(): self { if ($this->isReactionsFilled) { return $this; } $messageIds = $this->getIds(); if (empty($messageIds)) { return $this; } $reactions = new ReactionMessages($messageIds); foreach ($this as $message) { $message->setReactions($reactions->getReactionMessage($message->getMessageId())); } $this->isReactionsFilled = true; return $this; } /** * @return self */ public function fillAllForRest(bool $shortInfo = false, bool $onlyCommonInfo = false): self { if (!$shortInfo) { $this->fillUrls()->fillReactions(); } if (!$onlyCommonInfo) { $this->fillUnread()->fillViewed(); } return $this ->fillParams() ->fillUuid() ; } //endregion public function setViewedByOthers(): self { foreach ($this as $message) { if (!$message->isNotifyRead()) { $message->markNotifyRead(true); } } return $this; } //region Getters /** * @return FileCollection */ public function getFiles(): FileCollection { $this->fillFiles(); $files = new FileCollection(); foreach ($this as $message) { $filesFromMessage = $message->getFiles(); foreach ($filesFromMessage as $fileFromMessage) { $files[] = $fileFromMessage; } } return $files->getUnique(); } public function getUserIds(): array { $users = []; $this->fillParams(); foreach ($this as $message) { $usersFromMessage = $message->getUserIds(); if ($message->getParams()->isSet(Params::FORWARD_USER_ID)) { $forwardUserId = $message->getParams()->get(Params::FORWARD_USER_ID)->getValue(); $usersFromMessage[] = $forwardUserId; } if ($message->getParams()->isSet(Params::CHAT_USER)) { foreach ($message->getParams()->get(Params::CHAT_USER)->getValue() as $chatUser) { $usersFromMessage[] = $chatUser; } } foreach ($usersFromMessage as $userFromMessage) { $users[] = $userFromMessage; } } return $users; } /** * @return ReminderCollection */ public function getReminders(): ReminderCollection { return ReminderCollection::getByMessagesAndAuthorId($this, $this->getContext()->getUserId()); } public function getReplayedMessageIds(): array { $this->fillParams(); $result = []; foreach ($this as $message) { if ($message->getParams()->isSet(Params::REPLY_ID)) { $result[] = $message->getParams()->get(Params::REPLY_ID)->getValue(); } } return $result; } public function getReactions(): ReactionMessages { $reactions = new ReactionMessages([]); $this->fillReactions(); foreach ($this as $message) { $reactions->addReactionMessage($message->getReactions()); } return $reactions; } protected function getCopilotRoles(): array { $this->fillParams(); $copilotRoles = []; foreach ($this as $message) { $params = $message->getParams(); if ($params->isSet(Params::COPILOT_ROLE)) { if ($params->isSet(Params::FORWARD_ID)) { $messageId = (int)$params->get(Params::FORWARD_ID)->getValue(); } $copilotRoles[$messageId ?? $message->getId()] = $params->get(Params::COPILOT_ROLE)->getValue(); continue; } if (!$params->isSet(Params::COMPONENT_ID)) { continue; } $messageComponentId = $params->get(Params::COMPONENT_ID)->getValue(); if ( Loader::includeModule('imbot') && in_array($messageComponentId, CopilotChatBot::ALL_COPILOT_MESSAGE_COMPONENTS, true) ) { $copilotRoles[$message->getId()] = RoleManager::getDefaultRoleCode(); } } return $copilotRoles; } public function getPopupData(array $excludedList = []): PopupData { $additionalMessageIds = array_diff($this->getReplayedMessageIds(), $this->getIds()); $popup = [ new UserPopupItem($this->getUserIds()), new FilePopupItem($this->getFiles()), //new ReminderPopupItem($this->getReminders()), new AdditionalMessagePopupItem($additionalMessageIds), new CopilotPopupItem($this->getCopilotRoles(), Entity::Messages), ]; if (!in_array(ReactionPopupItem::class, $excludedList, true)) { $popup[] = new ReactionPopupItem($this->getReactions()); } $chat = $this->getAny()?->getChat(); if ($chat instanceof ChannelChat) { $popup[] = new CommentPopupItem($chat->getId(), $this->getIds()); } return new PopupData($popup, $excludedList); } public function filterByChatId(int $chatId): self { $filteredCollection = new static(); foreach ($this as $message) { if ($message->getChatId() === $chatId) { $filteredCollection->add($message); } } return $filteredCollection; } //endregion public function unpin(bool $clearParams = true): Result { $pinService = new PinService(); $pinService->setContext($this->context); return $pinService->unpinMessages($this, $clearParams); } protected static function processFilters(Query $query, array $filter, array $order): void { if (isset($filter['CHAT_ID'])) { $query->where('CHAT_ID', $filter['CHAT_ID']); } if (isset($filter['SEARCH_MESSAGE']) && mb_strlen($filter['SEARCH_MESSAGE']) > 2) { $connection = \Bitrix\Main\Application::getConnection(); if ($connection instanceof \Bitrix\Main\DB\PgsqlConnection) { $filter['SEARCH_MESSAGE'] = $connection->getSqlHelper()->forSql($filter['SEARCH_MESSAGE']); $query->registerRuntimeField( new ExpressionField( 'CASE_INSENSITIVE_MESSAGE', "(CASE WHEN %s ILIKE '%%{$filter['SEARCH_MESSAGE']}%%' THEN 1 ELSE 0 END)", ['MESSAGE'] ) ); $query->where('CASE_INSENSITIVE_MESSAGE', '=', '1'); } else { $query->whereLike('MESSAGE', "%{$filter['SEARCH_MESSAGE']}%"); } } if (isset($filter['START_ID']) && (int)$filter['START_ID'] > 0) { $query->where('ID', '>=', $filter['START_ID']); } if (isset($filter['LAST_ID'])) { $operator = $order['ID'] === 'DESC' ? '<' : '>'; $query->where('ID', $operator, $filter['LAST_ID']); } if (isset($filter['DATE_FROM'])) { $query->where('DATE_CREATE', '>=', $filter['DATE_FROM']); } if (isset($filter['DATE_TO'])) { $query->where('DATE_CREATE', '<=', $filter['DATE_TO']); } if (isset($filter['DATE'])) { $query->where('DATE_CREATE', '>=', $filter['DATE']); $to = clone $filter['DATE']; $to->add('1 DAY'); $query->where('DATE_CREATE', '<=', $to); } if ($filter['WITHOUT_SYSTEM_MESSAGE'] ?? false) { $query->where('AUTHOR_ID', '!=', 0); } } }