pdo = $pdo ?? DatabaseFactory::dev(); } public function find(int $id): ?Task { $stmt = $this->pdo->prepare('SELECT * FROM tasks WHERE id = :id'); $stmt->execute(['id' => $id]); $row = $stmt->fetch(); return $row !== false ? Task::fromArray($row) : null; } public function findById(int $id): ?Task { return $this->find($id); } public function findByUuid(string $uuid): ?Task { $stmt = $this->pdo->prepare('SELECT * FROM tasks WHERE uuid = :uuid'); $stmt->execute(['uuid' => $uuid]); $row = $stmt->fetch(); return $row !== false ? Task::fromArray($row) : null; } public function findAll(array $filters = [], int $limit = 50, int $offset = 0): array { $where = []; $params = []; if (isset($filters['status']) && $filters['status'] !== '') { $where[] = 'status = :status'; $params['status'] = $filters['status']; } if (isset($filters['type']) && $filters['type'] !== '') { $where[] = 'type = :type'; $params['type'] = $filters['type']; } if (isset($filters['created_by']) && $filters['created_by'] !== '') { $where[] = 'created_by = :created_by'; $params['created_by'] = $filters['created_by']; } if (isset($filters['search']) && $filters['search'] !== '') { $where[] = '(title LIKE :search OR description LIKE :search)'; $params['search'] = '%' . $filters['search'] . '%'; } $whereClause = count($where) > 0 ? 'WHERE ' . implode(' AND ', $where) : ''; $sql = "SELECT * FROM tasks {$whereClause} ORDER BY created_at DESC LIMIT :limit OFFSET :offset"; $stmt = $this->pdo->prepare($sql); foreach ($params as $key => $value) { $stmt->bindValue(':' . $key, $value); } $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT); $stmt->bindValue(':offset', $offset, \PDO::PARAM_INT); $stmt->execute(); $tasks = []; while ($row = $stmt->fetch()) { $tasks[] = Task::fromArray($row); } return $tasks; } public function findByStatus(string $status, int $limit = 50): array { return $this->findAll(['status' => $status], $limit); } public function findByAssignee(string $assignee, int $limit = 50): array { $sql = 'SELECT t.* FROM tasks t INNER JOIN task_assignments ta ON t.id = ta.task_id WHERE ta.assignee = :assignee ORDER BY t.created_at DESC LIMIT :limit'; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':assignee', $assignee); $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT); $stmt->execute(); $tasks = []; while ($row = $stmt->fetch()) { $tasks[] = Task::fromArray($row); } return $tasks; } public function findByCreator(string $createdBy, int $limit = 50): array { return $this->findAll(['created_by' => $createdBy], $limit); } public function findSubtasks(int $parentTaskId): array { $stmt = $this->pdo->prepare( 'SELECT * FROM tasks WHERE parent_task_id = :parent_id ORDER BY created_at ASC' ); $stmt->execute(['parent_id' => $parentTaskId]); $tasks = []; while ($row = $stmt->fetch()) { $tasks[] = Task::fromArray($row); } return $tasks; } public function save(Task $task): int { $sql = 'INSERT INTO tasks ( uuid, title, description, type, status, created_by, created_by_type, parent_task_id, due_date, created_at, updated_at, completed_at, metadata ) VALUES ( :uuid, :title, :description, :type, :status, :created_by, :created_by_type, :parent_task_id, :due_date, :created_at, :updated_at, :completed_at, :metadata )'; $stmt = $this->pdo->prepare($sql); $data = $task->toArray(); $stmt->execute([ 'uuid' => $data['uuid'], 'title' => $data['title'], 'description' => $data['description'], 'type' => $data['type'], 'status' => $data['status'], 'created_by' => $data['created_by'], 'created_by_type' => $data['created_by_type'], 'parent_task_id' => $data['parent_task_id'], 'due_date' => $data['due_date'], 'created_at' => $data['created_at'], 'updated_at' => $data['updated_at'], 'completed_at' => $data['completed_at'], 'metadata' => json_encode($data['metadata']), ]); return (int) $this->pdo->lastInsertId(); } public function update(Task $task): bool { $sql = 'UPDATE tasks SET title = :title, description = :description, type = :type, status = :status, parent_task_id = :parent_task_id, due_date = :due_date, updated_at = :updated_at, completed_at = :completed_at, metadata = :metadata WHERE id = :id'; $stmt = $this->pdo->prepare($sql); $data = $task->toArray(); return $stmt->execute([ 'id' => $data['id'], 'title' => $data['title'], 'description' => $data['description'], 'type' => $data['type'], 'status' => $data['status'], 'parent_task_id' => $data['parent_task_id'], 'due_date' => $data['due_date'], 'updated_at' => $data['updated_at'], 'completed_at' => $data['completed_at'], 'metadata' => json_encode($data['metadata']), ]); } public function delete(int $id): bool { $stmt = $this->pdo->prepare('DELETE FROM tasks WHERE id = :id'); return $stmt->execute(['id' => $id]); } public function count(array $filters = []): int { $where = []; $params = []; if (isset($filters['status']) && $filters['status'] !== '') { $where[] = 'status = :status'; $params['status'] = $filters['status']; } if (isset($filters['type']) && $filters['type'] !== '') { $where[] = 'type = :type'; $params['type'] = $filters['type']; } $whereClause = count($where) > 0 ? 'WHERE ' . implode(' AND ', $where) : ''; $stmt = $this->pdo->prepare("SELECT COUNT(*) FROM tasks {$whereClause}"); $stmt->execute($params); return (int) $stmt->fetchColumn(); } public function getStatistics(): array { $sql = "SELECT COUNT(*) as total, SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending, SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed, SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed, SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) as cancelled, SUM(CASE WHEN type = 'human_task' THEN 1 ELSE 0 END) as human_tasks, SUM(CASE WHEN type = 'ai_task' THEN 1 ELSE 0 END) as ai_tasks, SUM(CASE WHEN type = 'mixed' THEN 1 ELSE 0 END) as mixed_tasks FROM tasks"; $stmt = $this->pdo->query($sql); return $stmt->fetch(); } }