Я пытаюсь создать древовидную структуру из таблицы в базе данных. Таблица сохраняется в памяти, причем каждая запись имеет родительский_ид или 0. Конечной целью является создание сгенерированного окна выбора и массив узлов.
Код, который у меня есть до сих пор:
function init($table, $parent_id = 0) { $sql = "SELECT id, {$this->parent_id_field}, {$this->name_field} FROM $table WHERE {$this->parent_id_field}=$parent_id ORDER BY display_order"; $result = mysql_query($sql); $this->get_tree($result, 0); print_r($this->nodes); print_r($this->select); exit; } function get_tree($query, $depth = 0, $parent_obj = null) { while($row = mysql_fetch_object($query)) { /* Get node */ $this->nodes[$row->parent_category_id][$row->id] = $row; /* Get select item */ $text = ""; if($row->parent_category_id != 0) { $text .= " "; } $text .= "$row->name"; $this->select[$row->id] = $text; echo "$depth $text\n"; $sql = "SELECT id, parent_category_id, name FROM product_categories WHERE parent_category_id=".$row->id." ORDER BY display_order"; $nextQuery = mysql_query($sql); $rows = mysql_num_rows($nextQuery); if($rows > 0) { $this->get_tree($nextQuery, ++$depth, $row); } } }
Он почти работает, но не совсем. Может кто-нибудь помочь мне закончить его?
Я думаю, что здесь эта линия:
if($row->parent_category_id != 0) { $text .= " "; }
должно быть:
while ($depth-- > 0) { $text .= " "; }
Вы отступаете только один раз, а не столько раз, сколько должно быть отступом.
И эта строка:
$this->get_tree($nextQuery, ++$depth, $row);
должно быть:
$this->get_tree($nextQuery, $depth + 1, $row);
Обратите внимание, что вам, вероятно, следует следовать рекомендациям в другом ответе, и сразу же возьмите всю таблицу, а затем обработайте ее сразу, потому что в целом вы хотите минимизировать круглые поездки в базу данных (есть несколько случаев, когда то, как вы это делаете, более оптимально, например, если у вас очень большое дерево и выбирая небольшую часть, но я сомневаюсь, что это так)
Вы почти наверняка не должны продолжать свой текущий путь. Рекурсивный метод, который вы пытаетесь использовать, почти наверняка убьет вашу производительность, если ваше дерево когда-нибудь станет немного больше. Вероятно, вы должны смотреть на вложенную структуру набора вместо списка смежности, если вы планируете часто читать дерево.
С помощью вложенного набора вы можете легко получить все дерево, вложенное должным образом с помощью одного запроса.
Пожалуйста, ознакомьтесь с этими вопросами для обсуждения деревьев.
Можно ли запросить таблицу древовидной структуры в MySQL в одном запросе на любую глубину?
Реализация иерархической структуры данных в базе данных
Каков наиболее эффективный / элегантный способ разбора плоского стола в дерево?
$this->nodes[$row->parent_category_id][$row->id] = $row;
Эта строка уничтожает ваш ORDER BY display_order. Измените его на
$this->nodes[$row->parent_category_id][] = $row;
Моя следующая проблема – это часть $ row-> parent_category_id. Разве это не должно быть $ row-> parent_id?
EDIT: О, я не читал ваш источник достаточно близко. Избавиться от предложения WHERE. Прочитайте всю таблицу сразу. Вам нужно отправить процесс обработки дерева во второй раз. Сначала вы читаете базу данных в список массивов. Затем вы обрабатываете массив рекурсивно, чтобы выполнить свой вывод.
Ваш массив должен выглядеть так:
Array(0 => Array(1 => $obj, 5 => $obj), 1 => Array(2 => $obj), 2 => Array(3 => $obj, 4 => $obj), 5 => Array(6 => $obj) ); function display_tree() { // all the stuff above output_tree($this->nodes[0], 0); // pass all the parent_id = 0 arrays. } function output_tree($nodes, $depth = 0) { foreach($nodes as $k => $v) { echo str_repeat(' ', $depth*2) . $v->print_me(); // print my sub trees output_tree($this->nodes[$k], $depth + 1); } } output: object 1 object 2 object 3 object 4 object 5 object 6