Rephrasing
Rephrasing your problem : you need (every ancestor of your node and your node) and their siblings.
Other rephrasing : you need every ancestor of your node along with all of their children (but not all of their descendants)
And don't think you should have hasManyRoots set to true, unless you have several shops. Now let's assume you have one root, which you could name 'shop'
Here is a third, more simple rephrasing: all you need is the children of every ancestor of your node (and love, according to the Beatles).
Fetching the data
Getting the ancestors as an array (see why in the last §) is easy :
$this->ancestors = $currentCategory->getNode()->getAncestors()->getData();
Now let's build the query which will give you what you need. Let's assume your model is named Category, not Categories (it really should).
$q = CategoryTable::getInstance()->createQuery('c');
foreach ($this->ancestors as $ancestor)
{
// should work thanks to AND priority over OR
$q->orWhere('c.level = ?' $ancestor->getLevel() + 1)
->andWhere('c.lft > ?' $ancestor->getLeftValue())
->andWhere('c.rgt < ?' $ancestor->getRightValue())
}
If you don't understand what this last thing is, then you probably need to read this excellent article about adjacency list model vs nested set model
Ok now that you have your query, let's fetch the results:
$this->categoryTree = $q->execute(
array(),
Doctrine_Core::HYDRATE_RECORD_HIERARCHY);
O_o wait... what was that last parameter about? You probably didn't hear about it when reading the doctrine documentation about nested set. That's because it is documented on the page about data hydrators. This really sucks, because HYDRATE_RECORD_HIERARCHY is very interesting when working with nested sets. Now what you have everything you need in $categoryTree as a hierarchy. With only 2 requests no matter how deep your tree is! I guess one could write it in one request, but I don't see how.
Note: there also is Doctrine_Core::HYDRATE_ARRAY_HIERARCHY, which hydrates to a hierarchical array, which is much faster. You can use it if you don't need to call methods that provide stuff that is not part of your object, or that is computed at run time. You'll just have to use array instead of object notation in your template (e.g. $categoryTree['children'])
Displaying the data
Now in your _menu.php template, here is what you can do:
<?php
array_shift($ancestors);
include_partial('level', array(
'children' => $categoryTree->get('__children'),
'ancestors' => $ancestors
);
And in _level.php:
<ul>
<?php $selectedChild = array_shift($ancestors);
foreach ($children as $child):
if ($isSelected = ($child->getId() == $selectedChild->getId())):
$grandChildren = $child->get('__children');
endif; ?>
<li<?php if ($isSelected):?> class="selected"<?php endif?>>
<?php echo $child->getName() ?>
</li>
<?php endforeach ?>:
</ul>
<?php if (count($ancestors)):
// RecursiviRecurRecuRecursiRRecursivityecursivityvityrsivitysivityty
include_partial('level', array(
'children' => $grandChildren,
'ancestors' => $ancestors
);
endif; ?>
I just wrote this without testing anything, so it will probably not work right from the start. Just keep me posted with the problems you have. Good luck!