PHP RecursiveIteratorIterator: определение первого и последнего элемента на каждом уровне ветви - PullRequest
5 голосов
/ 03 декабря 2010

Я расширил Zend_View_Helper_Navigation_Menu, и он использует RecursiveIteratorIterator для перебора дерева меню. Я хочу определить, нахожусь ли я на первом или последнем элементе уровня ветви в дереве.

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

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

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

  • PHP Версия 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;
}

Ответы [ 2 ]

3 голосов
/ 06 декабря 2010

Использование 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 голосов
/ 07 декабря 2010

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

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

Вам придется проверить последний элемент отдельно.

...