/
vchechun
/
task_checklist_export
Обзор
Документация
Войти
/
vchechun
/
task_checklist_export
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/ChecklistSummary.php
221 строка
4 KB
Vsevolod Chechun
init
07 май 2026, 07:31
07 май 2026, 07:31
fde5953
Код
Авторство
О чём код?
<?php namespace BitrixExt\TaskChecklistExport; use Bitrix\Main\Application; use Bitrix\Main\Entity\Query; use Bitrix\Main\Entity\Query\Join; use Bitrix\Main\Entity\ReferenceField; use Bitrix\Main\Loader; use Bitrix\Tasks\Internals\Task\CheckListTable; use Bitrix\Tasks\Internals\Task\CheckListTreeTable; final class ChecklistSummary { public static function getFormattedByTaskIds(array $taskIds): array { $taskIds = array_values(array_unique(array_filter(array_map('intval', $taskIds)))); if (empty($taskIds) || !Loader::includeModule('tasks')) { return []; } $itemsByTask = self::loadItemsByTaskIds($taskIds); $result = []; foreach ($taskIds as $taskId) { $result[$taskId] = self::format($itemsByTask[$taskId] ?? []); } return $result; } private static function loadItemsByTaskIds(array $taskIds): array { if ( class_exists(CheckListTable::class) && class_exists(CheckListTreeTable::class) && class_exists(Query::class) ) { return self::loadItemsViaOrm($taskIds); } return self::loadItemsViaSql($taskIds); } private static function loadItemsViaOrm(array $taskIds): array { $query = new Query(CheckListTable::getEntity()); $query->setSelect([ 'ID', 'TASK_ID', 'PARENT_ID' => 'IT.PARENT_ID', 'IS_COMPLETE', 'SORT_INDEX', ]); $query->setFilter(['@TASK_ID' => $taskIds]); $query->setOrder([ 'TASK_ID' => 'ASC', 'IT.PARENT_ID' => 'ASC', 'SORT_INDEX' => 'ASC', 'ID' => 'ASC', ]); $query->registerRuntimeField('', new ReferenceField( 'IT', CheckListTreeTable::getEntity(), Join::on('this.ID', 'ref.CHILD_ID')->where('ref.LEVEL', 1), ['join_type' => 'LEFT'] )); $itemsByTask = []; $rows = $query->exec(); while ($item = $rows->fetch()) { $taskId = (int)$item['TASK_ID']; $item['PARENT_ID'] = (int)($item['PARENT_ID'] ?? 0); $itemsByTask[$taskId][] = $item; } return $itemsByTask; } private static function loadItemsViaSql(array $taskIds): array { $connection = Application::getConnection(); $ids = implode(',', array_map('intval', $taskIds)); $sql = " SELECT I.ID, I.TASK_ID, COALESCE(T.PARENT_ID, 0) AS PARENT_ID, I.IS_COMPLETE, I.SORT_INDEX FROM b_tasks_checklist_items I LEFT JOIN b_tasks_checklist_items_tree T ON T.CHILD_ID = I.ID AND T.LEVEL = 1 WHERE I.TASK_ID IN ({$ids}) ORDER BY I.TASK_ID ASC, T.PARENT_ID ASC, I.SORT_INDEX ASC, I.ID ASC "; $itemsByTask = []; $rows = $connection->query($sql); while ($item = $rows->fetch()) { $taskId = (int)$item['TASK_ID']; $item['PARENT_ID'] = (int)($item['PARENT_ID'] ?? 0); $itemsByTask[$taskId][] = $item; } return $itemsByTask; } private static function format(array $items): string { $groups = self::buildGroups($items); if (empty($groups)) { return '0'; } $totalComplete = 0; $total = 0; $parts = []; foreach ($groups as $group) { $complete = 0; $count = 0; foreach ($group as $item) { $count++; if (self::isComplete($item)) { $complete++; } } $total += $count; $totalComplete += $complete; $parts[] = $complete . '\\' . $count; } return $totalComplete . '\\' . $total . ' (' . implode('; ', $parts) . ')'; } private static function buildGroups(array $items): array { $byId = []; $childrenByParent = []; $roots = []; foreach ($items as $item) { $id = (int)($item['ID'] ?? 0); if ($id <= 0) { continue; } $parentId = (int)($item['PARENT_ID'] ?? 0); $byId[$id] = $item; $childrenByParent[$parentId][] = $id; if ($parentId === 0) { $roots[] = $id; } } if (empty($byId)) { return []; } if (empty($roots)) { return [array_values($byId)]; } $groups = []; foreach ($roots as $rootId) { $descendants = self::collectDescendants($rootId, $childrenByParent, $byId); $groups[] = !empty($descendants) ? $descendants : [$byId[$rootId]]; } return $groups; } private static function collectDescendants(int $rootId, array $childrenByParent, array $byId): array { $result = []; $queue = $childrenByParent[$rootId] ?? []; while (!empty($queue)) { $id = array_shift($queue); if (!isset($byId[$id])) { continue; } $result[] = $byId[$id]; foreach ($childrenByParent[$id] ?? [] as $childId) { $queue[] = $childId; } } return $result; } private static function isComplete(array $item): bool { $value = $item['IS_COMPLETE'] ?? false; return $value === true || $value === 'Y' || $value === '1' || $value === 1; } }