问题
I have extended Zend_View_Helper_Navigation_Menu
, and it uses a RecursiveIteratorIterator
to iterate over the menu tree. What I want to be able to determine is whether I am on the first or last item for a branch level in the tree.
Here's an example of what I'm looking for:
- Nav 1 (first)
- Nav 1.1 (first & last)
- Nav 1.1.1 (first)
- Nav 1.1.2
- Nav 1.1.3 (last)
- Nav 1.1 (first & last)
- Nav 2
- Nav 2.1 (first)
- Nav 2.2 (last)
- Nav 3 (last)
- Nav 3.1 (first)
- Nav 3.2 (last)
Additional Information
- PHP Version 5.2.13
Solution
Within the foreach ($iterator as $page)
loop two variables can be used to keep track of the depths, $depth
and $prevDepth
. A simple comparison conditional can then determine the first item in a branch level: if ($depth > $prevDepth)
.
Creating a RecursiveCachingIterator
using the Zend_Navigation_Container
object and then using that to create the RecursiveIteratorIterator
adds the the hasNext()
method.
$rci = new RecursiveCachingIterator($container, CachingIterator::FULL_CACHE);
$iterator = new RecursiveIteratorIterator($rci,
RecursiveIteratorIterator::SELF_FIRST);
/* snip */
$prevDepth = -1;
foreach ($iterator as $page) {
$depth = $iterator->getDepth();
/* snip */
if ($depth > $prevDepth) {
// first branch item
}
/* snip */
if (!$iterator->hasNext()) {
// last branch item
}
/* snip */
$prevDepth = $depth;
}
回答1:
Using RecursiveCachingIterator:
$rdi = new RecursiveDirectoryIterator('.');
$rci = new RecursiveCachingIterator($rdi, CachingIterator::FULL_CACHE);
$rii = new RecursiveIteratorIterator($rci, RecursiveIteratorIterator::SELF_FIRST);
foreach ($rii as $file) {
if ($file->isDir()) {
echo $file->getFilename() . PHP_EOL;
}
elseif (!$rii->hasNext()) {
echo $file->getFilename() . PHP_EOL;
}
elseif (count($rii->getCache()) == 1) {
echo $file->getFilename() . PHP_EOL;
}
}
Another solution with array:
function buildTree(RecursiveDirectoryIterator $iterator) {
$tree = array();
foreach ($iterator as $fileinfo) {
if ($fileinfo->isDir()) {
$tree[$fileinfo->getFilename()] = buildTree($iterator->getChildren());
} else {
$tree[$fileinfo->getFilename()] = $fileinfo->getFilename();
}
}
return $tree;
}
function filterTree(array $tree) {
foreach ($tree as $key => $value) {
if (is_array($value)) {
$tree[$key] = filterTree($value);
} elseif (reset($tree) !== $value && end($tree) !== $value) {
unset($tree[$key]);
}
}
return $tree;
}
print_r(filterTree(buildTree(new RecursiveDirectoryIterator('.'))));
回答2:
If $iterator is a dense array, this might work:
// iterate container
$prevDepth = -1;
foreach ($iterator as $key => $page) {
$depth = $iterator->getDepth();
/* snip */
if ($depth > $prevDepth) {
// $page is first branch item
if (isset($iterator[$key - 1])) {
// $iterator[$key - 1] is last branch item in previous branch
}
}
/* snip */
$prevDepth = $depth;
}
You will have to test for the very last item separately.
来源:https://stackoverflow.com/questions/4348100/php-recursiveiteratoriterator-determining-first-and-last-item-at-each-branch-le