1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
ReadService.php
См. документацию.
1<?php
2
3namespace Bitrix\Im\V2\Message;
4
5use Bitrix\Im\Model\ChatTable;
6use Bitrix\Im\Model\MessageUnreadTable;
7use Bitrix\Im\Model\MessageViewedTable;
8use Bitrix\Im\Model\RelationTable;
9use Bitrix\Im\Recent;
10use Bitrix\Im\V2\Chat;
11use Bitrix\Im\V2\Common\ContextCustomer;
12use Bitrix\Im\V2\Message;
13use Bitrix\Im\V2\MessageCollection;
14use Bitrix\Im\V2\Relation;
15use Bitrix\Im\V2\RelationCollection;
16use Bitrix\Im\V2\Result;
17use Bitrix\Im\V2\Service\Context;
18use Bitrix\Im\V2\Sync;
19use Bitrix\Main\Application;
20use Bitrix\Main\DB\SqlExpression;
21
23{
24 use ContextCustomer
25 {
26 setContext as private defaultSetContext;
27 }
28
31
32 private static array $lastMessageIdCache = [];
33
34 public function __construct(?int $userId = null)
35 {
36 $this->counterService = new CounterService();
37 $this->viewedService = new ViewedService();
38
39 if (isset($userId))
40 {
41 $context = new Context();
42 $context->setUser($userId);
43 $this->setContext($context);
44 $this->counterService->setContext($context);
45 $this->viewedService->setContext($context);
46 }
47 }
48
49 public function readTo(Message $message): Result
50 {
51 $this->setLastIdForRead($message->getMessageId(), $message->getChatId());
52 $this->counterService->deleteTo($message);
53 $counter = $this->counterService->getByChat($message->getChatId());
54 $viewResult = $this->viewedService->addTo($message);
55 $this->updateDateRecent($message->getChatId());
57 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $message->getChatId()),
58 $this->getContext()->getUserId(),
59 $message->getChat()
60 );
61
62 $viewedMessages = [];
63 if ($viewResult->isSuccess())
64 {
65 $viewedMessages = $viewResult->getResult()['VIEWED_MESSAGES'] ?? [];
66 }
67
68 return (new Result())->setResult(['COUNTER' => $counter, 'VIEWED_MESSAGES' => $viewedMessages]);
69 }
70
71 public function read(MessageCollection $messages, Chat $chat): Result
72 {
73 $maxId = max($messages->getIds());
74 $this->setLastIdForRead($maxId, $chat->getChatId());
75 $this->counterService->deleteTo($messages[$maxId]);
76 $counter = $this->counterService->getByChat($chat->getChatId());
77 $messagesToView = $messages
78 ->withContextUser($this->getContext()->getUserId())
79 ->fillViewed()
80 ->filter(fn (Message $message) => !$message->isViewed())
81 ;
82 $this->viewedService->add($messagesToView);
83 $this->updateDateRecent($chat->getChatId());
85 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $chat->getChatId()),
86 $this->getContext()->getUserId(),
87 $chat
88 );
89
90 return (new Result())->setResult(['COUNTER' => $counter, 'VIEWED_MESSAGES' => $messagesToView]);
91 }
92
93 public function readNotifications(MessageCollection $messages, array $userByChatId): Result
94 {
95 $chatIds = [];
96
97 foreach ($messages as $message)
98 {
99 $chatIds[$message->getChatId()] = 0;
100 }
101
102 $chatIds = array_keys($chatIds);
103
104 $this->counterService->deleteByMessagesForAll($messages, $userByChatId);
105 $counters = $this->counterService->getForNotifyChats($chatIds);
106 $time = microtime(true);
107 //$this->viewedController->add($messages);
108
109 /*foreach ($chatIds as $chatId)
110 {
111 $this->sendPush($chatId, [(int)$userByChatId[$chatId]], $counters[$chatId], $time);
112 Sync\Logger::getInstance()->add(
113 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $chatId),
114 (int)$userByChatId[$chatId]
115 );
116 }*/
117
118 return (new Result())->setResult(['COUNTERS' => $counters]);
119 }
120
121 public function readAllInChat(int $chatId): Result
122 {
123 $lastId = $this->getLastMessageIdInChat($chatId);
124 $this->setLastIdForRead($lastId, $chatId);
125 $this->counterService->deleteByChatId($chatId);
126 $counter = 0;
127 //$this->viewedController->addAllFromChat($chatId);
128 $this->updateDateRecent($chatId);
129 $chat = Chat::getInstance($chatId);
131 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $chatId),
132 $this->getContext()->getUserId(),
133 $chat
134 );
135
136 if ($chat instanceof Chat\ChannelChat)
137 {
138 $userId = $this->getContext()->getUserId();
139 Application::getInstance()->addBackgroundJob(fn () => $this->withContextUser($userId)->readChildren($chat));
140 }
141
142 return (new Result())->setResult(['COUNTER' => $counter, 'VIEWED_MESSAGES' => new MessageCollection()]);
143 }
144
145 public function readChildren(Chat $parentChat): array
146 {
147 $childrenToRead = CounterService::getChildrenWithCounters($parentChat, $this->getContext()->getUserId());
148
149 if (empty($childrenToRead))
150 {
151 return $childrenToRead;
152 }
153
154 $this->setLastIdForReadByIds($childrenToRead);
155 $this->counterService->deleteByChatIds($childrenToRead);
156
157 return $childrenToRead;
158 }
159
160 public function readAll(): void
161 {
162 $this->setLastIdForReadAll();
163 $this->counterService->deleteAll();
165 new Sync\Event(Sync\Event::READ_ALL_EVENT, Sync\Event::CHAT_ENTITY, 0),
166 $this->getContext()->getUserId()
167 );
168 }
169
170 public function unreadTo(Message $message): Result
171 {
172 //$this->setLastIdForUnread($message->getMessageId(), $message->getChatId());
173 $relation = $message->getChat()->withContext($this->context)->getSelfRelation();
174 if ($relation === null)
175 {
176 return new Result();
177 }
178 $this->counterService->addStartingFrom($message->getMessageId(), $relation);
179 $this->viewedService->deleteStartingFrom($message);
181 new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $message->getChatId()),
182 $this->getContext()->getUserId(),
183 $message->getChat()
184 );
185
186 return new Result();
187 }
188
190 {
191 $this->counterService->addCollection($messages, $relation);
192 $counter = $this->counterService->getByChatWithOverflow($relation->getChatId());
193
194 return (new Result())->setResult(['COUNTER' => $counter]);
195 }
196
205 {
206 $this->counterService->addForEachUser($message, $relations);
207 return $this;
208 }
209
217 public function markMessageUnread(Message $message, RelationCollection $relations): self
218 {
219 $this->counterService->addForEachUser($message, $relations);
220 $this->counterService->deleteTo($message);
221 return $this;
222 }
223
230 public function markRecentUnread(Message $message): self
231 {
232 $chat = $message->getChat()->withContext($this->context);
233 Recent::unread($chat->getDialogId(), false, $this->getContext()->getUserId(), null, $chat->getType());
234 return $this;
235 }
236
245 {
246 return $this->counterService->getByChatForEachUsers($message->getChatId(), $relations->getUserIds(), 100);
247 }
248
256 public function onAfterMessageSend(Message $message, RelationCollection $relations, bool $withoutCounters = false): Result
257 {
258 if (!$withoutCounters)
259 {
260 $this->markMessageUnread($message, $relations);
261 }
262
263 $counters = $this
264 ->markRecentUnread($message)
265 ->getCountersForUsers($message, $relations)
266 ;
267
268 return (new Result())->setResult(['COUNTERS' => $counters]);
269 }
270
271 public function deleteByMessage(Message $message, ?array $invalidateCacheUsers = null): void
272 {
273 $this->counterService->deleteByMessageForAll($message, $invalidateCacheUsers);
274 $this->viewedService->deleteByMessageIdForAll($message->getMessageId());
275 }
276
277 public function deleteByMessages(MessageCollection $messages, ?array $invalidateCacheUsers = null): void
278 {
279 $this->counterService->deleteByMessagesForAll($messages, $invalidateCacheUsers);
280 $this->viewedService->deleteByMessagesIdsForAll($messages->getIds());
281 }
282
283 public function deleteByChatId(int $chatId): void
284 {
285 $this->counterService->deleteByChatId($chatId);
286 $this->viewedService->deleteByChatId($chatId);
287 }
288
289 /*public function deleteByMessageIds(array $messageIds): void
290 {
291 $this->counterService->deleteByMessageIdsForAll($messageIds);
292 $this->viewedController->deleteByMessageIdsForAll($messageIds);
293 }*/
294
295 public function getReadStatusesByMessageIds(array $messageIds): array
296 {
297 if (empty($messageIds))
298 {
299 return [];
300 }
301
302 $query = MessageUnreadTable::query()
303 ->setSelect(['MESSAGE_ID'])
304 ->whereIn('MESSAGE_ID', $messageIds)
305 ->where('USER_ID', $this->getContext()->getUserId())
306 ->exec()
307 ; //todo add index
308
309 $unreadMessages = [];
310
311 while ($row = $query->fetch())
312 {
313 $unreadMessages[(int)$row['MESSAGE_ID']] = false;
314 }
315
316 $readStatuses = [];
317
318 foreach ($messageIds as $messageId)
319 {
320 $readStatuses[$messageId] = $unreadMessages[$messageId] ?? true;
321 }
322
323 return $readStatuses;
324 }
325
326 public function getViewStatusesByMessageIds(array $messageIds): array
327 {
328 if (empty($messageIds))
329 {
330 return [];
331 }
332
333 $query = MessageViewedTable::query()
334 ->setSelect(['MESSAGE_ID'])
335 ->whereIn('MESSAGE_ID', $messageIds)
336 ->where('USER_ID', $this->getContext()->getUserId())
337 ->exec()
338 ; //todo add index
339
340 $viewedMessages = [];
341
342 while ($row = $query->fetch())
343 {
344 $viewedMessages[(int)$row['MESSAGE_ID']] = true;
345 }
346
347 $viewStatuses = [];
348
349 foreach ($messageIds as $messageId)
350 {
351 $viewStatuses[$messageId] = $viewedMessages[$messageId] ?? false;
352 }
353
354 return $viewStatuses;
355 }
356
357 public function getLastIdByChatId(int $chatId): int
358 {
359 $relation = RelationTable::query()
360 ->setSelect(['LAST_ID'])
361 ->where('USER_ID', $this->getContext()->getUserId())
362 ->where('CHAT_ID', $chatId)->setLimit(1)
363 ->fetch();
364
365 if ($relation)
366 {
367 return $relation['LAST_ID'] ?? 0;
368 }
369
370 return 0;
371 }
372
373 public function getLastMessageIdInChat(int $chatId): int
374 {
375 if (isset(static::$lastMessageIdCache[$chatId]))
376 {
377 return static::$lastMessageIdCache[$chatId];
378 }
379
380 $result = ChatTable::query()->setSelect(['LAST_MESSAGE_ID'])->where('ID', $chatId)->fetch();
381 $lastMessageId = 0;
382
383 if (!$result)
384 {
385 $lastMessageId = 0;
386 }
387 else
388 {
389 $lastMessageId = (int)($result['LAST_MESSAGE_ID'] ?? 0);
390 }
391
392 static::$lastMessageIdCache[$chatId] = $lastMessageId;
393
394 return $lastMessageId;
395 }
396
397 public function getChatMessageStatus(int $chatId): string
398 {
399 $lastMessageId = $this->getLastMessageIdInChat($chatId);
400
401 if ($lastMessageId === 0)
402 {
403 return \IM_MESSAGE_STATUS_RECEIVED;
404 }
405
406 return $this->viewedService->getMessageStatus($lastMessageId);
407 }
408
410 {
412 }
413
415 {
417 }
418
419
420 public function setLastIdForRead(int $lastId, int $chatId): void
421 {
422 $sql = "
423 UPDATE b_im_relation
424 SET LAST_ID=(CASE WHEN LAST_ID > {$lastId} THEN LAST_ID ELSE {$lastId} END)
425 WHERE CHAT_ID={$chatId} AND USER_ID={$this->getContext()->getUserId()}
426 ";
427
428 Application::getConnection()->queryExecute($sql);
429 }
430
431 public function setContext(?Context $context): self
432 {
433 $this->defaultSetContext($context);
434 $this->getCounterService()->setContext($context);
435 $this->getViewedService()->setContext($context);
436
437 return $this;
438 }
439
440 private function getChildrenToReadIds(Chat $parentChat): array
441 {
442 $parentId = $parentChat->getId();
443 if (!$parentId)
444 {
445 return [];
446 }
447
448 $query = ChatTable::query()
449 ->setSelect(['ID'])
450 ->where('PARENT_ID', $parentId)
451 ;
452 $alias = Application::getConnection()->getSqlHelper()->quote($query->getInitAlias());
453
454 $subQuery = MessageUnreadTable::query()
455 ->setSelect(['CHAT_ID'])
456 ->where('USER_ID', $this->getContext()->getUserId())
457 ->where('CHAT_ID', new SqlExpression('?#', "{$alias}.ID"))
458 ;
459
460 return $query
461 ->whereIn('ID', $subQuery)
462 ->fetchCollection()
463 ->getIdList()
464 ;
465 }
466
467 private function setLastIdForReadAll(): void
468 {
469 $connection = Application::getConnection();
470 $helper = $connection->getSqlHelper();
471
472 $connection->queryExecute($helper->prepareCorrelatedUpdate(
473 'b_im_relation',
474 'R',
475 [
476 'LAST_ID' => 'C.LAST_MESSAGE_ID',
477 ],
478 ' b_im_chat C ',
479 " C.ID = R.CHAT_ID AND R.MESSAGE_TYPE NOT IN ('" . IM_MESSAGE_OPEN_LINE . "', '" . IM_MESSAGE_SYSTEM . "')
480 AND R.USER_ID = {$this->getContext()->getUserId()}"
481 ));
482 }
483
484 private function setLastIdForReadByIds(array $chatIds): void
485 {
486 if (empty($chatIds))
487 {
488 return;
489 }
490
491 $chatIdsString = implode(',', $chatIds);
492 $connection = Application::getConnection();
493 $helper = $connection->getSqlHelper();
494
495 $connection->queryExecute($helper->prepareCorrelatedUpdate(
496 'b_im_relation',
497 'R',
498 [
499 'LAST_ID' => 'C.LAST_MESSAGE_ID',
500 ],
501 ' b_im_chat C ',
502 " C.ID = R.CHAT_ID AND R.CHAT_ID IN ({$chatIdsString}) AND R.USER_ID = {$this->getContext()->getUserId()}"
503 ));
504 }
505
506 private function updateDateRecent(int $chatId): void
507 {
508 $userId = $this->getContext()->getUserId();
509 \Bitrix\Main\Application::getConnection()->query(
510 "UPDATE b_im_recent SET DATE_UPDATE = NOW() WHERE USER_ID = {$userId} AND ITEM_CID = {$chatId}"
511 );
512 }
513}
$connection
Определения actionsdefinitions.php:38
if(! $messageFields||!isset($messageFields['message_id'])||!isset($messageFields['status'])||!CModule::IncludeModule("messageservice")) $messageId
Определения callback_ismscenter.php:26
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static unread($dialogId, $unread, $userId=null, ?int $markedId=null, ?string $itemTypes=null)
Определения recent.php:1674
__construct(?int $userId=null)
Определения ReadService.php:34
deleteByChatId(int $chatId)
Определения ReadService.php:283
ViewedService $viewedService
Определения ReadService.php:30
getReadStatusesByMessageIds(array $messageIds)
Определения ReadService.php:295
deleteByMessages(MessageCollection $messages, ?array $invalidateCacheUsers=null)
Определения ReadService.php:277
readTo(Message $message)
Определения ReadService.php:49
read(MessageCollection $messages, Chat $chat)
Определения ReadService.php:71
getViewStatusesByMessageIds(array $messageIds)
Определения ReadService.php:326
CounterService $counterService
Определения ReadService.php:29
readChildren(Chat $parentChat)
Определения ReadService.php:145
readNotifications(MessageCollection $messages, array $userByChatId)
Определения ReadService.php:93
unreadNotifications(MessageCollection $messages, Relation $relation)
Определения ReadService.php:189
readAllInChat(int $chatId)
Определения ReadService.php:121
getChatMessageStatus(int $chatId)
Определения ReadService.php:397
setLastIdForRead(int $lastId, int $chatId)
Определения ReadService.php:420
onAfterMessageSend(Message $message, RelationCollection $relations, bool $withoutCounters=false)
Определения ReadService.php:256
getCountersForUsers(Message $message, RelationCollection $relations)
Определения ReadService.php:244
markRecentUnread(Message $message)
Определения ReadService.php:230
getLastMessageIdInChat(int $chatId)
Определения ReadService.php:373
setContext(?Context $context)
Определения ReadService.php:431
markMessageUnread(Message $message, RelationCollection $relations)
Определения ReadService.php:217
deleteByMessage(Message $message, ?array $invalidateCacheUsers=null)
Определения ReadService.php:271
unreadTo(Message $message)
Определения ReadService.php:170
getLastIdByChatId(int $chatId)
Определения ReadService.php:357
markNotificationUnread(Message $message, RelationCollection $relations)
Определения ReadService.php:204
getMessageId()
Определения Message.php:806
static getInstance()
Определения Logger.php:37
static getInstance()
Определения application.php:98
static getConnection($name="")
Определения application.php:638
Определения result.php:20
static getInstance()
Определения servicelocator.php:33
if(!\Bitrix\Main\Loader::includeModule('clouds')) $lastId
Определения sync.php:68
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$query
Определения get_search.php:11
const IM_MESSAGE_SYSTEM
Определения include.php:21
const IM_MESSAGE_OPEN_LINE
Определения include.php:26
$context
Определения csv_new_setup.php:223
Определения Uuid.php:3
Определения ChatsSync.php:3
Определения culture.php:9
$time
Определения payment.php:61
$message
Определения payment.php:8
$counter
Определения options.php:5
$messages
Определения template.php:8
$counters
Определения options.php:100