1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
ChatContentCollector.php
См. документацию.
1<?php
2
3declare(strict_types=1);
4
5namespace Bitrix\Im\V2\Chat\Cleanup;
6
7use Bitrix\Disk\File;
8use Bitrix\Disk\Folder;
9use Bitrix\Disk\SystemUser;
10use Bitrix\Im\Model\AnchorTable;
11use Bitrix\Im\Model\BlockUserTable;
12use Bitrix\Im\Model\ChatIndexTable;
13use Bitrix\Im\Model\ChatParamTable;
14use Bitrix\Im\Model\ChatTable;
15use Bitrix\Im\Model\LastMessageTable;
16use Bitrix\Im\Model\LinkCalendarIndexTable;
17use Bitrix\Im\Model\LinkCalendarTable;
18use Bitrix\Im\Model\LinkFavoriteTable;
19use Bitrix\Im\Model\LinkFileTable;
20use Bitrix\Im\Model\LinkPinTable;
21use Bitrix\Im\Model\LinkReminderTable;
22use Bitrix\Im\Model\LinkTaskTable;
23use Bitrix\Im\Model\LinkUrlIndexTable;
24use Bitrix\Im\Model\LinkUrlTable;
25use Bitrix\Im\Model\MessageDisappearingTable;
26use Bitrix\Im\Model\MessageIndexTable;
27use Bitrix\Im\Model\MessageParamTable;
28use Bitrix\Im\Model\MessageTable;
29use Bitrix\Im\Model\MessageUnreadTable;
30use Bitrix\Im\Model\MessageUuidTable;
31use Bitrix\Im\Model\MessageViewedTable;
32use Bitrix\Im\Model\NoRelationPermissionDiskTable;
33use Bitrix\Im\Model\ReactionTable;
34use Bitrix\Im\Model\RecentTable;
35use Bitrix\Im\Model\RelationTable;
36use Bitrix\Im\V2\Anchor\DI\AnchorContainer;
37use Bitrix\Im\V2\Chat;
38use Bitrix\Im\V2\Integration\HumanResources\Structure;
39use Bitrix\Im\V2\Message\CounterService;
40use Bitrix\Im\V2\Sync\Event;
41use Bitrix\Im\V2\Sync\Logger;
42use Bitrix\ImConnector\Model\ChatLastMessageTable;
43use Bitrix\Main\Application;
44use Bitrix\Main\ArgumentException;
45use Bitrix\Main\Entity\Query;
46use Bitrix\Main\ObjectPropertyException;
47use Bitrix\Main\ORM\Data\DataManager;
48use Bitrix\Main\SystemException;
49use CPullStack;
50
52{
53 private int $chatId;
54 private array $chatMembers;
55
56 public function __construct(Chat|int $chat)
57 {
58 if ($chat instanceof Chat)
59 {
60 $this->chatId = $chat->getChatId();
61 }
62 else
63 {
64 $this->chatId = $chat;
65 }
66 }
67
79 private function collectByColumn(
80 string $tableClass,
81 mixed $columnValue,
82 int|null $limit = null,
83 string $columnName = 'CHAT_ID',
84 string|array $selectColumnName = 'ID',
85 ): array
86 {
87 if (!is_a($tableClass, DataManager::class, true))
88 {
89 return [];
90 }
91
92 $isMultiColumn = is_array($selectColumnName);
93 $indexColumn = $isMultiColumn ? reset($selectColumnName) : $selectColumnName;
94
95 $params = [
96 'select' => $isMultiColumn ? $selectColumnName : [$selectColumnName],
97 'filter' => [(is_array($columnValue) ? '@' : '=') . $columnName => $columnValue],
98 ];
99
100 if (null !== $limit)
101 {
102 $params['limit'] = $limit;
103 }
104
105 $result = $tableClass::getList($params);
106 $data = [];
107
108 foreach ($result->fetchAll() as $row)
109 {
110 $data[$row[$indexColumn]] = $isMultiColumn ? $row : $row[$indexColumn];
111 }
112
113 return $data;
114 }
115
124 private function deleteByColumn(
125 string $tableClass,
126 array $idColumnValues,
127 string $idColumnName = 'ID',
128 ): void
129 {
130 if (0 === count($idColumnValues))
131 {
132 return;
133 }
134
135 if (!is_a($tableClass, DataManager::class, true))
136 {
137 return;
138 }
139
140 $whereSql = Query::buildFilterSql($tableClass::getEntity(), ['@' . $idColumnName => $idColumnValues]);
141 $tableName = $tableClass::getTableName();
142 $connection = Application::getConnection();
143 $connection->queryExecute($sql = "DELETE FROM {$tableName} WHERE {$whereSql}");
144 }
145
146 private function getCleanupSequence(): array
147 {
148 return [
149 'cleanupChatAddons',
150 'cleanupMessages',
151 'cleanupLastMessages',
152 'cleanupFavoritesLinks',
153 'cleanupUrlsLinks',
154 'cleanupTasksLinks',
155 'cleanupCalendarLinks',
156 'cleanupFilesLinks',
157 'cleanupReactions',
158 'cleanupReminder',
159 'cleanupNoRelationPermDisk',
160 ];
161 }
162
163 private function getCurrentCleanupStep(?string $previousCompletedStep = null): ?string
164 {
165 $prevStepFound = false;
166
167 foreach ($this->getCleanupSequence() as $step)
168 {
169 if ((null === $previousCompletedStep) || $prevStepFound)
170 {
171 return $step;
172 }
173
174 if ($step === $previousCompletedStep)
175 {
176 $prevStepFound = true;
177 }
178 }
179
180 return null;
181 }
182
183 public function processCleanup(int $limit, ?string $previousCompletedStep = null): ?string
184 {
185 $currentStep = $this->getCurrentCleanupStep($previousCompletedStep);
186
187 if (null === $currentStep)
188 {
189 return null;
190 }
191
192 $isCompleted = !$this->{$currentStep}($limit);
193
194 return $isCompleted ? $currentStep : $previousCompletedStep;
195 }
196
202 public function getNextChatIdToCleanup(): ?int
203 {
204 $nextChildChat = $this->collectByColumn(
205 ChatTable::class,
206 $this->chatId,
207 1,
208 'PARENT_ID',
209 );
210
211 if (count($nextChildChat) > 0)
212 {
213 return array_key_first($nextChildChat);
214 }
215
216 return null;
217 }
218
225 public function deleteChat(?int $userId = null): void
226 {
228 ChatCleanupAgent::register($this->chatId, userId: $userId);
229 }
230
231 protected function getChatMembers(): array
232 {
233 $this->chatMembers ??= $this->collectByColumn(
234 RelationTable::class,
235 $this->chatId,
236 selectColumnName: 'USER_ID',
237 );
238
239 return $this->chatMembers;
240 }
241
247 protected function writeSyncLog(): void
248 {
249 $userIds = $this->getChatMembers();
250 $chat = Chat::getInstance($this->chatId);
251 $logger = Logger::getInstance();
252
253 foreach ($userIds as $userId)
254 {
255 $logger->add(
256 new Event(Event::COMPLETE_DELETE_EVENT, Event::CHAT_ENTITY, $this->chatId),
257 (int)$userId,
258 $chat,
259 );
260 }
261 }
262
270 public function cleanupChatBasics(?int $userId = null): void
271 {
272 $chat = Chat::getInstance($this->chatId);
273 $arMessage = [
274 'module_id' => 'im',
275 'command' => 'chatDelete',
276 'params' => [
277 'chatId' => $this->chatId,
278 'parentChatId' => $chat->getParentChatId() ?? 0,
279 'dialogId' => $chat->getDialogId(),
280 'type' => $chat->getExtendedType(),
281 'userId' => $userId,
282 ],
283 ];
284
285 $this->writeSyncLog();
286 $this->deleteByColumn(RelationTable::class, [$this->chatId], 'CHAT_ID');
287 $this->deleteByColumn(ChatTable::class, [$this->chatId]);
288 Chat::cleanCache($this->chatId);
289 $this->deleteByColumn(RecentTable::class, [$this->chatId], 'ITEM_CID');
290 $this->deleteByColumn(MessageUnreadTable::class, [$this->chatId], 'CHAT_ID');
291 $this->deleteByColumn(MessageUnreadTable::class, [$this->chatId], 'PARENT_ID');
292 $this->cleanupCounterCache();
293 $this->deleteByColumn(ChatIndexTable::class, [$this->chatId], 'CHAT_ID');
294 $this->deleteByColumn(AnchorTable::class, [$this->chatId], 'CHAT_ID');
295 $this->cleanupAnchorCache();
296
297 (new Structure($chat))->unlinkAll();
298
299 CPullStack::AddShared($arMessage);
300 }
301
302 protected function cleanupCounterCache(): void
303 {
304 foreach ($this->getChatMembers() as $userId)
305 {
307 }
308 }
309
310 protected function cleanupAnchorCache(): void
311 {
312 $provider = AnchorContainer::getInstance()->getAnchorProvider();
313 foreach ($this->getChatMembers() as $userId)
314 {
315 $provider->cleanCache((int)$userId);
316 }
317 }
318
325 protected function cleanupChatAddons($limit): bool
326 {
327 $this->deleteByColumn(ChatParamTable::class, [$this->chatId], 'CHAT_ID');
328 $this->deleteByColumn(ChatLastMessageTable::class, [$this->chatId], 'EXTERNAL_CHAT_ID');
329 $this->deleteByColumn(BlockUserTable::class, [$this->chatId], 'CHAT_ID');
330
331 return false;
332 }
333
339 protected function cleanupLastMessages(int $limit): bool
340 {
341 $ids = $this->collectByColumn(LastMessageTable::class, $this->chatId, $limit);
342
343 if (count($ids) === 0)
344 {
345 return false;
346 }
347
348 $this->deleteByColumn(LastMessageTable::class, $ids);
349
350 return true;
351 }
352
358 protected function cleanupMessages($limit): bool
359 {
360 $ids = $this->collectByColumn(MessageTable::class, $this->chatId, $limit);
361
362 if (count($ids) === 0)
363 {
364 $folderId = Chat::getInstance($this->chatId)->getDiskFolderId();
365
366 if ($folderId)
367 {
368 $folderModel = Folder::getById($folderId);
369 $folderModel->deleteTree(SystemUser::SYSTEM_USER_ID);
370 }
371
372 return false;
373 }
374
375 $params = $this->collectByColumn(
376 MessageParamTable::class,
377 $ids,
378 columnName: 'MESSAGE_ID',
379 selectColumnName: [
380 'ID',
381 'PARAM_NAME',
382 'PARAM_VALUE',
383 ],
384 );
385 $paramIds = array_keys($params);
386 $fileIds = [];
387
388 foreach ($params as $row)
389 {
390 if ($row['PARAM_NAME'] === 'FILE_ID')
391 {
392 $fileIds = intval($row['PARAM_VALUE']);
393 }
394 }
395
396 $this->deleteByColumn(MessageTable::class, $ids);
397 $this->deleteByColumn(MessageUuidTable::class, $ids, 'MESSAGE_ID');
398 $this->deleteByColumn(MessageIndexTable::class, $ids, 'MESSAGE_ID');
399 $this->deleteByColumn(MessageViewedTable::class, $ids, 'MESSAGE_ID');
400 $this->deleteByColumn(MessageDisappearingTable::class, $ids, 'MESSAGE_ID');
401 $this->deleteByColumn(MessageParamTable::class, $paramIds);
402 $this->deleteByColumn(LinkPinTable::class, $ids, 'MESSAGE_ID');
403
404 foreach ($fileIds as $fileId)
405 {
406 File::getById($fileId)->delete(SystemUser::SYSTEM_USER_ID);
407 }
408
409 return true;
410 }
411
417 protected function cleanupFavoritesLinks(int $limit): bool
418 {
419 $ids = $this->collectByColumn(LinkFavoriteTable::class, $this->chatId, $limit);
420
421 if (count($ids) === 0)
422 {
423 return false;
424 }
425
426 $this->deleteByColumn(LinkFavoriteTable::class, $ids);
427
428 return true;
429 }
430
436 protected function cleanupUrlsLinks(int $limit): bool
437 {
438 $ids = $this->collectByColumn(LinkUrlTable::class, $this->chatId, $limit);
439
440 if (count($ids) === 0)
441 {
442 return false;
443 }
444
445 $this->deleteByColumn(LinkUrlIndexTable::class, $ids, 'URL_ID');
446 $this->deleteByColumn(LinkUrlTable::class, $ids);
447
448 return true;
449 }
450
456 protected function cleanupTasksLinks(int $limit): bool
457 {
458 $ids = $this->collectByColumn(LinkTaskTable::class, $this->chatId, $limit);
459
460 if (count($ids) === 0)
461 {
462 return false;
463 }
464
465 $this->deleteByColumn(LinkTaskTable::class, $ids);
466
467 return true;
468 }
469
475 protected function cleanupCalendarLinks(int $limit): bool
476 {
477 $ids = $this->collectByColumn(LinkCalendarTable::class, $this->chatId, $limit);
478
479 if (count($ids) === 0)
480 {
481 return false;
482 }
483
484 $this->deleteByColumn(LinkCalendarIndexTable::class, $ids);
485 $this->deleteByColumn(LinkCalendarTable::class, $ids);
486
487 return true;
488 }
489
495 protected function cleanupFilesLinks(int $limit): bool
496 {
497 $ids = $this->collectByColumn(LinkFileTable::class, $this->chatId, $limit);
498
499 if (count($ids) === 0)
500 {
501 return false;
502 }
503
504 $this->deleteByColumn(LinkFileTable::class, $ids);
505
506 return true;
507 }
508
514 protected function cleanupReactions(int $limit): bool
515 {
516 $ids = $this->collectByColumn(ReactionTable::class, $this->chatId, $limit);
517
518 if (count($ids) === 0)
519 {
520 return false;
521 }
522
523 $this->deleteByColumn(ReactionTable::class, $ids);
524
525 return true;
526 }
527
533 protected function cleanupReminder(int $limit): bool
534 {
535 $ids = $this->collectByColumn(LinkReminderTable::class, $this->chatId, $limit);
536
537 if (count($ids) === 0)
538 {
539 return false;
540 }
541
542 $this->deleteByColumn(LinkReminderTable::class, $ids);
543
544 return true;
545 }
546
552 protected function cleanupNoRelationPermDisk(int $limit): bool
553 {
554 $ids = $this->collectByColumn(
555 NoRelationPermissionDiskTable::class,
556 $this->chatId,
557 $limit,
558 );
559
560 if (count($ids) === 0)
561 {
562 return false;
563 }
564
565 $this->deleteByColumn(NoRelationPermissionDiskTable::class, $ids);
566
567 return true;
568 }
569}
$connection
Определения actionsdefinitions.php:38
if(!Loader::includeModule('messageservice')) $provider
Определения callback_ednaruimhpx.php:21
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static register(int $chatId, ?int $currentChatId=null, ?int $userId=null,)
Определения ChatCleanupAgent.php:62
processCleanup(int $limit, ?string $previousCompletedStep=null)
Определения ChatContentCollector.php:183
static getInstance()
Определения application.php:98
static clearCache($moduleId)
Определения option.php:464
static cleanCache()
Определения datamanager.php:1983
$data['IS_AVAILABLE']
Определения .description.php:13
</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
</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
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799