isAjax()) { $this->json(['success' => false, 'message' => 'Unauthorized'], 403); } header('Location: /login'); exit; } $taskId = (int)($_POST['task_id'] ?? 0); $text = trim((string)($_POST['text'] ?? '')); if ($taskId <= 0 || $text === '') { if ($this->isAjax()) { $this->json(['success' => false, 'message' => 'Комментарий не заполнен'], 400); } $_SESSION['error'] = 'Комментарий не заполнен'; header('Location: /tasks'); exit; } $pdo = DB::connection(); // 1. Добавляем комментарий $stmt = $pdo->prepare(" INSERT INTO task_comments ( task_id, user_id, text, created_at, updated_at ) VALUES (?, ?, ?, NOW(), NOW()) "); $stmt->execute([ $taskId, Auth::user()['id'], $text, ]); // 2. Получаем мета $stmt = $pdo->prepare(" SELECT COUNT(*) AS comment_count, MAX(id) AS last_comment_id FROM task_comments WHERE task_id = ? "); $stmt->execute([$taskId]); $commentMeta = $stmt->fetch(); // 3. Получаем задачу $stmt = $pdo->prepare(" SELECT id, name, assignee_id FROM tasks WHERE id = ? LIMIT 1 "); $stmt->execute([$taskId]); $task = $stmt->fetch(); // 4. WS — обновление счетчиков $publisher = new EventPublisher(); $publisher->publish([ 'type' => 'comment_added', 'task_id' => $taskId, 'comment_count' => (int)($commentMeta['comment_count'] ?? 0), 'last_comment_id' => (int)($commentMeta['last_comment_id'] ?? 0), 'author_user_id' => (int)Auth::user()['id'], 'created_at' => date('Y-m-d H:i:s'), ]); // 5. Уведомление ответственному if ($task && !empty($task['assignee_id'])) { $assigneeId = (int)$task['assignee_id']; $currentUserId = (int)Auth::user()['id']; if ($assigneeId !== $currentUserId) { // запись в БД (если есть таблица notifications) $stmt = $pdo->prepare(" INSERT INTO notifications ( user_id, type, title, message, data_json, is_read, created_at ) VALUES (?, ?, ?, ?, ?, 0, NOW()) "); $stmt->execute([ $assigneeId, 'task_comment_added', 'Новый комментарий', 'Задача: ' . (string)$task['name'], json_encode(['task_id' => $taskId], JSON_UNESCAPED_UNICODE), ]); // WS уведомление $publisher->publish([ 'type' => 'notification_created', 'user_id' => $assigneeId, 'task_id' => $taskId, 'title' => 'Новый комментарий', 'message' => 'Задача: ' . (string)$task['name'], 'created_at' => date('Y-m-d H:i:s'), ]); } } // 6. Ответ if ($this->isAjax()) { $this->json([ 'success' => true, 'task_id' => $taskId, 'comment_count' => (int)($commentMeta['comment_count'] ?? 0), 'last_comment_id' => (int)($commentMeta['last_comment_id'] ?? 0), ]); } header('Location: /tasks'); exit; } private function isAjax(): bool { return strtolower((string)($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '')) === 'xmlhttprequest'; } private function json(array $data, int $statusCode = 200): void { http_response_code($statusCode); header('Content-Type: application/json; charset=utf-8'); echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } }