2010-12-03 3 views
5

Я расширил Zend_View_Helper_Navigation_Menu, и он использует RecursiveIteratorIterator для итерации по дереву меню. То, что я хочу, чтобы определить, является ли я на первом или последнем элементе для уровня ветки в дереве.PHP RecursiveIteratorIterator: определение первого и последнего элемента на каждом уровне филиала

Вот пример того, что я ищу:

  • Nav 1 (первый)
    • Nav 1.1 (первый & последний)
      • Nav 1.1.1 (первый)
      • Nav 1.1.2
      • Nav 1.1.3 (последний)
  • нав 2
    • Нав 2.1 (первый)
    • Нав 2.2 (последний)
  • Нав 3 (последний)
    • Нав 3.1 (первый)
    • Нав 3.2 (последний)

Дополнительная информация

  • PHP Version 5.2.13

Решение

В цикле foreach ($iterator as $page) две переменные могут быть использованы для отслеживания из глубины, $depth и $prevDepth. Простой пример сравнения может затем определить первый элемент на уровне филиала: if ($depth > $prevDepth).

Создание RecursiveCachingIterator с помощью Zend_Navigation_Container объекта, а затем с помощью, чтобы создать RecursiveIteratorIterator добавляет метод hasNext().

$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; 
} 
+0

Должно быть возможно каким-то образом использовать `getChildren` или` nextElement` ... Но, к сожалению, эти классы еще мало документированы http://www.php.net/manual/en/class.recursiveiteratoriterator.php – 2010-12-03 17:29:36

+0

Что mode - это `RecursiveIteratorIterator`, работающий с (это второй параметр для конструктора)? `LEAVES_ONLY`,` CHILD_FIRST` или `SELF_FIRST` (` LEAVES_ONLY` является значением по умолчанию)? – ircmaxell 2010-12-03 17:41:24

ответ

3

Использование 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; 
    } 
} 

Другое решение с массивом:

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('.')))); 
0

Если $ итератор плотный массив, это может работать:

// 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; 
} 

Вы будете должны испытать на самом последнем i отдельно.