Генерируйте навигацию от многомерного массива

Вопрос: Как я генерирую навигацию, допуская применение различных классов к различным подэлементам, от многомерного массива?

Вот то, как я делал его, прежде чем у меня была любая потребность в многоуровневой навигации:

Home 
Pics 
About

и был сгенерирован путем называния военно-морским ():

function nav(){       
    $links = array(
        "Home" => "home.php",
        "Pics" => "pics.php",
        "About" => "about.php"
    );

    $base = basename($_SERVER['PHP_SELF']);

    foreach($nav as $k => $v){
        echo buildLinks($k, $v, $base);
    }
}

Вот buildLinks ():

function buildLinks($name, $page, $selected){
    if($selected == $page){
       $theLink = "<li class=\"selected\"><a href=\"$page\">$name</a></li>\n";
    } else {
       $thelink = "<li><a href=\"$page\">$name</a></li>\n";
    }

    return $thelink;
}

Мой вопрос, снова:

как был бы я достигать следующего военно-морского (и заметьте, что видимые sub элементы навигации только присутствуют когда на той определенной странице):

Home
    something1
    something2 
Pics 
About

и...

Home
Pics
    people
    places 
About

Что я попробовал

От рассмотрения его казалось бы, что некоторый итератор в SPL будет подходящим вариантом для этого, но я не уверен, как приблизиться к этому. Я играл вокруг с RecursiveIteratorIterator, но я не уверен, как применить другой стиль только к объектам подменю и также как только показать эти объекты, если Вы находитесь на корректной странице.

Я создал этот массив для тестирования с, но не знаю, как работать с submenu1 объектами индивидуально:

$nav = array(
array(
"Home" => "home.php",
"submenu1" => array(
    "something1"=>"something1.php",
    "something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);

Следующее распечатает партию в порядке, но как я применяю, говорю имя класса submenu1 объектам или только показываю им, когда человек идет, скажем, страница "Home"?

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($nav));

foreach($iterator as $key=>$value) {
    echo $key.' -- '.$value.'<br />';
}

И это получает меня:

Home
something1
something2
Pics
About

Но у меня нет способа применить классы к тем sub объектам и никакому способу только отобразить их условно, потому что я не вижу, как быть нацеленным просто на эти элементы.

7
задан Lothar 20 May 2010 в 20:55
поделиться

6 ответов

Вы были на правильном пути с RecursiveIteratorIterator. Это существенно сглаживает рекурсивный итератор. Вот правильный способ:

$nav = array(
    array(
    "Home" => "home.php",
    "submenu1" => array(
        "something1"=>"something1.php",
        "something2" => "something2.php")
    ),
    array("Pics" => "pics.php"),
    array("About" => "about.php"),
);

$it = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($nav),
    RecursiveIteratorIterator::SELF_FIRST
);

foreach ($it as $k => $v) {
    if ($it->getDepth() == 0)
        continue;
    echo str_repeat("    ", $it->getDepth() - 1) .
        "$k => $v\n";
}

дает

Home => home.php
submenu1 => Array
    something1 => something1.php
    something2 => something2.php
Pics => pics.php
About => about.php
1
ответ дан 7 December 2019 в 03:12
поделиться

Похоже, вы могли бы сделать это более объектно-ориентированным способом. В противном случае кажется, что вы должны хотя бы определить алгоритм, который имеет смысл, прямо сейчас вы просто слепо гадаете. Вместо этого DEFINE.

Например:

Я определяю свою навигацию как дерево на основе хэша php. Элемент навигации будет иметь следующее:

A) если есть ссылка верхнего уровня, хэш массива будет содержать элемент (подмассив) с меткой «лист навигации»

б) лист навигации будет содержать элементы с меткой « Отображаемое значение »,« значение ссылки »и« значение alt ». Эти элементы будут использоваться для создания тега привязки.

c) если у элемента есть подменю, помимо содержания «Листа навигации», будет присутствовать элемент «подменю». Элемент поднавигации будет иметь «Лист навигации», если у него есть отображаемый элемент навигации.

Затем вы можете написать функции / методы, которые будут отображать вашу навигацию на основе выбранного вами определения.

1
ответ дан 7 December 2019 в 03:12
поделиться

А как насчет перезаписи функции навигации следующим образом:

function nav($links, $level){       
    foreach($links as $k => $v) {
        if (is_array($v)) {
            nav($v, $level + 1)
        } else {
            echo buildLinks($k, $v, $base);
        }
    }
}

И затем вызвать ее:

$links = array(
array(
"Home" => "home.php",
"submenu1" => array(
    "something1"=>"something1.php",
    "something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);
nav($links, 0);
1
ответ дан 7 December 2019 в 03:12
поделиться

Что я бы сделал, так это что-то в этом роде:

class MenuItem {
    protected $active = false;
    protected $children = array();
    protected $name = '';
    protected $link = '';

    public function __construct($name, $link, $active) {}

    public function __toString() {
        //render this item
        $out = ''; #render here
        if (!$this->isActive()) { 
            return $out;
        }
        $out .= '<ul>';
        foreach ($this->children as $child) {
            $out .= (string) $child;
        }
        $out .= '</ul>';
        return $out;
    }

    public function isActive() {
        if ($this->active) {
            return true;
        }
        foreach ($this->children as $child) {
            if ($child->isActive()) {
                return true;
            }
        }
        return false;
    }
 }

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

$rootItems = array($item1, $item2);
$out = '<ul>';
foreach ($rootItems as $item) {
    $out .= (string) $item;
}
$out .= '</ul>';

Я оставлю семантику построения объекта, добавления детей и т.д. пользователю...

1
ответ дан 7 December 2019 в 03:12
поделиться

ИМХО, самый простой способ - это просто сделать рекурсивный вызов и использовать древовидное описание вашей навигации (то есть вложенные массивы). Непроверенный пример кода:

<?php
$links = array(
    "Home" => array("home.php", array(
        "something1"=> array("something1.php", array()),
        "hello"=> array("hello.php", array(
            "world" => array("world.php", array()),
            "bar" => array("bar.php", array()),
        )),
    )),
    "Pics" => array("pics.php", array(
        "people"=>"people.php",
        "places" => "places.php",
    )),
    "About" => array("about.php", array()), // example no subitems
);

// use the following $path variable to indicate the current navigational position
$path = array(); // expand nothing
$path = array('Home'); // expand Home
$path = array('Home', 'hello'); // also expand hello in Home

// map indent levels to classes
$classes = array(
    'item',
    'subitem',
    'subsubitem',
);


// recursive function to build navigation list
function buildNav($links, $path, $classes)
{
    // selected page at current level
    // NOTE: array_shift returns NULL if $path is empty.
    // it also alters the array itself
    $selected = array_shift($path);
    $class = array_shift($classes);

    echo "<ul>\n";

    foreach($links as $name => $link)
    {
        list($href, $sublinks) = $link;
        if ($name == $selected)
        {
            echo "<li class=\"selected $class\"><a href=\"$href\">$name</a>\n";
            // recursively show subitems
            // NOTE: path starts now with the selected subitem
            buildNav($sublinks, $path, $classes);
            echo "</li>\n";
        }
        else
        {
            echo "<li><a href=\"$href\" class=\"$class\">$name</a></li>\n";
        }
    }

    echo "<ul>\n";
}

// actually build the navigation
buildNav($links, $path, $classes);
?>
1
ответ дан 7 December 2019 в 03:12
поделиться

Не изобретайте велосипед, используйте Zend_Navigation , и вы будете счастливы.

3
ответ дан 7 December 2019 в 03:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: