symfony - nestedSet and rendering of parent/child nodes
I have created a model using the doctrine nestedSet behaviour in Symfony1.4, as I'm trying to create a basic cms, with heiracrchial pages.
I have a couple of pages, with parent and child nodes
Parent_1
Child_1
Child_2
Parent_2
Child_3
My problem comes with rendering these items in terms of a navigation header. (<ul><li>
etc)
What would be the easiest/best way to do this?
I'd like the root
nodes to have URLs such开发者_如何学Python as /parent_1
and subsequent child nodes, be parent_1/child_1
Thanks
I wrote a recursive function that will draw the tree starting from any node. Specifying the root node will draw the entire tree. It is used in my cart plug-in, and you can view a demo of the completed UI here.
I have pasted the function below, but modified it from my implementation to make it more clear.
<?php
//Render a nested set. Recurses for all descendants of that node. Can be used to draw entire tree, when specifying root id.
//Secondary parameter ($node) is used for performance boost, internally in function.
public static function display_node($id, $node = null) {
$isRoot = false;
if ($node == null) {
$node = Doctrine_Core::getTable('YOURNESTEDTABLENAME')->findOneById($id)->getNode();
if ($node->isRoot()) {
$isRoot = true;
}
}
$record = $node->getRecord();
if (!$isRoot) {
echo "<li class='tree_item' id='list_". $record->getId() . "'>";
echo "<div class='listitem' id='listitem_".$record->getId()."'>";
echo $record->getName();
echo "<div style='clear:both'></div>";
echo "</div>";
if ($node->hasChildren()) {
echo "<ol>";
foreach ($node->getChildren() as $child) {
self::display_node($child->getId(), $child->getNode());
}
echo "</ol>";
}
}
else {
if ($node->hasChildren()) {
echo "<ol class='sortable'>";
echo "<li class='tree_item root_item' style='position: relative;' id='list_". $record->getId() . "'>";
foreach ($node->getChildren() as $child) {
self::display_node($child->getId(), $child->getNode());
}
echo "</ol>";
}
}
}
?>
You can also easily modify the code to add URLs as you wish. Hopefully this helps. Let me know if you require clarification.
I hate to echo view element anywhere other than templates, so here's my version.
//actions:
public function executeShow(sfWebRequest $request)
{
$this->tree = Doctrine::getTable('Model')->getMenuTree();
}
//lib:
class ModelTable extends Doctrine_Table
{
/**
* Gets tree element in one query
*/
public function getMenuTree()
{
$q = $this->createQuery('g')
->orderBy('g.root_id')
->addOrderBy('g.lft')
->where('g.root_id NOT NULL');
return $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY_HIERARCHY);
}
}
//template:
<?php function echoNode($tree, $parent=null) { ?>
<ul>
<?php foreach ($tree as $node): ?>
<li data-id='<?php echo $node['id'] ?>'>
<?php echo $node['name'] ?>
<?php if (count($node['__children']) > 0): ?>
<?php echo echoNode($node['__children'], $node) ?>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php } ?>
<?php echo echoNode($tree) ?>
Now, if you need a part of tree, you can either do in an action or better yet, write a separate model method for that.
精彩评论