Web lists-archives.com

Re: [PHP] Nested Menu




Hi,

Something like this looks more elegant to me

<?php

$menuItems = array(
    array('id'=>1, 'title'=>'One', 'parent_id'=>0),
    array('id'=>2, 'title'=>'two', 'parent_id'=>0),
    array('id'=>3, 'title'=>'three', 'parent_id'=>0),
    array('id'=>4, 'title'=>'two.1', 'parent_id'=>2),
    array('id'=>5, 'title'=>'two.2', 'parent_id'=>2),
    array('id'=>6, 'title'=>'two.1.1', 'parent_id'=>4),
    array('id'=>7, 'title'=>'two.1.2', 'parent_id'=>4),
    array('id'=>8, 'title'=>'two.1.3', 'parent_id'=>4),
    array('id'=>9, 'title'=>'two.1.3.1', 'parent_id'=>8),
    array('id'=>10, 'title'=>'two.1.3.2', 'parent_id'=>8),
    array('id'=>11, 'title'=>'two.1.3.2.1', 'parent_id'=>10),
    array('id'=>12, 'title'=>'two.1.3.2.2', 'parent_id'=>10),
    array('id'=>13, 'title'=>'two.1.3.2.3', 'parent_id'=>10),
);

class DomUnorderedListBuilder {

    private $items;
    private $processed;
    private $document;

    public function __construct(array $items)
    {
        $this->items = $items;
    }

    public function build()
    {
        $items = $this->items;
        $this->processed = array();
        $this->document = new DOMDocument('1.0', 'utf-8');

        $rootNode = $this->doBuild($items);
        $this->document->appendChild($rootNode);

        return $this->document;
    }

    private function getChildrenItemsOf($parent)
    {
        return array_filter($this->items, function(array $item) use
($parent) { return $item['parent_id'] === $parent; });
    }

    private function doBuild(array $unprocessedItems)
    {
        $rootNode = $this->document->createElement('ul');
        $this->processItems($unprocessedItems, $rootNode);

        return $rootNode;
    }

    private function processItems(array $unprocessedItems, DOMNode
$parentNode)
    {
        foreach ($unprocessedItems as $item) {
            if ($this->isProcessed($item['id'])) continue;
            $this->markProcessed($item['id']);

            $liNode = $this->document->createElement('li', $item['title']);
            $parentNode->appendChild($liNode);

            $children = $this->getChildrenItemsOf($item['id']);

            if (!empty($children)) {
                $ulNode = $this->document->createElement('ul');
                $this->processItems($children, $ulNode);
                $liNode->appendChild($ulNode);
            }
        }
    }

    private function isProcessed($id)
    {
        return isset($this->processed[$id]);
    }

    private function markProcessed($id)
    {
        $this->processed[$id] = true;
    }
}

$b = new DomUnorderedListBuilder($menuItems);
$document = $b->build();
$document->formatOutput = true;

echo $document->saveHTML(), PHP_EOL;

On Wed, Jan 6, 2016 at 8:47 AM, Kevin Waterson <kevin.waterson@xxxxxxxxx>
wrote:

> Trying to create a menu based on results from an adjacency list and DOM.
>
> I can get it work with some nasty hacks with loadHTML in the constructor
>  and str_replace in the toString functions.
> I was looking for something more elegant.
>
> http://pastie.org/10672688
>
> Thanks
> Kev
>