Запись была отнесена к рубрике «Zend Framework» 01.03.2008, Сб в 09:45. Вы можете следить за общением по теме этой записи с помощью RSS 2.0 ленты. Вы можете оставить отзыв, или trackback с Вашего сайта.
Хранение деревьев в базе — вопрос если не самый популярный, то частовозникающий.
В свое время на phpclub.ru была опубликована статья с неплохим описанием модели, структурой таблиц и примерами. Также Максимом Матюхиным был приведен класс для работы с этой моделью. После возникшей потребности этот класс был переписан под Zend Framework. При «портировании» я просто заставил код немного по другому звучать и добавил некоторую функциональность из PEAR::DB_NestedSet.
Для работы с любыми классами производными от ZF-классов обычно рядом с директорией Zend, содержащей фреймворк, создается директория Application с аналогичной ZF иерархией — в этом случае Zend_Loader сможет подгрузить их в обычном порядке. Этим и обусловлено название класса — Application_Db_Table_Nestedset.
Код документирован и не является чем-то новым поэтому развернутый мануал по использованию приводить бессмыслено.
Доступ через хранилище или архивом.
К слову о лесе или множестве деревьев в одной таблице. Можно хранить таковые, если добавить в каждый кортеж еще один атрибут — id корневого узла root_id, а все выборки и обновления снабдить добавочным условием AND root_id = someRootIdValue, выполняющего роль фильтра. Т.о. будут произведены действия только над некоторым нужным деревом. На мой взгляд неплохим примером может быть организация комментариев к некоторому объекту.
NestedSet хм — спорная вещь
Как и многие другие, не так ли? По поводу Вашего коммента решил перелопатить ДКлаб, там как-то было достойное обсуждение по поводу деревьев, и наткнулся на , которая еще в далеком 2005ом позволяла свести спорные моменты метода к минимуму. Все довольно лаконично и четко.
Не знаю почему, но метод 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
и ещё... не кажется ли вам, что так будет удобнее записывать запросы?
было:
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 ничего личного :), кто как хочет ...
Такое дерево легко сломать, Вы уверены, что у Вас индексы в порядке? Если уверены, можно дампик поглядеть, интересно?
Спасибо, за класс. Правда ручками походу надо будет ещё поработать.
Спасибо за класс!
Ох и тяжело добывать его из репозитория в ситуации когда с DNS непорядок :)
Это не работает так как вы хотите если не указывать дополнительный ордер.
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) не имеет смысла, вываливается ошибка.
Это промах. Угу. Спасибо.
Даже понятно почему: 26 вызовов getChildren () и ни одного без параметра сортировки. Впрочем, исправлено до возможности ничего не сортировать. Еще раз спасибо.