вопрос по nested sets

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
вопрос по nested sets

Имеется таблица nested sets с разделами сайта в БД mysql, она имеет вид:

id | cleft | cright | clevel
1 1 74 0
... ... ... ...
20 70 71 1
21 72 73 1

т.е. здесь указаны категории первого левла.
В таблице также имеется записи 1го и 2го левла с определенным числом разделов-потомков (до 4 уровня).

Есть вопрос, как сделать, чтобы в пределах одного уровня( допустим 1го или 2го) возможно было создавать тот порядок следования разделов, который мне необходим.

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

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
естественно умею, но вопрос как можно изменить порядок следования разделов.
 

SiMM

Новичок
Простой пример - меняем порядок следования разделов 20 и 21:
21 70 71 1
20 72 73 1
Для решения этой задачи тебе собственно и предложили удалить, к примеру, элемент 20, и вставить его затем за элементом 21.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Симм, вы меня не поняли... читайте то что я написал...
Я запросто могу поменять разделы местами и без удаления, но только если у них нету потомков.

Если же у раздела структура
1-главный
2---второй
3------второй-первый
4---третий
5------третий-первый
6------третий-второй

как сделать так, чтобы поменять местами третий и второй? Я просто не могу придумать алгоритма, видать туплю. =( Просто если меня их cleft и cright местами - получится не то что надо.
 

Tor

Новичок
запросто могу поменять разделы местами и без удаления, но только если у них нету потомков
специально для альтернативно одаренных повторяю
создаешь НОВЫЙ раздел там, где он тебе нужен, повторяя всю структору, всех потомков
старый потом удаляешь
 

crocodile2u

http://vbolshov.org.ru
И все же можно обойтись и безо всякого удаления, одними UPDATE'ами
 

Tor

Новичок
все же можно обойтись и безо всякого удаления, одними UPDATE'ами
а никто и не утверждал обратного
но есть легкие пути и есть остальные
право каждого - выбирать
 

crocodile2u

http://vbolshov.org.ru
Путь через UPDATE'ы - вовсе не такой уж и тяжелый. ИМХО, не тяжелее, чем DELETE+INSERT. Просто алгоритм не такой очевидный.
 

alexhemp

Новичок
c0dex

Посмотри реализацию dbTree от su1d

На этом форуме поищи, была большая ветка по этому вопросу.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
спасиб. уже реализовано через копирование ветки посредством insertNear и удалением того, что не нужно.
 

docker

Новичок
пример реализации

В рамках класса CDBTree создал дополнительные методы, реализующие это перемещение в пределах одного уровня
PHP:
// Стандартная инфа по родителям
    function GetParentInfo($child_id) {
        $res = $this->db->FetchRow($this->getParent($child_id));
        return $this->getNodeInfo($res['id']);
    }
    
    // получаем пару узлов, которые нужно поменять местами
    function GetReplacePairNodes($tid, $order) {
        list($originLeft, $originRight, $originLevel) = $this->getNodeInfo($tid);
        list($parentLeft, $parentRight, $parentLevel) = $this->getParentInfo($tid);
        
        
        if ($order == 'down') {
            $res = $this->db->GetOne2Arr('SELECT `id` FROM `?#CAT_TREE_TABLE`
                                          WHERE `'.$this->level.'` = ? AND `'.$this->left.'` > ? AND `'.$this->left.'` > ? AND `'.$this->right.'` < ?
                                          ORDER BY `'.$this->left.'` LIMIT 1',
                                          $originLevel, $originLeft, $parentLeft, $parentRight);
            if (!$res) return false;
            $upper = $tid;
            $down  = $res['id'];
        } else {
            $res = $this->db->GetOne2Arr('SELECT `id` FROM `?#CAT_TREE_TABLE`
                                          WHERE `'.$this->level.'` = ? AND `'.$this->left.'` < ? AND `'.$this->left.'` > ? AND `'.$this->right.'` < ?
                                          ORDER BY `'.$this->left.'` DESC LIMIT 1',
                                          $originLevel, $originLeft, $parentLeft, $parentRight);
            if (!$res) return false;
            $upper = $res['id'];
            $down  = $tid;
        }
        return array($upper, $down);
    }


    // Перемещение ветки в пределах одного уровня: смена порядка
    function ChangePartOrder($tid, $order) {
        if ($tid <= 1) return false;
        
        // Находим верхний и нижний, которые будем менять местами.
        // затем создаем под нижним временный узел, туда перемещаем ветку верхнего узла
        // и затем удаляем этот временный без удаления его детей.
        if (!($pair = $this->GetReplacePairNodes($tid, $order))) return false;
        
        
        $tmpId = $this->insertNear($pair[1]);
        $this->moveAll($pair[0], $tmpId);
        $this->delete($tmpId);
        return true;
    }
Вызывается просто:
PHP:
$ClassObj->ChangePartOrder($tid, 'down');
или
$ClassObj->ChangePartOrder($tid, 'up');
где $tid - id перемещаемой ветки

p.s. на функции выполнения sql запросов - не следует обращать внимание - там используется принцип плейсхолдеров Котерова(http://dklab.ru/lib/Database_Placeholder/) + некоторая дополнительная удобная обертка, главное - сам текст запросов.
 

kvf77

Red Devil
c0dex

в моей лиюе http://php.russofile.ru/ru/authors/sql/nestedsets01/ есть метод changePositionAll и MoveAll - первая позволяет переставить местами детей у одного родителя вместе со всеми их ветками, вторая вообще позволяет перемещать ветки по дереву практически в любое положение

P.S. мой метод именно перемещает разделы, он ничего не удаляет и не вставляет
 

Popoff

popoff.donetsk.ua
docker
сделай к этой функции описание (я понимаю, что в этом топике об этом написано, но приведи это к виду готовой документации), сделай какой-нибудь пример (со всеми иклюдами и примером исходных данных), который может запустить любой не разбирающийся в вопросе и посмотреть результат работы и давай разместим эту функцию в факе. если этого не сделать, то этот топик затеряется в этом форуме, как и море другой полезной информации.

-~{}~ 25.11.05 10:23:

kvf77
c0dex задавал свой вопрос три месяца назад :)

я не помню, чтобы я добавлял ссылку на твою библиотеку в факе. чтобы добавить ссылку, хорошо бы какую-нибудь краткую аннотацию: в чем основная особенность твоей библиотеки, какие возможности она добавляет в исходную? Сформулируй фразу, которую ты хотел бы расположить рядом со своей ссылкой.
 

docker

Новичок
Popoff да сделал все: описание, оформил.
Добавил все необходимые методы в дистрибутив phpDbTree-1.4.zip(который скачивается отсюда http://phpclub.ru/detail/article/db_tree) +изменил там пример(test.php), добавив демонстрацию перемещения.

Куда тебе выслать выслать архивчик?
 
Сверху