如何自动获取指定ID分类节点的所有父节点(Symfony+Gedmo-Tree)
解决指定分类节点及其所有父节点的自动获取问题
我明白你现在的困扰——想自动获取指定分类的所有父节点,而不是靠手动加根节点的临时方案凑数。之前尝试的->orWhere('node.id in (node.parent)')报错,是因为这种写法逻辑不对:node.parent是单个字段(对应父节点ID),不是集合,而且树形结构的父节点需要递归查询,不是简单的WHERE条件能搞定的。
下面给你两种靠谱的解决方案,按需选择:
方案一:用递归CTE(推荐,支持MySQL 8+/PostgreSQL)
这是最优雅的方式,利用数据库的递归公共表表达式(CTE)自动遍历所有父节点,完全不需要手动处理层级逻辑。
单个分类ID的场景
public function getCategoryWithAncestors(int $categoryId): array { $em = $this->getEntityManager(); $connection = $em->getConnection(); // 递归CTE:先取目标节点,再递归关联父节点直到根节点 $sql = <<<SQL WITH RECURSIVE category_hierarchy AS ( SELECT id, name, parent_id -- 替换成你的Category实体实际字段 FROM category WHERE id = :categoryId UNION ALL SELECT c.id, c.name, c.parent_id FROM category c JOIN category_hierarchy ch ON c.id = ch.parent_id ) SELECT * FROM category_hierarchy ORDER BY parent_id IS NULL DESC, parent_id, id; -- 根节点排最前,按层级排序 SQL; $stmt = $connection->prepare($sql); $stmt->bindValue('categoryId', $categoryId); $stmt->execute(); return $stmt->fetchAllAssociative(); }
多个分类ID的场景(适配你原函数的需求)
如果需要同时处理多个分类ID,只需修改CTE的初始查询条件:
public function getCategoriesWithAncestors(array $categoryIds): array { $em = $this->getEntityManager(); $connection = $em->getConnection(); // 生成安全的占位符,避免SQL注入 $placeholders = implode(',', array_fill(0, count($categoryIds), '?')); $sql = <<<SQL WITH RECURSIVE category_hierarchy AS ( SELECT id, name, parent_id FROM category WHERE id IN ($placeholders) UNION ALL SELECT c.id, c.name, c.parent_id FROM category c JOIN category_hierarchy ch ON c.id = ch.parent_id ) SELECT * FROM category_hierarchy ORDER BY parent_id IS NULL DESC, parent_id, id; SQL; $stmt = $connection->prepare($sql); $stmt->execute($categoryIds); return $stmt->fetchAllAssociative(); }
方案二:利用Doctrine Tree扩展(如果已集成)
如果你已经用了DoctrineExtensions的Tree组件(比如Adjacency List模式),可以直接用现成方法获取父节点:
use Gedmo\Tree\Entity\Repository\NestedTreeRepository; // 确保你的Category仓库继承自NestedTreeRepository public function getCategoryWithAncestors(int $categoryId): array { $category = $this->find($categoryId); // 获取所有父节点(第二个参数true表示包含自身) return $this->getAncestors($category, true); }
把平级结果转成树形结构
如果需要把查询到的平级节点转成嵌套的树形结构,可以用递归函数处理:
private function buildTree(array $items, $parentId = null): array { $tree = []; foreach ($items as $item) { if ($item['parent_id'] === $parentId) { $children = $this->buildTree($items, $item['id']); if (!empty($children)) { $item['children'] = $children; } $tree[] = $item; } } return $tree; } // 使用示例: $flatResult = $this->getCategoriesWithAncestors([1,3,5]); $treeResult = $this->buildTree($flatResult);
这样就完全替代了手动获取根节点的临时方案,自动递归获取所有父节点啦!
内容的提问来源于stack exchange,提问作者emovere
相关产品推荐
相关产品推荐

