Zend Framework: дерево вложенных множеств


Хранение деревьев в базе — вопрос если не самый популярный, то частовозникающий.

В свое время на phpclub.ru была опубликована статья с неплохим описанием модели, структурой таблиц и примерами. Также Максимом Матюхиным был приведен класс для работы с этой моделью. После возникшей потребности этот класс был переписан под Zend Framework. При «портировании» я просто заставил код немного по другому звучать и добавил некоторую функциональность из PEAR::DB_NestedSet.

Для работы с любыми классами производными от ZF-классов обычно рядом с директорией Zend, содержащей фреймворк, создается директория Application с аналогичной ZF иерархией — в этом случае Zend_Loader сможет подгрузить их в обычном порядке. Этим и обусловлено название класса — Application_Db_Table_Nestedset.

Код документирован и не является чем-то новым поэтому развернутый мануал по использованию приводить бессмыслено.

Доступ через хранилище или архивом.

11 комментариев на «Zend Framework: дерево вложенных множеств»

  1. wd,

    К слову о лесе или множестве деревьев в одной таблице. Можно хранить таковые, если добавить в каждый кортеж еще один атрибут — id корневого узла root_id, а все выборки и обновления снабдить добавочным условием AND root_id = someRootIdValue, выполняющего роль фильтра. Т.о. будут произведены действия только над некоторым нужным деревом. На мой взгляд неплохим примером может быть организация комментариев к некоторому объекту.

  2. ScareCrow,

    NestedSet хм — спорная вещь

  3. wd,

    Как и многие другие, не так ли? По поводу Вашего коммента решил перелопатить ДКлаб, там как-то было достойное обсуждение по поводу деревьев, и наткнулся на статью, которая еще в далеком 2005ом позволяла свести спорные моменты метода к минимуму. Все довольно лаконично и четко.

  4. nanoL,

    Не знаю почему, но метод getChildren у меня перестал работать корректно. создавая такой запрос :

    SELECT * FROM categories _categories, categories WHERE _categories.iCategoryID = 1 AND categories.`iCatLeft` BETWEEN _categories.`iCatLeft` AND _categories.`iCatRight` AND categories.`iCatLevel`=_categories.`iCatLevel` + 1 ORDER BY categories.`iCatLevel` , categories.`sName`

    он ничего не выдаёт.

    Только если вручную указать всё, работает :

    SELECT * FROM categories

    WHERE `iCatLeft` > 1

    AND `iCatRight`< 12

    AND `iCatLevel` = 2

  5. nanoL,

    и ещё... не кажется ли вам, что так будет удобнее записывать запросы?

    было:

    function getParent ($id, $level = 1) {

    if ($level getAdapter () ->fetchRow (

    'SELECT * FROM ' .

    $this->_name . ' _' . $this->_name . ', ' . $this->_name . ' ' .

    'WHERE _' . $this->_name . '.' . $this->_id . ' = ' . (int)$id . ' AND ' .

    '_' . $this->_name . '.' . $this->_left . ' BETWEEN ' . $this->_name . '.' . $this->_left . ' AND ' . $this->_name . '.' . $this->_right . ' AND ' .

    $this->_name . '.' . $this->_level . ' = _' . $this->_name . '.' . $this->_level . ' — ' . $level

    );

    }

    стало :

    function getParent ($id, $level = 1) {

    if ($level getAdapter () ->fetchRow («SELECT * FROM {$this->_name}

    WHERE _{$this->_name}.{$this->_id} = $id AND

    _{$this->_name}.{$this->_left} BETWEEN {$this->_name}.{$this->_left}

    AND {$this->_name}.{$this->_right} AND

    {$this->_name}.{$this->_level} = _{$this->_name}.{$this->_level} — $level» );

    }

    ps ничего личного :), кто как хочет ...

  6. wd,

    Такое дерево легко сломать, Вы уверены, что у Вас индексы в порядке? Если уверены, можно дампик поглядеть, интересно?

  7. illusive,

    Спасибо, за класс. Правда ручками походу надо будет ещё поработать.

  8. o4kapuk,

    Спасибо за класс!

    Ох и тяжело добывать его из репозитория в ситуации когда с DNS непорядок :)

  9. 2people,

    Это не работает так как вы хотите если не указывать дополнительный ордер.

    if (!is_array ($order)) $order = array ($order);

    foreach ($order as $val)

    $orderSql[] = $this->_name . '.' . $this->getAdapter () ->quoteIdentifier ($val);

    После первой строки получается $order === array (0=>NULL), при этом форич выполняется один раз.

    $orderSql === array (0=>'tablename.').

    Угу.

    Тогда вот эта хренотень !empty ($orderSql) не имеет смысла, вываливается ошибка.

  10. wd,

    Это промах. Угу. Спасибо.

  11. wd,

    Даже понятно почему: 26 вызовов getChildren () и ни одного без параметра сортировки. Впрочем, исправлено до возможности ничего не сортировать. Еще раз спасибо.

Оставить отзыв

 

Март 2008
Пн Вт Ср Чт Пт Сб Вс
« Фев   Апр »
 12
3456789
10111213141516
17181920212223
24252627282930
31