$assignmentCount, 'submissions' => $submissionCount, 'certificates' => $certificateCount, 'methods' => $methodCount, 'escalation_events' => $escalationEventCount, ]; } public function findById(int $taskId): ?array { return TaskCertDb::fetchOne('SELECT * FROM task_definition WHERE id = ?', 'i', [$taskId]); } public function listForAdmin(string $searchQuery = '', int $categoryIdFilter = 0): array { $searchQuery = trim($searchQuery); $categoryIdFilter = max(0, $categoryIdFilter); $sql = 'SELECT d.*, MAX(tc.name) AS task_category_name, COUNT(a.id) AS assignment_count, SUM(CASE WHEN a.status IN ("open", "in_progress", "approval_pending", "overdue") THEN 1 ELSE 0 END) AS open_count, SUM(CASE WHEN a.status = "completed" THEN 1 ELSE 0 END) AS completed_count FROM task_definition d LEFT JOIN task_category tc ON tc.id = d.task_category_id LEFT JOIN task_assignment a ON a.task_id = d.id'; $conditions = []; $types = ''; $params = []; if ($categoryIdFilter > 0) { $conditions[] = 'd.task_category_id = ?'; $types .= 'i'; $params[] = $categoryIdFilter; } if ($searchQuery !== '') { $searchLike = '%' . $searchQuery . '%'; $conditions[] = '( d.title LIKE ? OR d.description LIKE ? OR COALESCE(tc.name, "") LIKE ? OR CAST(d.id AS CHAR) LIKE ? )'; $types .= 'ssss'; $params[] = $searchLike; $params[] = $searchLike; $params[] = $searchLike; $params[] = $searchLike; } if ($conditions !== []) { $sql .= ' WHERE ' . implode(' AND ', $conditions); } $sql .= ' GROUP BY d.id ORDER BY d.active DESC, d.created_at DESC'; return TaskCertDb::fetchAll($sql, $types, $params); } public function listForResponsible(int $contactId): array { if ($contactId <= 0) { return []; } $sql = 'SELECT d.*, MAX(tc.name) AS task_category_name, COUNT(a.id) AS assignment_count, SUM(CASE WHEN a.status IN ("open", "in_progress", "approval_pending", "overdue") THEN 1 ELSE 0 END) AS open_count, SUM(CASE WHEN a.status = "completed" THEN 1 ELSE 0 END) AS completed_count FROM task_definition d INNER JOIN task_responsible tr ON tr.task_id = d.id AND tr.main_contact_id = ? LEFT JOIN task_category tc ON tc.id = d.task_category_id LEFT JOIN task_assignment a ON a.task_id = d.id GROUP BY d.id ORDER BY d.active DESC, d.created_at DESC'; return TaskCertDb::fetchAll($sql, 'i', [$contactId]); } public function listActive(): array { return TaskCertDb::fetchAll( 'SELECT * FROM task_definition WHERE active = 1 ORDER BY id DESC' ); } }