db = DatabaseFactory::content(); } /** * {@inheritDoc} */ public function findAll(): array { return $this->db->query( 'SELECT t.*, COUNT(DISTINCT ct.chunk_id) as chunk_count, (SELECT COUNT(*) FROM taxonomy_terms WHERE parent_id = t.id) as children_count FROM taxonomy_terms t LEFT JOIN chunk_taxonomy ct ON t.id = ct.taxonomy_term_id GROUP BY t.id ORDER BY t.path, t.name' )->fetchAll(); } /** * {@inheritDoc} */ public function getStats(): array { $result = $this->db->query( 'SELECT (SELECT COUNT(*) FROM taxonomy_terms) as total_terms, (SELECT COUNT(*) FROM taxonomy_terms WHERE parent_id IS NULL) as root_terms, (SELECT MAX(depth) FROM taxonomy_terms) as max_depth, (SELECT COUNT(DISTINCT chunk_id) FROM chunk_taxonomy) as tagged_chunks' )->fetch(); return $result !== false ? $result : [ 'total_terms' => 0, 'root_terms' => 0, 'max_depth' => 0, 'tagged_chunks' => 0, ]; } /** * {@inheritDoc} */ public function find(int $id): ?array { $stmt = $this->db->prepare('SELECT * FROM taxonomy_terms WHERE id = :id'); $stmt->execute(['id' => $id]); $result = $stmt->fetch(); return $result === false ? null : $result; } /** * {@inheritDoc} */ public function create(string $name, ?int $parentId = null): int { $depth = 0; $path = $name; if ($parentId !== null) { $parent = $this->find($parentId); if ($parent !== null) { $depth = $parent['depth'] + 1; $path = $parent['path'] . '/' . $name; } } $stmt = $this->db->prepare( 'INSERT INTO taxonomy_terms (name, parent_id, depth, path, created_at) VALUES (:name, :parent, :depth, :path, NOW())' ); $stmt->execute([ 'name' => $name, 'parent' => $parentId, 'depth' => $depth, 'path' => $path, ]); return (int) $this->db->lastInsertId(); } /** * {@inheritDoc} */ public function update(int $id, string $name, ?int $parentId = null): bool { $depth = 0; $path = $name; if ($parentId !== null) { $parent = $this->find($parentId); if ($parent !== null) { $depth = $parent['depth'] + 1; $path = $parent['path'] . '/' . $name; } } $stmt = $this->db->prepare( 'UPDATE taxonomy_terms SET name = :name, parent_id = :parent, depth = :depth, path = :path WHERE id = :id' ); return $stmt->execute([ 'id' => $id, 'name' => $name, 'parent' => $parentId, 'depth' => $depth, 'path' => $path, ]); } /** * {@inheritDoc} */ public function delete(int $id): bool { // Check for children $stmt = $this->db->prepare('SELECT COUNT(*) FROM taxonomy_terms WHERE parent_id = :id'); $stmt->execute(['id' => $id]); if ((int) $stmt->fetchColumn() > 0) { return false; // Has children, cannot delete } // Delete chunk associations $stmt = $this->db->prepare('DELETE FROM chunk_taxonomy WHERE taxonomy_term_id = :id'); $stmt->execute(['id' => $id]); // Delete term $stmt = $this->db->prepare('DELETE FROM taxonomy_terms WHERE id = :id'); return $stmt->execute(['id' => $id]); } /** * {@inheritDoc} */ public function findForSelect(): array { return $this->db->query( 'SELECT id, name, depth, path FROM taxonomy_terms ORDER BY path, name' )->fetchAll(); } }