【问题标题】:Traverse Doctrine NestedSet structure without querying无需查询即可遍历 Doctrine NestedSet 结构
【发布时间】:2011-08-25 11:08:43
【问题描述】:

我通常这样获取 NestedSet 树:

class ModelTable extends Doctrine_Table
{
  /**
   * Gets tree elements in one query
   */
  public function getMenuTree()
  {
    $q = $this->createQuery('p')
      ->orderBy('p.root_id')
      ->addOrderBy('p.lft');

    $tree = $q->execute(array(),  Doctrine_Core::HYDRATE_RECORD_HIERARCHY);      

    return $tree;
  }
}

所以我实际上可以在只使用一个查询数据库的同时显示整棵树。直到我尝试遍历树。例如,如果您在这样的节点上调用方法:

$node->getNode()->getAncestors()

Doctrine 将为此构建一个全新的查询(查看 Doctrine_Node_NestedSet::getAncestors())。其他遍历方法如 getChildren() 也使用 DQL。但这有点低效,不是吗?一旦我获取了整棵树,我就不想再查询数据库了。

也许有人写了一个驱动程序来做正确的事情? (没有 DQL)

【问题讨论】:

    标签: symfony1 doctrine doctrine-1.2


    【解决方案1】:

    如果您只想获取孩子(这是最有可能的,为什么需要getAncestors() 在树上迭代?),您还可以保留您向我们展示的代码作为示例,并执行类似的操作这个:

    foreach ($categories->getFirst()->get('__children') as $child) {
        // ...
    }
    

    这是记录在here (很难找到,除非您选择阅读整个文档)。

    我曾经在只有一个查询的整棵树上使用递归代码。

    1015 lib % ack --type="php" "_node"                                                                                                                                                          2011-05-15 14:26:22 greg pts/1
    vendor/doctrine/Doctrine/Record.php
    94:    protected $_node;
    814:        unset($vars['_node']);
    2403:        if ( ! isset($this->_node)) {
    2404:            $this->_node = Doctrine_Node::factory($this,
    2410:        return $this->_node;
    liche ~/source/symfony/1.4/lib/plugins/sfDoctrinePlugin/lib
    

    _node 似乎只设置在getNode() 本身,我不知道您是否可以像其他任何字段一样对其进行水合,也不知道您将如何做到这一点。

    我认为getNode() 应该只用于对树的修改。 如果要显示从根开始的路径,则应使用递归方法来显示树,并使用包含父路径的参数。如果您还需要树功能,请告诉我们...

    更新

    我想我终于明白了。你想显示一个树形菜单和一个面包屑,并且你想在面包屑中重用菜单的数据,不是吗? 要显示你的面包屑,你必须在 $tree 上递归,并且当且仅当它是当前页面的祖先时才显示一个节点。还有一种方法:isAncestorOf()。 所以“你所要做的一切”就是一个模板,它可以做这样的事情:

    //module/templates/_breadcrumbElement.php
    foreach ($node->get('__children') as $child) :
      if ($child->isAncestorOf($pageNode)):
         echo link_to($child->getName(), $child->getUrl());
         include_partial('module/breadcrumbElement', array('node' => $child, 'pageNode' => $pageNode));
      endif;
    endforeach;
    

    喂它你的树根,你会没事的。希望。

    【讨论】:

    • 很高兴看到有人在周日工作 =)。 NestedSet::fetchTree 返回完全相同的 Doctrine_Collection (或数组,取决于水合方法)。当您迭代它并需要树功能时,您可以在特定记录上调用 $node = $record->getNode() 。我对吗?然而,问题在于 $node 现在不知道您的集合,因此需要查询 db 来遍历树。
    • 为什么你可能想要获得祖先?例如,从根获取节点的完整路径。这里甚至还有一个方法:Doctrine_Node_NestedSet::getPath()。
    • @Dziamid:好的,对第一种方法很抱歉,这是一种预感,我将对其进行更新,因为我认为 _node 仅设置在 getNode() 本身中。
    • @Dziamid:顺便说一句,我周末不工作,我只是沉迷于 SO ;)
    • 我完全理解递归的方法。如果我需要祖先的多个属性(例如,构建面包屑菜单的 url 和名称)怎么办?在“真正的”树结构中,子对象通常具有对其父对象的引用。这很有意义,不是吗?
    猜你喜欢
    • 1970-01-01
    • 2015-12-16
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 2013-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多