2010-12-03 2 views
5

Zend_View_Helper_Navigation_Menuを拡張し、RecursiveIteratorIteratorを使用してメニューツリーを反復処理します。ツリー内のブランチレベルの最初の項目か最後の項目かどうかを判断できるようにする必要があります。ここでPHP RecursiveIteratorIterator:各ブランチレベルの最初と最後の項目を決定する

は私が探しているものの例です:

  • ナビ1(最初の)
    • ナビ1.1(最初&最後)
      • ナビ1.1.1(最初の)
      • Nav 1.1.2
      • Nav 1.1.3(最終)
  • ナビ2
    • ナビ2.1(第一)
    • ナビゲーション2.2(最後)
  • ナビ3(最後)
    • ナビ3.1(第一)
    • ナビ3.2(最後)

追加情報

  • PHPバージョン5.2.13

ソリューション2つの変数がを追跡するために使用することができますforeach ($iterator as $page)ループ内

深さ、$depthおよび$prevDepth。単純比較条件では、ブランチレベルの最初の項目を確認することができます:if ($depth > $prevDepth)

Zend_Navigation_Containerオブジェクトを使用してRecursiveCachingIteratorを作成し、それを使用してRecursiveIteratorIteratorを作成すると、hasNext()メソッドが追加されます。

RecursiveCachingIteratorを使用して
$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 –

+0

modeは 'RecursiveIteratorIterator'で実行されます(コンストラクタの2番目のパラメータです)。 'LEAVES_ONLY'、' CHILD_FIRST'または 'SELF_FIRST'(' LEAVES_ONLY'がデフォルトです)? – ircmaxell

+0

あなたはそれを使用する方法の使用例を与えることができます – Gordon

答えて

3

$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

良いコード例をここに掲載しましたが、最初または最後の項目がどこにあるかわかりません。 – Sonny

+0

@ソニー:最初のスニペットでは、 '$ rii-> hasNext()'は最後の要素を除くすべての要素に対してtrueであり、 'count($ rii-> getCache())'はイテレータが最初の要素にある場合は1になります。 2番目のスニペットでは、 'reset($ tree)!== $ value && end($ tree)!== $ value'は最初と最後の要素を除くすべての要素に当てはまります。 – rik

+0

説明に基づいて、「平坦化」イテレータの最初の要素と最後の要素のみを決定し、分岐/レベルの最初と最後の要素は決定しないように思えます。公正であるために、私の元々の質問はそれを明確にしていないかもしれないので、明確にするためにそれを更新しました。 – Sonny

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

をあなたがします非常にテストする必要があります最後の項目は別にします。

関連する問題