2010-12-03 8 views
5

He extendido Zend_View_Helper_Navigation_Menu, y usa un RecursiveIteratorIterator para recorrer el árbol del menú. Lo que quiero poder determinar es si estoy en el primer o el último elemento para un nivel de rama en el árbol.PHP RecursiveIteratorIterator: determinando el primer y último elemento en cada nivel de rama

He aquí un ejemplo de lo que estoy buscando:

  • de navegación 1 (primera)
    • Nav 1.1 (primera & pasado)
      • Nav 1.1.1 (primera)
      • Nav 1.1.2
      • Nav 1.1.3 (último)
  • Nav 2
    • Nav 2.1 (primera)
    • Nav 2.2 (última)
  • Nav 3 (última)
    • Nav 3.1 (primera)
    • Nav 3.2 (último)

Información adicional

  • PHP Versión 5.2.13

Solución

dentro del bucle foreach ($iterator as $page) dos variables se pueden utilizar para realizar un seguimiento de la profundidades, $depth y $prevDepth. Un simple condicional de comparación puede determinar el primer elemento en un nivel de rama: if ($depth > $prevDepth).

Creación de una RecursiveCachingIterator utilizando el objeto Zend_Navigation_Container y luego utilizar eso para crear la RecursiveIteratorIterator agrega el método 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

Debería ser posible de alguna manera usar 'getChildren' o' nextElement' ... Pero lamentablemente, esas clases no están muy documentadas aún http://www.php.net/manual/en/class.recursiveiteratoriterator.php –

+0

What modo es el 'RecursiveIteratorIterator' corriendo con (es el segundo parámetro para el constructor)? 'LEAVES_ONLY',' CHILD_FIRST' o 'SELF_FIRST' (' LEAVES_ONLY' es el valor predeterminado)? – ircmaxell

+0

¿Puedes dar un ejemplo de uso de cómo piensas usarlo? – Gordon

Respuesta

3

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

Otra solución con arreglo:

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

Ha publicado algunos buenos ejemplos de código aquí, pero no veo dónde determina el primer o el último elemento. – Sonny

+0

@Sonny: en el primer fragmento '$ rii-> hasNext()' es verdadero para todos menos el último elemento y 'count ($ rii-> getCache()) 'es igual a 1 si el iterador está en el primer elemento. En el segundo fragmento 'reset ($ tree)! == $ value && end ($ tree)! == $ value' es verdadero para todos menos el primer y último elemento. – rik

+0

Según su descripción, parece que solo determina el primer y último elemento del iterador "aplanado", y no el primer y último elemento de la rama/nivel. Para ser justos, mi pregunta original puede no haber dejado eso en claro, así que la actualicé para aclararla. – Sonny

0

Si $ iterador es una matriz densa, esto podría funcionar:

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

Se hará tiene que probar para el mismo último artículo por separado.

Cuestiones relacionadas