使用Doctrine NestedSet进行面包屑导航

时间:2011-05-15 14:57:25

标签: symfony1 doctrine nested-sets doctrine-1.2

我有一个实现NestedSet行为的模型:

Page:
  actAs:
    NestedSet:
      hasManyRoots: true
      rootColumnName: root_id
  columns:
    slug: string(255)
    name: string(255)

示例灯具:

Page:
  NestedSet: true
  Page_1:
    slug: slug1
    name: name1
  Page_2:
    slug: slug2
    name: name2
    children:
      Page_3:
        slug: page3
        name: name3

我正在寻找实施面包屑导航(路径)的最简单方法。例如,对于Page_3导航将如下所示:

<a href="page2">name2</a> > <a href="page2/page3>name3</a>

3 个答案:

答案 0 :(得分:1)

由于我讨厌在模板(和部分)中使用任何类型的逻辑,这是我稍微改进的版本。

//module/templates/_breadcrumbElement.php
<?php foreach ($node as $child): ?>
<li>
  <a href="<?php echo $child->getPath($parent) ?>"><?php echo $child->getName() ?></a>
  <?php if (count($child->get('__children')) > 0): ?>
    <ul>
      <?php include_partial('node', array('node' => $child->get('__children'), 'parent' => $child)) ?>
    </ul>
  <?php endif; ?>
</li>
<?php endforeach; ?>

因此,构建url的所有逻辑现在都在Page :: getPath()方法中。

class Page extends BasePage
{
  /**
   * Full path to node from root
   *
   */
  protected $path = false;

  public function __toString()
  {
    return $this->getSlug();
  }
  public function getPath($parent = null)
  {
    if (!$this->path)
    {
      $this->path = join('/', null !== $parent ? array($parent->getPath(), $this) : array($this));
    }
    return $this->path;
  } 
}

我不喜欢将$ parent传递给Page :: getPath()。它只是没有任何语义意义。

答案 1 :(得分:0)

与其他问题几乎相同,但您必须添加'parentUrl'变量:

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

将树的根目录为$node(按层次方式对其进行水合),将当前页面的节点作为$pageNode,将“{”作为$currentNodeUrl并添加'&gt; '以及当前页面的链接。

为什么此解决方案使用递归而不是getAncestors()?因为你的网址似乎意味着递归。

答案 2 :(得分:0)

使用getAncestors()和递归的另一个答案,更简单(也许更有效):

//module/templates/_breadcrumbElement.php
if ($node = array_pop($nodes)) // stop condition
{
    $currentNodeUrl = $parentUrl . $node->getSlug() . '/';
    echo link_to($node->getName(), $currentNodeUrl) . ' > ' ;
    include_partial('module/breadcrumbElement', array(
      'nodes' => $nodes, 'parentUrl' => $currentNodeUrl));
}

使用祖先节点数组调用此方法,或者如果要直接与Doctrine_Collection一起使用,可以找到弹出getAncestors()的方法。 同样,你所有的问题都来自你的网址是递归计算的事实,如果你有一个当前网址的colum路径(但你必须计算,更新它)等,它会更简单,更快速地显示。如果你有更多的读取而不是写入(如果你的树不经常改变),请考虑这样做。