PHP: Дерево меню из объектов

Предлагаю необычный способ построения дерева меню из объектов любой степени вложенности, используя преимущества php5 и вызов методов цепочкой

В первую очередь опишем класс – представляющий собой 1 элемент меню:

class MenuItem {
public $name = '';
public $caption = '';
public $sub = array();
public static function factory($name, $caption) {
return new MenuItem($name, $caption);
}
public function __construct($name, $caption) {
$this->name = $name;
$this->caption = $caption;
}
public function & addSub(MenuItem &$item) {
$this->sub[] = $item;
return $this;
}
public function __toString($base_prefix = NULL) {
$txt = '';
$prefix = is_null($base_prefix) ? url::site() . 'moder' : $base_prefix;
if (!is_null($prefix)) $txt .= "

  • ";
    $txt .= "{$this->caption}\n";
    if (count($this->sub)) {
    $txt .= "

      ";
      foreach($this->sub as $s)
      $txt .= $s->__toString("{$prefix}{$this->name}/");
      $txt .= "

    \n";
    }
    if (!is_null($prefix)) $txt .= "

  • ";
    return $txt;
    }
    }

    Меню на объектахДумаю понятно, что вся фишка не в перегруженном методе __toString(который больше всего строк :D – это всего лишь view-часть), а в статическом методе factory который возвращает экземпляр объекта меню, и самое главное, в addSub – добавляющий подменю и возвращающий ссылку на этот же объект, в котором был добавлен элемент.

    Разумется, в __toString может быть всё что угодно, зависит от вашей фантазии. Создание разметки внутри (фактически) логики – это нарушение MVC, зато хорошо наглядно. Данную штуку я использовал вместе с фреймворком kohana, котороую имел глупость честь использовать в новом проекте.

    Пример кода “в одну строчку”, который строит меню на картинке:

    echo MenuItem::factory('', 'Начало')
    ->addSub(MenuItem::factory('torrents', 'Торренты')
    ->addSub(MenuItem::factory('index', 'Статистика'))
    ->addSub(MenuItem::factory('unchecked', 'Непроверенные'))
    ->addSub(MenuItem::factory('active', 'Активные'))
    ->addSub(MenuItem::factory('finished', 'Завершённые'))
    ->addSub(MenuItem::factory('monitor', 'Монитор')) )
    ->addSub(MenuItem::factory('users', 'Пользователи')
    ->addSub(MenuItem::factory('index', 'Статистика'))
    ->addSub(MenuItem::factory('unchecked', 'Непроверенные'))
    ->addSub(MenuItem::factory('recent', 'Новые'))
    ->addSub(MenuItem::factory('online', 'Online')) )
    ->addSub(MenuItem::factory('movies', 'Фильмы')
    ->addSub(MenuItem::factory('genres', 'Жанры'))
    ->addSub(MenuItem::factory('unchecked', 'Непровереные'))
    ->addSub(MenuItem::factory('manage', 'Управление')) );

    Думаю, этот подход можно вынести во многие вещи.


    Навеянно фреймворком kohana.
    Который поочерёдно вызывет то ненависть,
    то благодарность – странный он какой то.