построение навигации с вложенными наборами, начиная с выбранного узла - PullRequest
2 голосов
/ 07 апреля 2010

У меня есть следующая древовидная структура, использующая вложенные множества со значениями lft & rgt.

node
    node
        node
    node
        node (selected)
        node
node
node
    node

Я бы хотел построить навигацию так, чтобы дерево расширялось только до пути выбранного узла, а нерелевантные узлы были свернуты / скрыты.

Используя вышеуказанный метод, дерево будет выведено следующим образом:

node
    node
    node
        node (selected)
        node
node
node

возможно ли это с помощью php / mysql? Если какой-нибудь гуру SQL может помочь в создании запроса, я был бы очень благодарен .?

Я не против, если мне понадобится дополнительный запрос на уровень, вероятно, он будет иметь глубину не более 4 или 5 уровней ...

Обзор таблицы узлов:

--
-- Table structure for table `exp_node_tree_1`
--

CREATE TABLE `exp_node_tree_1` (
  `node_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `lft` mediumint(8) unsigned DEFAULT NULL,
  `rgt` mediumint(8) unsigned DEFAULT NULL,
  `moved` tinyint(1) NOT NULL,
  `label` varchar(255) DEFAULT NULL,
  `entry_id` int(10) DEFAULT NULL,
  `template_path` varchar(255) DEFAULT NULL,
  `custom_url` varchar(250) DEFAULT NULL,
  `extra` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`node_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=18 ;

--
-- Dumping data for table `exp_node_tree_1`
--

INSERT INTO `exp_node_tree_1` VALUES(1, 1, 12, 0, 'Home', 1, '0', '/', '');
INSERT INTO `exp_node_tree_1` VALUES(5, 10, 11, 0, 'About Us', 2, '4', '', '');
INSERT INTO `exp_node_tree_1` VALUES(6, 6, 9, 0, 'Team', 3, '5', '', '');
INSERT INTO `exp_node_tree_1` VALUES(7, 3, 4, 0, 'Contact Us', 4, '4', '', '');
INSERT INTO `exp_node_tree_1` VALUES(8, 7, 8, 0, 'Awards', 5, '5', '', '');
INSERT INTO `exp_node_tree_1` VALUES(10, 2, 5, 0, 'New Page', 6, '4', '', '');

Спасибо!

1 Ответ

0 голосов
/ 28 ноября 2010

Ваш пример данных усложняет задачу, учитывая, что у вас нет узлов-братьев, которые не являются прямыми дочерними элементами корневого узла, но я поработаю с тем, что там есть:)

Я думаю, вам понадобятся два вызова SQL - один для захвата всех узлов, которые содержат левые / правые значения выбранного вами узла, и один для использования «родительских» левых / правых значений из предыдущего вызова захватить братьев и сестер выбранного вами узла

например. Захватите все узлы, которые содержат левые / правые значения вашего целевого узла

SELECT e.* FROM exp_node_tree_1 as e, (SELECT lft, rgt FROM exp_node_tree_1 WHERE node_id = ?) AS tbl WHERE (e.lft < tbl.lft) and (e.rgt > tbl.rgt) ORDER BY e.lft ASC

Заменить? с ID_узла выбранного узла. Это возвращает всех предков выбранного вами узла, начиная с верхнего уровня и вплоть до прямого родителя выбранного вами узла

Второй запрос (братья и сестры) можно выполнить двумя способами, в зависимости от того, хотите ли вы использовать уже возвращенные значения lft / rgt (например, получить значения из PHP), или хотите ли вы выполнять тяжелую работу в SQL. Выполнение этого в SQL означает, что запрос более сложный, но вам не нужны никакие данные, кроме идентификатора выбранного узла

Использование значений PHP от родителей выбранного узла (возвращается в предыдущем запросе)

SELECT * FROM `exp_node_tree_1` WHERE (lft > ?) AND (rgt < ?) ORDER BY lft ASC

заменить первый? с lft значением родительского, а второго? со значением rgt родителя

Второй метод использует только идентификатор_узла выбранного узла

select s.* FROM exp_node_tree_1 as s, (SELECT e.lft, e.rgt FROM exp_node_tree_1 as e, (SELECT lft, rgt FROM exp_node_tree_1 WHERE node_id = ?) AS tbl WHERE (e.lft < tbl.lft) and (e.rgt > tbl.rgt) ORDER BY e.lft DESC LIMIT 1) as parent WHERE (s.lft > parent.lft) AND (s.rgt < parent.rgt) ORDER BY s.lft ASC

Как я уже сказал - немного сложнее. Заменить ? с выбранным узлом node_id

Надеюсь, это поможет!

...