1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
CounterService.php
См. документацию.
1<?php
2
3namespace Bitrix\Im\V2\Message;
4
5use Bitrix\Im\Model\ChatTable;
6use Bitrix\Im\Model\MessageTable;
7use Bitrix\Im\Model\MessageUnreadTable;
8use Bitrix\Im\Model\RecentTable;
9use Bitrix\Im\V2\Application\Features;
10use Bitrix\Im\V2\Chat;
11use Bitrix\Im\V2\Chat\NotifyChat;
12use Bitrix\Im\V2\Common\ContextCustomer;
13use Bitrix\Im\V2\Entity\User\User;
14use Bitrix\Im\V2\Message;
15use Bitrix\Im\V2\Message\Counter\CounterOverflowService;
16use Bitrix\Im\V2\MessageCollection;
17use Bitrix\Im\V2\Relation;
18use Bitrix\Im\V2\RelationCollection;
19use Bitrix\Im\V2\Service\Context;
20use Bitrix\Main\ArgumentException;
21use Bitrix\Main\Data\Cache;
22use Bitrix\Main\Loader;
23use Bitrix\Main\ObjectPropertyException;
24use Bitrix\Main\ORM\Fields\ExpressionField;
25use Bitrix\Main\SystemException;
26use Bitrix\Main\Type\DateTime;
27use CTimeZone;
28
30{
31 use ContextCustomer;
32
33 protected const DELAY_DELETION_COUNTERS_OF_FIRED_USER = 604800; // 1 week
34 protected const EXPIRY_INTERVAL = '-12 months';
35
36 protected const CACHE_TTL = 86400; // 1 month
37 protected const CACHE_NAME = 'counter_v5';
38 protected const CACHE_CHATS_COUNTERS_NAME = 'chats_counter_v6';
39 protected const CACHE_PATH = '/bx/im/counter/v5/';
40
41 protected const DEFAULT_COUNTERS = [
42 'TYPE' => [
43 'ALL' => 0,
44 'NOTIFY' => 0,
45 'CHAT' => 0,
46 'LINES' => 0,
47 'COPILOT' => 0,
48 'COLLAB' => 0,
49 'MESSENGER' => 0,
50 ],
51 'CHAT' => [],
52 'COLLAB' => [],
53 'CHAT_MUTED' => [],
54 'CHAT_UNREAD' => [],
55 'COLLAB_UNREAD' => [],
56 'COPILOT_UNREAD' => [],
57 'LINES' => [],
58 'COPILOT' => [],
59 'CHANNEL_COMMENT' => [],
60 ];
61
62 protected static array $staticCounterCache = [];
63 protected static array $staticChatsCounterCache = [];
65
66 protected array $counters;
67 protected array $countersByChatIds = [];
68
69 public function __construct(?int $userId = null)
70 {
71 $this->counters = static::DEFAULT_COUNTERS;
72
73 if (isset($userId))
74 {
75 $context = new Context();
76 $context->setUser($userId);
77 $this->setContext($context);
78 }
79 }
80
81 public function getTotal(): int
82 {
83 $totalUnreadMessages = $this->getTotalCountUnreadMessages();
84 $unreadUnmutedChats = $this->getUnreadChats(false);
85
86 return $totalUnreadMessages + count($unreadUnmutedChats);
87 }
88
89 public function getByChatForEachUsers(int $chatId, array $userIds): array
90 {
91 $result = [];
92 $overflowService = new CounterOverflowService($chatId);
93 $overflowInfo = $overflowService->getOverflowInfo($userIds);
94
95 $countForEachUsers = $this->getCountUnreadMessagesByChatIdForEachUsers($chatId, $overflowInfo->getUsersWithoutOverflow());
96
97 foreach ($countForEachUsers as $countForUser)
98 {
99 $result[(int)$countForUser['USER_ID']] = (int)$countForUser['COUNT'];
100 }
101
102 $overflowService->insertOverflowed($result);
103
104 foreach ($userIds as $userId)
105 {
106 if ($overflowInfo->hasOverflow($userId))
107 {
108 $result[$userId] = CounterOverflowService::getOverflowValue();
109 }
110 if (!isset($result[$userId]))
111 {
112 $result[$userId] = 0;
113 }
114 }
115
116 return $result;
117 }
118
119 public function getByChat(int $chatId): int
120 {
121 return $this->getCountUnreadMessagesByChatId($chatId);
122 }
123
124 public function getByChatWithOverflow(int $chatId): int
125 {
126 $currentUser = $this->getContext()->getUserId();
127 $overflowService = new CounterOverflowService($chatId);
128 $overflowInfo = $overflowService->getOverflowInfo([$currentUser]);
129
130 if (!empty($overflowInfo->getUsersWithoutOverflow()))
131 {
132 $count = $this->getCountUnreadMessagesByChatId($chatId);
133 $overflowService->insertOverflowed([$currentUser => $count]);
134
135 return $count;
136 }
137
138 return CounterOverflowService::getOverflowValue();
139 }
140
141 public function get(): array
142 {
143 $userId = $this->getContext()->getUserId();
144 if (isset(self::$staticCounterCache[$userId]))
145 {
146 return self::$staticCounterCache[$userId];
147 }
148
149 $cache = $this->getCacheForPreparedCounters();
150 $cachedCounters = $cache->getVars();
151 if ($cachedCounters !== false)
152 {
153 self::$staticCounterCache[$userId] = $cachedCounters;
154
155 return $cachedCounters;
156 }
157
158 $this->counters = static::DEFAULT_COUNTERS;
159 $this->countersByChatIds = [];
160
161 $this->countUnreadMessages();
162 $this->countUnreadChats();
163
164 $this->savePreparedCountersInCache($cache);
166
167 return $this->counters;
168 }
169
170 public function getForEachChat(?array $chatIds = null): array
171 {
172 $userId = $this->getContext()->getUserId();
173 if (isset(self::$staticChatsCounterCache[$userId]))
174 {
175 return self::$staticChatsCounterCache[$userId];
176 }
177
178 if ($chatIds !== null && $this->haveInSpecificChatsCache($chatIds))
179 {
180 return static::$staticSpecificChatsCounterCache[$userId] ?? [];
181 }
182
183 $cache = $this->getCacheForChatsCounters();
184 $cachedCounters = $cache->getVars();
185 if ($cachedCounters !== false)
186 {
187 self::$staticChatsCounterCache[$userId] = $cachedCounters;
188
189 return $cachedCounters;
190 }
191
192 $this->counters = static::DEFAULT_COUNTERS;
193 $this->countersByChatIds = [];
194
195 $this->countUnreadMessages($chatIds);
196
197 if ($chatIds === null)
198 {
199 $this->saveChatsCountersInCache($cache);
200 }
201 else
202 {
203 $this->saveSpecificChatsCountersInCache($chatIds);
204 }
205
206 return $this->countersByChatIds;
207 }
208
209 public function getForNotifyChat(): int
210 {
211 $findResult = NotifyChat::find(['TO_USER_ID' => $this->getContext()->getUserId()]);
212
213 if (!$findResult->isSuccess())
214 {
215 return 0;
216 }
217
218 $chatId = (int)$findResult->getResult()['ID'];
219
220 return $this->getByChatWithOverflow($chatId);
221 }
222
223 public function getForNotifyChats(array $chatIds): array
224 {
225 if (empty($chatIds))
226 {
227 return [];
228 }
229
230 $counters = $this->getCountersForEachChat($chatIds, false);
231 $countersByChatId = [];
232
233 foreach ($counters as $counter)
234 {
235 $countersByChatId[$counter['CHAT_ID']] = $counter['COUNT'];
236 }
237
238 $result = [];
239
240 foreach ($chatIds as $chatId)
241 {
242 $result[$chatId] = $countersByChatId[$chatId] ?? 0;
243 }
244
245 return $result;
246 }
247
248 public function getIdFirstUnreadMessage(int $chatId): ?int
249 {
250 $result = MessageUnreadTable::query()
251 ->setSelect(['MIN'])
252 ->where('CHAT_ID', $chatId)
253 ->where('USER_ID', $this->getContext()->getUserId())
254 ->registerRuntimeField('MIN', new ExpressionField('MIN', 'MIN(%s)', ['MESSAGE_ID']))
255 ->fetch()
256 ;
257
258 return isset($result['MIN']) ? (int)$result['MIN'] : null;
259 }
260
262 {
263 if (empty($chatIds))
264 {
265 return [];
266 }
267
268 $result = MessageUnreadTable::query()
269 ->setSelect(['CHAT_ID', 'UNREAD_ID' => new ExpressionField('UNREAD_ID', 'MIN(%s)', ['MESSAGE_ID'])])
270 ->whereIn('CHAT_ID', $chatIds)
271 ->where('USER_ID', $this->getContext()->getUserId())
272 ->setGroup(['CHAT_ID'])
273 ->fetchAll() //todo index (CHAT_ID, USER_ID, MESSAGE_ID)
274 ;
275
276 $firstUnread = [];
277
278 foreach ($result as $row)
279 {
280 $firstUnread[(int)$row['CHAT_ID']] = (int)$row['UNREAD_ID'];
281 }
282
283 return $firstUnread;
284 }
285
286 public function updateIsMuted(int $chatId, string $isMuted): void
287 {
288 MessageUnreadTable::updateBatch(
289 ['IS_MUTED' => $isMuted],
290 ['=CHAT_ID' => $chatId, '=USER_ID' => $this->getContext()->getUserId()]
291 );
292 static::clearCache($this->getContext()->getUserId());
293 }
294
295 public function deleteByChatId(int $chatId): void
296 {
297 if ($this->getContext()->getUserId() <= 0)
298 {
299 return;
300 }
301
302 MessageUnreadTable::deleteByFilter(['=CHAT_ID' => $chatId, '=USER_ID' => $this->getContext()->getUserId()]);
303 static::clearCache($this->getContext()->getUserId());
304 (new CounterOverflowService($chatId))->delete($this->getContext()->getUserId());
305 }
306
307 public static function deleteByChatIdForAll(int $chatId): void
308 {
309 MessageUnreadTable::deleteByFilter(['=CHAT_ID' => $chatId]);
310 CounterOverflowService::deleteByChatIdForAll($chatId);
311 }
312
313 public static function deleteByChatIdsForAll(array $chatIds): void
314 {
315 MessageUnreadTable::deleteByFilter(['=CHAT_ID' => $chatIds]);
316 CounterOverflowService::deleteByChatIds($chatIds);
317 }
318
319 public function deleteByChatIds(array $chatIds): void
320 {
321 if (empty($chatIds) || $this->getContext()->getUserId() <= 0)
322 {
323 return;
324 }
325
326 MessageUnreadTable::deleteByFilter(['=CHAT_ID' => $chatIds, '=USER_ID' => $this->getContext()->getUserId()]);
327 static::clearCache($this->getContext()->getUserId());
328 CounterOverflowService::deleteByChatIds($chatIds, $this->getContext()->getUserId());
329 }
330
331 /*public function deleteByChatIdForAll(int $chatId): void
332 {
333 MessageUnreadTable::deleteByFilter(['=CHAT_ID' => $chatId]);
334 static::clearCache();
335 }*/
336
342 public function deleteAll(bool $withNotify = false): void
343 {
345 $this->getContext()->getUserId(),
346 $withNotify,
347 );
348 }
349
350 public static function getChildrenWithCounters(Chat $parentChat, ?int $userId = null): array
351 {
352 $parentId = $parentChat->getId();
353 if (!$parentId)
354 {
355 return [];
356 }
357
358 $query = MessageUnreadTable::query()
359 ->setSelect(['CHAT_ID'])
360 ->where('PARENT_ID', $parentId)
361 ->addGroup('CHAT_ID')
362 ;
363
364 if (isset($userId))
365 {
366 $query->where('USER_ID', $userId);
367 }
368
369 $parentIds = [];
370 foreach ($query->fetchAll() as $row)
371 {
372 $parentIds[] = isset($row['CHAT_ID']) ? (int)$row['CHAT_ID'] : 0;
373 }
374
375 return $parentIds;
376 }
377
378 public function addForEachUser(Message $message, RelationCollection $relations): void
379 {
380 $insertFields = [];
381 $usersIds = [];
382
383 foreach ($relations as $relation)
384 {
385 if ($relation->getMessageType() !== \IM_MESSAGE_SYSTEM && $message->getAuthorId() === $relation->getUserId())
386 {
387 continue;
388 }
389
390 $insertFields[] = $this->prepareInsertFields($message, $relation);
391 $usersIds[] = $relation->getUserId();
392 }
393
394 MessageUnreadTable::multiplyInsertWithoutDuplicate($insertFields);
395 foreach ($usersIds as $userId)
396 {
397 static::clearCache($userId);
398 }
399 }
400
401 public function addCollection(MessageCollection $messages, Relation $relation): void
402 {
403 $insertFields = [];
404
405 foreach ($messages as $message)
406 {
407 if ($relation->getMessageType() !== \IM_MESSAGE_SYSTEM && $message->getAuthorId() === $relation->getUserId())
408 {
409 continue;
410 }
411
412 $insertFields[] = $this->prepareInsertFields($message, $relation);
413 }
414
415 MessageUnreadTable::multiplyInsertWithoutDuplicate($insertFields);
416 static::clearCache($relation->getUserId());
417 }
418
419 public function addStartingFrom(int $messageId, Relation $relation): void
420 {
421 $query = MessageTable::query()
422 ->setSelect([
423 'ID_CONST' => new ExpressionField('ID_CONST', '0'),
424 'USER_ID_CONST' => new ExpressionField('USER_ID_CONST', (string)$this->getContext()->getUserId()),
425 'CHAT_ID_CONST' => new ExpressionField('CHAT_ID', (string)$relation->getChatId()),
426 'MESSAGE_ID' => 'ID',
427 'IS_MUTED' => new ExpressionField('IS_MUTED', $relation->getNotifyBlock() ? "'Y'" : "'N'"),
428 'CHAT_TYPE' => new ExpressionField('CHAT_TYPE', "'{$relation->getMessageType()}'"),
429 'DATE_CREATE'
430 ])
431 ->where('CHAT_ID', $relation->getChatId())
432 ->where('MESSAGE_ID', '>=', $messageId)
433 ;
434 if ($relation->getMessageType() !== \IM_MESSAGE_SYSTEM)
435 {
436 $query->whereNot('AUTHOR_ID', $this->getContext()->getUserId());
437 }
438
439 MessageUnreadTable::insertSelect($query, ['ID', 'USER_ID', 'CHAT_ID', 'MESSAGE_ID', 'IS_MUTED', 'CHAT_TYPE', 'DATE_CREATE']);
440
441 static::clearCache($this->getContext()->getUserId());
442 }
443
444 public function deleteByMessageForAll(Message $message, ?array $invalidateCacheUsers = null): void
445 {
446 if (empty($message->getId()))
447 {
448 return;
449 }
450
451 MessageUnreadTable::deleteByFilter(['=MESSAGE_ID' => $message->getId()]);
452 CounterOverflowService::deleteByChatIdForAll($message->getChatId());
453
454 if (!isset($invalidateCacheUsers))
455 {
456 static::clearCache();
457
458 return;
459 }
460
461 foreach ($invalidateCacheUsers as $user)
462 {
463 static::clearCache((int)$user);
464 }
465 }
466
467 public function deleteByMessagesForAll(MessageCollection $messages, ?array $invalidateCacheUsers = null): void
468 {
469 $messageIds = $messages->getIds();
470 $chatIds = [];
471 if (empty($messageIds))
472 {
473 return;
474 }
475
476 foreach ($messages as $message)
477 {
478 $chatId = $message->getChatId();
479 $chatIds[$chatId] = $chatId;
480 }
481
482 MessageUnreadTable::deleteByFilter(['=MESSAGE_ID' => $messageIds]);
483 CounterOverflowService::deleteByChatIds($chatIds);
484
485 if (!isset($invalidateCacheUsers))
486 {
487 static::clearCache();
488
489 return;
490 }
491
492 foreach ($invalidateCacheUsers as $user)
493 {
494 static::clearCache((int)$user);
495 }
496 }
497
498 public function deleteTo(Message $message): void
499 {
500 $userId = $this->getContext()->getUserId();
501 if ($userId <= 0)
502 {
503 return;
504 }
505
506 MessageUnreadTable::deleteByFilter([
507 '<=MESSAGE_ID' => $message->getMessageId(),
508 '=CHAT_ID' => $message->getChatId(),
509 '=USER_ID' => $userId
510 ]);
511 (new CounterOverflowService($message->getChatId()))->delete($userId);
512 static::clearCache($userId);
513 }
514
515 public static function onAfterUserUpdate(array $fields): void
516 {
517 if (!isset($fields['ACTIVE']))
518 {
519 return;
520 }
521
522 if ($fields['ACTIVE'] === 'N')
523 {
524 self::onFireUser((int)$fields['ID']);
525 }
526 else
527 {
528 self::onHireUser((int)$fields['ID']);
529 }
530 }
531
532 public static function deleteCountersOfFiredUserAgent(int $userId): string
533 {
535 if ($user->isExist() && $user->isActive())
536 {
537 return '';
538 }
539
540 $counterService = new self($userId);
541 $counterService->deleteAll(true);
542
543 return '';
544 }
545
546 public static function deleteExpiredCountersAgent(): string
547 {
548 $dateExpired = (new DateTime())->add(self::EXPIRY_INTERVAL);
549 MessageUnreadTable::deleteByFilter(['<=DATE_CREATE' => $dateExpired]);
550 static::clearCache();
551
552 return '\Bitrix\Im\V2\Message\CounterService::deleteExpiredCountersAgent();';
553 }
554
555 protected static function onFireUser(int $userId): void
556 {
557 \CAgent::AddAgent(
558 "\Bitrix\Im\V2\Message\CounterService::deleteCountersOfFiredUserAgent({$userId});",
559 'im',
560 'N',
561 self::DELAY_DELETION_COUNTERS_OF_FIRED_USER,
562 '',
563 'Y',
564 ConvertTimeStamp(time()+CTimeZone::GetOffset()+self::DELAY_DELETION_COUNTERS_OF_FIRED_USER, "FULL"),
565 existError: false
566 );
567 }
568
569 protected static function onHireUser(int $userId): void
570 {
571 \CAgent::RemoveAgent(
572 "\Bitrix\Im\V2\Message\CounterService::deleteCountersOfFiredUserAgent({$userId});",
573 'im'
574 );
575 }
576
577 public static function clearCache(?int $userId = null): void
578 {
579 $cache = \Bitrix\Main\Data\Cache::createInstance();
580 if (isset($userId))
581 {
582 unset(self::$staticCounterCache[$userId], self::$staticChatsCounterCache[$userId], self::$staticSpecificChatsCounterCache[$userId]);
583 $cache->clean(static::CACHE_NAME.'_'.$userId, self::CACHE_PATH);
584 $cache->clean(static::CACHE_NAME.'_'.$userId, CounterServiceLegacy::CACHE_PATH);
585 $cache->clean(self::CACHE_CHATS_COUNTERS_NAME.'_'.$userId, self::CACHE_PATH);
586 }
587 else
588 {
589 self::$staticCounterCache = [];
590 self::$staticChatsCounterCache = [];
591 self::$staticSpecificChatsCounterCache = [];
592 $cache->cleanDir(self::CACHE_PATH);
593 $cache->cleanDir(CounterServiceLegacy::CACHE_PATH);
594 }
595 }
596
597 protected function getCacheForPreparedCounters(): Cache
598 {
599 $userId = $this->getContext()->getUserId();
600 $cache = \Bitrix\Main\Data\Cache::createInstance();
601 $cache->initCache(static::CACHE_TTL, static::CACHE_NAME . '_' . $userId, static::CACHE_PATH);
602
603 return $cache;
604 }
605
606 protected function getCacheForChatsCounters(): Cache
607 {
608 $userId = $this->getContext()->getUserId();
609 $cache = \Bitrix\Main\Data\Cache::createInstance();
610 $cache->initCache(self::CACHE_TTL, self::CACHE_CHATS_COUNTERS_NAME . '_' . $userId, self::CACHE_PATH);
611
612 return $cache;
613 }
614
615 protected function savePreparedCountersInCache(Cache $cache): void
616 {
617 $cache->startDataCache();
618 $cache->endDataCache($this->counters);
619 self::$staticCounterCache[$this->getContext()->getUserId()] = $this->counters;
620 }
621
622 protected function saveChatsCountersInCache(Cache $cache): void
623 {
624 $cache->startDataCache();
625 $cache->endDataCache($this->countersByChatIds);
626 self::$staticChatsCounterCache[$this->getContext()->getUserId()] = $this->countersByChatIds;
627 }
628
629 protected function saveSpecificChatsCountersInCache(array $chatIds): void
630 {
631 $userId = $this->getContext()->getUserId();
632
633 foreach ($chatIds as $chatId)
634 {
635 self::$staticSpecificChatsCounterCache[$userId][$chatId] = $this->countersByChatIds[$chatId] ?? 0;
636 }
637 }
638
639 protected function countUnreadChats(): void
640 {
641 $unreadChats = $this->getUnreadChats(false);
642
643 foreach ($unreadChats as $unreadChat)
644 {
645 $chatId = (int)$unreadChat['CHAT_ID'];
646 $isMuted = $unreadChat['IS_MUTED'] === 'Y';
647
648 match ($unreadChat['CHAT_TYPE'])
649 {
650 Chat::IM_TYPE_COLLAB => $this->setUnreadCollab($chatId, $isMuted),
651 Chat::IM_TYPE_COPILOT => $this->setUnreadCopilot($chatId, $isMuted),
652 default => $this->setUnreadChat($chatId, $isMuted),
653 };
654 }
655 }
656
657 protected function countUnreadMessages(?array $chatIds = null): void
658 {
659 $counters = $this->getCountersForEachChat($chatIds);
660 $chatIdToParentIdMap = $this->getMapChatIdToParentId($counters);
661
662 foreach ($counters as $counter)
663 {
664 $chatId = (int)$counter['CHAT_ID'];
665 $count = (int)$counter['COUNT'];
666 if ($counter['IS_MUTED'] === 'Y')
667 {
668 $this->setFromMutedChat($chatId, $count);
669 }
670 elseif ($counter['CHAT_TYPE'] === Chat::IM_TYPE_COLLAB)
671 {
672 $this->setFromCollab($chatId, $count);
673 }
674 else if ($counter['CHAT_TYPE'] === \IM_MESSAGE_SYSTEM)
675 {
676 $this->setFromNotify($count);
677 }
678 else if ($counter['CHAT_TYPE'] === \IM_MESSAGE_OPEN_LINE)
679 {
680 $this->setFromLine($chatId, $count);
681 }
682 else if ($counter['CHAT_TYPE'] === Chat::IM_TYPE_COPILOT)
683 {
684 $this->setFromCopilot($chatId, $count);
685 }
686 else if ($counter['CHAT_TYPE'] === Chat::IM_TYPE_COMMENT)
687 {
688 $this->setFromComment($chatId, $chatIdToParentIdMap[$chatId] ?? null, $count);
689 }
690 else
691 {
692 $this->setFromChat($chatId, $count);
693 }
694 $this->countersByChatIds[$chatId] = $count;
695 }
696 }
697
698 protected function setUnreadChat(int $id, bool $isMuted): void
699 {
700 if (!$isMuted && !isset($this->counters['CHAT'][$id]))
701 {
702 $this->counters['TYPE']['ALL']++;
703 $this->counters['TYPE']['CHAT']++;
704 $this->counters['TYPE']['MESSENGER']++;
705 }
706
707 $this->counters['CHAT_UNREAD'][] = $id;
708 }
709
710 protected function setUnreadCollab(int $id, bool $isMuted): void
711 {
712 if (!$isMuted && !isset($this->counters['COLLAB'][$id]))
713 {
714 $this->counters['TYPE']['ALL']++;
715 $this->counters['TYPE']['CHAT']++;
716 $this->counters['TYPE']['COLLAB']++;
717 $this->counters['TYPE']['MESSENGER']++;
718 }
719
720 $this->counters['CHAT_UNREAD'][] = $id;
721 $this->counters['COLLAB_UNREAD'][] = $id;
722 }
723
724 protected function setUnreadCopilot(int $id, bool $isMuted): void
725 {
726 if (!$isMuted && !isset($this->counters['COPILOT'][$id]))
727 {
728 $this->counters['TYPE']['ALL']++;
729 $this->counters['TYPE']['CHAT']++;
730 $this->counters['TYPE']['COPILOT']++;
731 $this->counters['TYPE']['MESSENGER']++;
732 $this->counters['CHAT_UNREAD'][] = $id;
733 }
734
735 $this->counters['COPILOT_UNREAD'][] = $id;
736 }
737
738 protected function setFromMutedChat(int $id, int $count): void
739 {
740 $this->counters['CHAT_MUTED'][$id] = $count;
741 }
742
743 protected function setFromNotify(int $count): void
744 {
745 $this->counters['TYPE']['ALL'] += $count;
746 $this->counters['TYPE']['NOTIFY'] += $count;
747 }
748
749 protected function setFromLine(int $id, int $count): void
750 {
751 $this->counters['TYPE']['ALL'] += $count;
752 $this->counters['TYPE']['LINES'] += $count;
753 $this->counters['TYPE']['MESSENGER'] += $count;
754 $this->counters['LINES'][$id] = $count;
755 }
756
757 protected function setFromCopilot(int $id, int $count): void
758 {
759 $this->counters['TYPE']['ALL'] += $count;
760 $this->counters['TYPE']['CHAT'] += $count;
761 $this->counters['TYPE']['MESSENGER'] += $count;
762 $this->counters['TYPE']['COPILOT'] += $count;
763 $this->counters['COPILOT'][$id] = $count;
764 $this->counters['CHAT'][$id] = $count;
765 }
766
767 protected function setFromCollab(int $id, int $count): void
768 {
769 $this->counters['TYPE']['ALL'] += $count;
770 $this->counters['TYPE']['CHAT'] += $count;
771 $this->counters['TYPE']['MESSENGER'] += $count;
772 $this->counters['TYPE']['COLLAB'] += $count;
773 $this->counters['CHAT'][$id] = $count;
774 $this->counters['COLLAB'][$id] = $count;
775 }
776
777 protected function setFromComment(int $id, ?int $parentId, int $count): void
778 {
779 if ($parentId === null || $parentId === 0)
780 {
781 return;
782 }
783
784 $this->counters['TYPE']['ALL'] += $count;
785 $this->counters['TYPE']['MESSENGER'] += $count;
786 $this->counters['CHANNEL_COMMENT'][$parentId][$id] = $count;
787 }
788
789 protected function setFromChat(int $id, int $count): void
790 {
791 $this->counters['TYPE']['ALL'] += $count;
792 $this->counters['TYPE']['CHAT'] += $count;
793 $this->counters['TYPE']['MESSENGER'] += $count;
794 $this->counters['CHAT'][$id] = $count;
795 }
796
798 {
799 $commentChatIds = $this->getCommentChatIdsOnly($counters);
800
801 if (empty($commentChatIds))
802 {
803 return [];
804 }
805
806 $raw = ChatTable::query()
807 ->setSelect(['ID', 'PARENT_ID'])
808 ->whereIn('ID', $commentChatIds)
809 ->fetchAll()
810 ;
811 $result = [];
812
813 foreach ($raw as $row)
814 {
815 $chatId = (int)$row['ID'];
816 $parentId = (int)($row['PARENT_ID'] ?? 0);
817 $result[$chatId] = $parentId;
818 }
819
820 return $result;
821 }
822
824 {
825 $result = [];
826
827 foreach ($counters as $counter)
828 {
829 if ($counter['CHAT_TYPE'] === Chat::IM_TYPE_COMMENT)
830 {
831 $result[] = (int)$counter['CHAT_ID'];
832 }
833 }
834
835 return $result;
836 }
837
838 protected function getUnreadChats(?bool $isMuted = null): array
839 {
840 $query = RecentTable::query()
841 ->setSelect([
842 'CHAT_ID' => 'ITEM_CID',
843 'CHAT_TYPE' => 'ITEM_TYPE',
844 'IS_MUTED' => 'RELATION.NOTIFY_BLOCK',
845 ])
846 ->where('USER_ID', $this->getContext()->getUserId())
847 ->where('UNREAD', true)
848 ;
849 if (isset($isMuted))
850 {
851 $query->where('IS_MUTED', $isMuted);
852 }
853
854 return $query->fetchAll();
855 }
856
857 protected function getCountersForEachChat(?array $chatIds = null, bool $forCurrentUser = true): array
858 {
859 $additionalCounters = $this->getAdditionalCounters($chatIds, $forCurrentUser);
860 $query = MessageUnreadTable::query()
861 ->setSelect(['CHAT_ID', 'IS_MUTED', 'CHAT_TYPE', 'COUNT'])
862 ->setGroup(['CHAT_ID', 'CHAT_TYPE', 'IS_MUTED'])
863 ->registerRuntimeField('COUNT', new ExpressionField('COUNT', 'COUNT(*)'))
864 ;
865
866 if (isset($chatIds) && !empty($chatIds))
867 {
868 $query->whereIn('CHAT_ID', $chatIds);
869 }
870 if ($forCurrentUser)
871 {
872 $query->where('USER_ID', $this->getContext()->getUserId());
873 }
874
875 return array_merge($additionalCounters, $query->fetchAll());
876 }
877
878 protected function getAdditionalCounters(?array $chatIds = null, bool $forCurrentUser = true): array
879 {
880 $result = [];
881 $nonAnsweredLines = [];
882
883 if ($forCurrentUser && empty($chatIds) && Loader::includeModule('imopenlines'))
884 {
885 $nonAnsweredLines = \Bitrix\ImOpenLines\Recent::getNonAnsweredLines($this->getContext()->getUserId());
886 }
887
888 foreach ($nonAnsweredLines as $lineId)
889 {
890 $result[] = [
891 'CHAT_ID' => $lineId,
892 'IS_MUTED' => 'N',
893 'CHAT_TYPE' => Chat::IM_TYPE_OPEN_LINE,
894 'COUNT' => 1,
895 ];
896 }
897
898 return $result;
899 }
900
901 protected function getTotalCountUnreadMessages(): int
902 {
903 return (int)MessageUnreadTable::query()
904 ->setSelect(['COUNT'])
905 ->where('USER_ID', $this->getContext()->getUserId())
906 ->where('IS_MUTED', false)
907 ->whereNot('CHAT_TYPE', Chat::IM_TYPE_COPILOT)
908 ->registerRuntimeField('COUNT', new ExpressionField('COUNT', 'COUNT(*)'))
909 ->fetch()['COUNT']
910 ;
911 }
912
913 protected function getCountUnreadMessagesByChatIdForEachUsers(int $chatId, ?array $userIds = null): array
914 {
915 $query = MessageUnreadTable::query()
916 ->setSelect(['USER_ID', 'COUNT'])
917 ->where('CHAT_ID', $chatId)
918 ->setGroup(['USER_ID'])
919 ->registerRuntimeField('COUNT', new ExpressionField('COUNT', 'COUNT(*)'))
920 ;
921 if (!empty($userIds))
922 {
923 $query->whereIn('USER_ID', $userIds);
924 }
925
926 return $query->fetchAll();
927 }
928
929 protected function getCountUnreadMessagesByChatId(int $chatId): int
930 {
931 return MessageUnreadTable::query()
932 ->setSelect(['COUNT'])
933 ->where('CHAT_ID', $chatId)
934 ->where('USER_ID', $this->getContext()->getUserId())
935 ->registerRuntimeField('COUNT', new ExpressionField('COUNT', 'COUNT(*)'))
936 ->fetch()['COUNT'] ?? 0
937 ;
938 }
939
940 protected function haveInSpecificChatsCache(array $chatIds): bool
941 {
942 $userId = $this->getContext()->getUserId();
943
944 foreach ($chatIds as $chatId)
945 {
946 if ($chatId > 0 && !isset(self::$staticSpecificChatsCounterCache[$userId][$chatId]))
947 {
948 return false;
949 }
950 }
951
952 return true;
953 }
954
955 private function prepareInsertFields(Message $message, Relation $relation): array
956 {
957 return [
958 'MESSAGE_ID' => $message->getMessageId(),
959 'CHAT_ID' => $relation->getChatId(),
960 'USER_ID' => $relation->getUserId(),
961 'CHAT_TYPE' => $relation->getMessageType(),
962 'IS_MUTED' => $relation->getNotifyBlock() ? 'Y' : 'N',
963 'PARENT_ID' => $message->getChat()->getParentChatId() ?? 0,
964 ];
965 }
966}
$count
Определения admin_tab.php:4
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 getInstance($userId=null)
Определения user.php:45
static deleteAllViaAgent(int $userId, bool $withNotify)
Определения CounterServiceAgent.php:72
__construct(?int $userId=null)
Определения CounterService.php:69
deleteByChatId(int $chatId)
Определения CounterService.php:295
setFromCopilot(int $id, int $count)
Определения CounterService.php:757
static onAfterUserUpdate(array $fields)
Определения CounterService.php:515
getIdFirstUnreadMessage(int $chatId)
Определения CounterService.php:248
getIdFirstUnreadMessageForEachChats(array $chatIds)
Определения CounterService.php:261
updateIsMuted(int $chatId, string $isMuted)
Определения CounterService.php:286
static deleteExpiredCountersAgent()
Определения CounterService.php:546
setUnreadCollab(int $id, bool $isMuted)
Определения CounterService.php:710
deleteByMessageForAll(Message $message, ?array $invalidateCacheUsers=null)
Определения CounterService.php:444
setUnreadChat(int $id, bool $isMuted)
Определения CounterService.php:698
getUnreadChats(?bool $isMuted=null)
Определения CounterService.php:838
getByChat(int $chatId)
Определения CounterService.php:119
savePreparedCountersInCache(Cache $cache)
Определения CounterService.php:615
setFromNotify(int $count)
Определения CounterService.php:743
getCountUnreadMessagesByChatIdForEachUsers(int $chatId, ?array $userIds=null)
Определения CounterService.php:913
saveSpecificChatsCountersInCache(array $chatIds)
Определения CounterService.php:629
saveChatsCountersInCache(Cache $cache)
Определения CounterService.php:622
static getChildrenWithCounters(Chat $parentChat, ?int $userId=null)
Определения CounterService.php:350
getCommentChatIdsOnly(array $counters)
Определения CounterService.php:823
setFromLine(int $id, int $count)
Определения CounterService.php:749
getAdditionalCounters(?array $chatIds=null, bool $forCurrentUser=true)
Определения CounterService.php:878
getByChatWithOverflow(int $chatId)
Определения CounterService.php:124
static deleteByChatIdsForAll(array $chatIds)
Определения CounterService.php:313
countUnreadMessages(?array $chatIds=null)
Определения CounterService.php:657
static onHireUser(int $userId)
Определения CounterService.php:569
addCollection(MessageCollection $messages, Relation $relation)
Определения CounterService.php:401
getForNotifyChats(array $chatIds)
Определения CounterService.php:223
setFromMutedChat(int $id, int $count)
Определения CounterService.php:738
getForEachChat(?array $chatIds=null)
Определения CounterService.php:170
static array $staticChatsCounterCache
Определения CounterService.php:63
haveInSpecificChatsCache(array $chatIds)
Определения CounterService.php:940
static array $staticSpecificChatsCounterCache
Определения CounterService.php:64
static deleteCountersOfFiredUserAgent(int $userId)
Определения CounterService.php:532
setFromComment(int $id, ?int $parentId, int $count)
Определения CounterService.php:777
getCountUnreadMessagesByChatId(int $chatId)
Определения CounterService.php:929
static onFireUser(int $userId)
Определения CounterService.php:555
const DELAY_DELETION_COUNTERS_OF_FIRED_USER
Определения CounterService.php:33
getByChatForEachUsers(int $chatId, array $userIds)
Определения CounterService.php:89
setUnreadCopilot(int $id, bool $isMuted)
Определения CounterService.php:724
getCountersForEachChat(?array $chatIds=null, bool $forCurrentUser=true)
Определения CounterService.php:857
static clearCache(?int $userId=null)
Определения CounterService.php:577
getMapChatIdToParentId(array $counters)
Определения CounterService.php:797
setFromChat(int $id, int $count)
Определения CounterService.php:789
deleteByChatIds(array $chatIds)
Определения CounterService.php:319
deleteAll(bool $withNotify=false)
Определения CounterService.php:342
static array $staticCounterCache
Определения CounterService.php:62
addForEachUser(Message $message, RelationCollection $relations)
Определения CounterService.php:378
deleteByMessagesForAll(MessageCollection $messages, ?array $invalidateCacheUsers=null)
Определения CounterService.php:467
static deleteByChatIdForAll(int $chatId)
Определения CounterService.php:307
deleteTo(Message $message)
Определения CounterService.php:498
setFromCollab(int $id, int $count)
Определения CounterService.php:767
addStartingFrom(int $messageId, Relation $relation)
Определения CounterService.php:419
endDataCache($vars=false)
Определения cache.php:404
startDataCache($TTL=false, $uniqueString=false, $initDir=false, $vars=array(), $baseDir='cache')
Определения cache.php:345
</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
Определения culture.php:9
$user
Определения mysql_to_pgsql.php:33
$message
Определения payment.php:8
$counter
Определения options.php:5
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$messages
Определения template.php:8
$counters
Определения options.php:100
$fields
Определения yandex_run.php:501