Последние несколько часов я пытался найти решение этого вопроса в Интернете. Я нашел множество примеров того, как преобразовать из вложенного множества в смежность ... но немногие из них идут наоборот. Примеры, которые я нашел, либо не работают, либо используют процедуры MySQL. К сожалению, я не могу использовать процедуры для этого проекта. Мне нужно чистое решение PHP.
У меня есть таблица, которая использует модель смежности ниже:
id parent_id category
1 0 Books
2 0 CD's
3 0 Magazines
4 1 Books/Hardcover
5 1 Books/Large Format
6 3 Magazines/Vintage
И я хотел бы преобразовать его в таблицу вложенных наборов ниже:
id left right category
0 1 14 Root Node
1 2 7 Books
4 3 4 Books/Hardcover
5 5 6 Books/Large Format
2 8 9 CD's
3 10 13 Magazines
6 11 12 Magazines/Vintage
Вот изображение того, что мне нужно:
У меня есть функция, основанная на псевдокоде из этого сообщения на форуме (http://www.sitepoint.com/forums/showthread.php?t=320444), но она не работает. Я получаю несколько строк с одинаковым значением left. Этого не должно быть.
<code><?php
/**
--
-- Table structure for table `adjacent_table`
--
CREATE TABLE IF NOT EXISTS `adjacent_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`father_id` int(11) DEFAULT NULL,
`category` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
--
-- Dumping data for table `adjacent_table`
--
INSERT INTO `adjacent_table` (`id`, `father_id`, `category`) VALUES
(1, 0, 'ROOT'),
(2, 1, 'Books'),
(3, 1, 'CD''s'),
(4, 1, 'Magazines'),
(5, 2, 'Hard Cover'),
(6, 2, 'Large Format'),
(7, 4, 'Vintage');
--
-- Table structure for table `nested_table`
--
CREATE TABLE IF NOT EXISTS `nested_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`lft` int(11) DEFAULT NULL,
`rgt` int(11) DEFAULT NULL,
`category` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
*/
mysql_connect('localhost','USER','PASSWORD') or die(mysql_error());
mysql_select_db('DATABASE') or die(mysql_error());
adjacent_to_nested(0);
/**
* adjacent_to_nested
*
* Reads a "adjacent model" table and converts it to a "Nested Set" table.
* @param integer $i_id Should be the id of the "root node" in the adjacent table;
* @param integer $i_left Should only be used on recursive calls. Holds the current value for lft
*/
function adjacent_to_nested($i_id, $i_left = 0)
{
// the right value of this node is the left value + 1
$i_right = $i_left + 1;
// get all children of this node
$a_children = get_source_children($i_id);
foreach ($a_children as $a)
{
// recursive execution of this function for each child of this node
// $i_right is the current right value, which is incremented by the
// import_from_dc_link_category method
$i_right = adjacent_to_nested($a['id'], $i_right);
// insert stuff into the our new "Nested Sets" table
$s_query = "
INSERT INTO `nested_table` (`id`, `lft`, `rgt`, `category`)
VALUES(
NULL,
'".$i_left."',
'".$i_right."',
'".mysql_real_escape_string($a['category'])."'
)
";
if (!mysql_query($s_query))
{
echo "<pre>$s_query
\ п ";
бросить новое исключение (mysql_error ());
}
echo "
$ s_query
\ n";
// получаем новый идентификатор строки
$ i_new_nested_id = mysql_insert_id ();
}
вернуть $ i_right + 1;
}
/ **
* get_source_children
*
* Исследует "соседнюю" таблицу и находит всех непосредственных потомков узла
* @param integer $ i_id Уникальный идентификатор узла в таблице смежных таблиц
* @return array Возвращает массив результатов или пустой массив, если результатов нет.
* /
функция get_source_children ($ i_id)
{
$ a_return = array ();
$ s_query = "SELECT * FROM` adj_table` WHERE `Father_id` = '". $ i_id. "'";
if (! $ i_result = mysql_query ($ s_query))
{
echo "
$s_query
\ n";
бросить новое исключение (mysql_error ());
}
if (mysql_num_rows ($ i_result)> 0)
{
while ($ a = mysql_fetch_assoc ($ i_result))
{
$ a_return [] = $ a;
}
}
вернуть $ a_return;
}
?>
Это вывод вышеуказанного скрипта.
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, '2', '5', 'Hard Cover')
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, «2», «7», «Большой формат»)
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, «1», «8», «Книги»)
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, '1', '10', 'CD \' s ')
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, '10', '13', 'Vintage')
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, «1», «14», «Журналы»)
INSERT INTO nested_table
(id
,
lft
, rgt
, category
) ЗНАЧЕНИЯ (
NULL, '0', '15', 'ROOT')
Как видите, есть несколько строк, разделяющих значение lft в «1», то же самое относится и к «2». Во вложенном множестве значения для left и right должны быть уникальными. Вот пример того, как вручную нумеровать левый и правый идентификаторы во вложенном наборе:
Изображение предоставлено: Gijs Van Tulder, ссылка статья