PHP - вернуть массив родителей из многомерного ассоциативного массива для списка хлебных крошек

Я пытаюсь создать динамические хлебные крошки из массива. Таким образом, я могу добавлять в массив и не обновлять хлебные крошки вручную.

Хорошо, вот фрагмент моего массива: (это не будет намного глубже)

$menu = array(
    'Dashboard' => array(
        'Projects' => array(
            'Project 1' => array(
                'Project settings' => 'projects/project_1/settings',
                'Issue Tracker' => 'projects/project_1/issue_tracker',
                'Customize page' => 'projects/project_1',
                'Manage files' => 'projects/project_1/files',
            ),
            'Project 2' => array(
                'Project settings' => 'projects/project_2/settings',
                'Issue Tracker' => 'projects/project_2/issue_tracker',
                'Customize page' => 'projects/project_2',
                'Manage files' => 'projects/project_2/files',
            ),
        ),
        'Logout' => '#',
    )
);

Я хотел бы иметь возможность вернуть всех родителей любого ключа таким образом, чтобы я мог повторить его позже. Например, для «Настройки проекта»:

'Dashboard','Projects','Project 1'.

person thisispiers    schedule 24.12.2012    source источник
comment
Все, что я могу сказать прямо сейчас, это то, что об этом уже спрашивали и отвечали на сайте. Дай-ка я посмотрю, смогу ли я достать его из архива для тебя.   -  person hakre    schedule 24.12.2012
comment
Разве Получение данных из одностороннего массива в обратном порядке не удовлетворит ваши потребности?   -  person hakre    schedule 24.12.2012
comment
Быстро посмотрел. Это любезно, но разве это не просто переворачивание массива? Как бы я изолировал родителей ключа, который я ищу?   -  person thisispiers    schedule 24.12.2012


Ответы (1)


В вашем примере на самом деле возможны два пути:

Key 'Project settings' found: 'Projects' -> 'Project 1'
Key 'Project settings' found: 'Projects' -> 'Project 2'

Вы можете легко решить эту проблему с помощью рекурсивного итератора (см. RecursiveIteratorIterator, он предлагает все, что вам нужно). Я выбрал его, потому что он упрощает поиск и получение ключей родительских уровней:

$search = 'Project settings';
$it     = new ParentKeysIterator($menu);
foreach ($it as $key) {
    if ($key !== $search) continue;
    printf("Key '%s' found: '%s'\n", $key, implode("' -> '", $it->key()));
}

И ParentKeysIterator:

class ParentKeysIterator extends RecursiveIteratorIterator
{
    public function __construct(array $array) {
        parent::__construct(new  RecursiveArrayIterator($array));
    }

    public function current() {
        return parent::key();
    }

    public function key() {
        return $this->getParentKeys();
    }


    public function getParentKeys() {
        $keys = [];
        for ($depth = $this->getDepth() - 1; $depth; $depth--) {
            array_unshift($keys, $this->getSubIterator($depth)->key());
        }
        return $keys;
    }
}
person hakre    schedule 24.12.2012
comment
Вау, спасибо. Это выглядит довольно хорошо. Вы уверены, что это невозможно без внешнего класса? Я не сторонник полагаться на целые классы только для одной или двух функций - это кажется раздутым... - person thisispiers; 24.12.2012
comment
Эти классы встроены в PHP. И третий класс вы пишете сами, так что это не внешний. Если вы хотите этого для некоторых функций, проверьте другой вопрос, который я связал. И затем вам нужно закодировать всю логику, которая уже есть в RecursiveIteratorIterator вашей собственной, что было бы новым изобретением колеса, чего вы обычно не хотите делать. - person hakre; 24.12.2012
comment
Я внес одну поправку: цикл for должен быть for ($depth = $this->getDepth(); $depth>=0; $depth--), чтобы он мог правильно вернуть ключ, найденный на самом верхнем уровне (в данном примере на панели инструментов). - person nshew13; 10.05.2013
comment
@ N13: Для самого верхнего ключа вам не нужен цикл, он всегда: $this->getSubIterator($depth = 0)->key(); (переменная там только для обозначения значения). - person hakre; 10.05.2013
comment
@hakre: В этом примере да. Однако это не сработало для моей структуры данных, поэтому я хотел поделиться более широким решением. Пока вы здесь, знаете ли вы, как использовать возвращаемый массив $keys для извлечения значений из $menu? - person nshew13; 10.05.2013
comment
Если $menu является рекурсивным итераторитератором, вам нужно создать фильтр для этого или, чтобы преобразовать все в массив и получить к нему доступ. Это в основном два варианта, которые я вижу. Второй, вероятно, проще написать, решение для массива уже дано для этих двух частей: а) преобразование в многомерный массив и б) доступ к такому массиву по пути ключей. - Для другого варианта я мог бы написать пример в IteratorGarden, но я не знаю, когда. Надеюсь, скоро, но до тех пор пример не дан (я знаю об этом далеко не понаслышке). - person hakre; 10.05.2013