2

I'm trying to create dynamic breadcrumbs from an array. So I can add to the array and not have to manually update the breadcrumbs.

Okay, here's a snippet of my array: (It won't go much deeper)

$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' => '#',
    )
);

I would like to be able to return all the parents of any key in a way that I can iterate through later. For instance, for 'Project settings':

'Dashboard','Projects','Project 1'.
hakre
  • 193,403
  • 52
  • 435
  • 836
thisispiers
  • 109
  • 9
  • 1
    All I can say right now is that this has been asked and answered before on the site. Let me look if I can pull it up from the archives for you. – hakre Dec 24 '12 at 11:53
  • Wouldn't [Getting data from one way array in reverse order](http://stackoverflow.com/q/13007380/367456) suit your needs? – hakre Dec 24 '12 at 11:54
  • Had a quick look. It's kind there, but isn't that just reversing an array? How would I isolate the parents of the key I'm looking for? – thisispiers Dec 24 '12 at 12:30

1 Answers1

3

In your example there are actually two paths possible:

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

You can easily solve this with a recursive iterator (See RecursiveIteratorIterator it offers all you need). I chose it because it allows you to easier search and obtain the parent levels keys:

$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()));
}

And the 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;
    }
}
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Wow, thanks. That's looks pretty good. Are you sure it's not possible without an external class? I'm not a fan of relying on entire classes just for one or two functions - makes it seem bloated... – thisispiers Dec 24 '12 at 12:31
  • Those classes are built-in in PHP. And the third class you write your own so is not external. If you want that per some functions, check the other question I've linked. And then you need to code the whole logic that is already in `RecursiveIteratorIterator` your own which would be re-inventing the wheel, something you normally don't want to do. – hakre Dec 24 '12 at 15:59
  • I made one adjustment: the for loop should be `for ($depth = $this->getDepth(); $depth>=0; $depth--)` so that it can properly return a key found at the top-most level ("Dashboard", in this example). – nshew13 May 10 '13 at 17:54
  • @N13: For the topmost key you do not need the loop, it is always: `$this->getSubIterator($depth = 0)->key();` (variable in there only to name the value). – hakre May 10 '13 at 18:09
  • @hakre: In this example, yes. It didn't work for my data structure, though, so I wanted to share a broader solution. While you're here, do you know of a way to use the returned $keys array to retrieve the values from $menu? – nshew13 May 10 '13 at 18:29
  • If `$menu` is the recursiveiteratoriterator you need to create a filter for that *or* to convert the whole into an array and access it. That are basically the two options I see. The second one is probably more easy to write, the solution for an array has been answered already for those two parts: a) converting to multi-dimenstional array and b) accessing such an array by a "path" of keys. - For the other alternative I might write an example in the IteratorGarden but I dunno when. Hopefully soon but until then no example given (I know of so far from top of my head). – hakre May 10 '13 at 18:52