Я пытаюсь получить все категории и подкатегории из базы данных MySQL в иерархии:
Мой результат должен быть таким (только пример):
- Cat A
- Sub-Cat 1
- Sub_Sub_Cat 1
- Sub_Sub_Cat 2
- Sub_Cat 2
- Cat B
- Cat C
- …
Код MySQL:
CREATE TABLE IF NOT EXISTS `categories` ( `category_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `parent_id` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'for sub-categories' PRIMARY KEY (`category_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
Просто, как можно получить это в hirarchy с PHP-кодами ?
При использовании модели списка смежности вы можете создать структуру за один проход.
Взято из структуры одного родительского дочернего массива (сентябрь 2007 г., Нейт Вайнер) :
$refs = array(); $list = array(); $sql = "SELECT item_id, parent_id, name FROM items ORDER BY name"; /** @var $pdo \PDO */ $result = $pdo->query($sql); foreach ($result as $row) { $ref = & $refs[$row['item_id']]; $ref['parent_id'] = $row['parent_id']; $ref['name'] = $row['name']; if ($row['parent_id'] == 0) { $list[$row['item_id']] = & $ref; } else { $refs[$row['parent_id']]['children'][$row['item_id']] = & $ref; } }
Из связанной статьи, вот фрагмент, чтобы создать список для вывода. Он рекурсивный, если есть дети для узла, он снова вызывает себя, чтобы создать поддерево.
function toUL(array $array) { $html = '<ul>' . PHP_EOL; foreach ($array as $value) { $html .= '<li>' . $value['name']; if (!empty($value['children'])) { $html .= toUL($value['children']); } $html .= '</li>' . PHP_EOL; } $html .= '</ul>' . PHP_EOL; return $html; }
Связанный вопрос:
У меня есть новая идея, я думаю, это будет хорошо. Идея такова: в столбце category_parent мы вставим ссылку на всех родителей этого узла.
+ ---- + ---------------------- + ----------------- + | id | category_name | иерархия | + ---- + ---------------------- + ----------------- + | 1 | cat1 | 1 | + ---- + ---------------------- + ----------------- + | 2 | cat2 | 2 | + ---- + ---------------------- + ----------------- + | 3 | cat3 | 3 | + ---- + ---------------------- + ----------------- + | 4 | subcat1_1 | 1-4 | + ---- + ---------------------- + ----------------- + | 5 | subcat1_2 | 1-5 | + ---- + ---------------------- + ----------------- + | 6 | subsubcat1_1 | 1-4-6 | + ---- + ---------------------- + ----------------- + | 7 | subsubcat1_2 | 1-4-7 | + ---- + ---------------------- + ----------------- + | 8 | subsubcat1_3 | 1-4-8 | + ---- + ---------------------- + ----------------- + | 9 | subsubcat1_3_1 | 1-4-8-9 | + ---- + ---------------------- + ----------------- + | 10 | subsubcat1_3_2 | 1-4-8-10 | + ---- + ---------------------- + ----------------- + | 11 | subsubcat1_3_1_1 | 1-4-8-9-11 | + ---- + ---------------------- + ----------------- + | 12 | subsubsubcat1_3_1_1 | 1-4-8-9-12 | + ---- + ---------------------- + ----------------- + | 13 | subsubsubcat1_3_1_2 | 1-4-8-9-11-13 | + ---- + ---------------------- + ----------------- + | 14 | subsubsubcat1_2_1_3 | 1-4-8-9-11-14 | + ---- + ---------------------- + ----------------- +
если вы посмотрите на мою обновленную таблицу, вы заметите, что в каждой записи есть ссылка на своих родителей, а не только на прямую, но и на всех родителей. И для этой работы я сделал некоторые изменения для вставки:
Insert into table_name (category_name, hierarchy) values ('new_name', (concat(parent_hierarch, '-', (SELECT Auto_increment FROM information_schema.tables WHERE table_name='table_name'))))
Теперь давайте сделаем желаемые запросы:
1- все подкатегории автомобилей:
select * from table_name where hierarchy like '1-%'
2- если вам нужен весь родитель BLACK, вы просто вводите:
select * from table_name where hierarchy = '1-4-8-9' or hierarchy = '1-4-8' or hierarchy = '1-4' or hierarchy = '1'
(вы можете построить этот запрос из php, разбивая поле иерархии на символе '-')
3- Чтобы увидеть все категории, с уровнем и прямым родителем:
select *, SUBSTR(hierarchy, 1, (LENGTH(hierarchy) - LENGTH(id) - 1)) as parent, LENGTH(hierarchy) - LENGTH(REPLACE(hierarchy, '-', '')) as level From table_name
+ ---- + ---------------------- + ----------------- + --- -------- + -------- + | id | название категории | иерархия | родитель | уровень | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 1 | cat1 | 1 | | 0 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 2 | cat2 | 2 | | 0 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 3 | cat3 | 3 | | 0 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 4 | subcat1_1 | 1-4 | 1 | 1 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 5 | subcat1_2 | 1-5 | 1 | 1 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 6 | subsubcat1_1 | 1-4-6 | 1-4 | 2 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 7 | subsubcat1_2 | 1-4-7 | 1-4 | 2 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 8 | subsubcat1_3 | 1-4-8 | 1-4 | 2 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 9 | subsubcat1_3_1 | 1-4-8-9 | 1-4-8 | 3 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 10 | subsubcat1_3_2 | 1-4-8-10 | 1-4-8 | 3 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 11 | subsubcat1_3_1_1 | 1-4-8-9-11 | 1-4-8-9 | 4 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 12 | subsubsubcat1_3_1_1 | 1-4-8-9-12 | 1-4-8-9 | 4 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 13 | subsubsubcat1_3_1_2 | 1-4-8-9-11-13 | 1-4-8-9-11 | 5 | + ---- + ---------------------- + ----------------- + --- -------- + -------- + | 14 | subsubsubcat1_2_1_3 | 1-4-8-9-11-14 | 1-4-8-9-11 | 5 | + ---- + ---------------------- + ----------------- + --- -------- + -------- +
Это новая идея и нуждается в улучшении.
@Amnon Ваш код работает отлично. Просто протестировал его с помощью CodeIgniter, и он работал как шарм. Вот рабочий код, если кому-то это нужно:
<?php function disTree($all_cats) { $tree = array(); foreach ($all_cats as $cat) { $pid = $cat->parent_id; $id = $cat->cat_id; $name = $cat->cat_name; // Create or add child information to the parent node if (isset($tree[$pid])) // a node for the parent exists // add another child id to this parent $tree[$pid]["children"][] = $id; else // create the first child to this parent $tree[$pid] = array("children"=>array($id)); // Create or add name information for current node if (isset($tree[$id])) // a node for the id exists: // set the name of current node $tree[$id]["name"] = $name; else // create the current node and give it a name $tree[$id] = array( "name"=>$name ); } return $tree; } function toUL($tree, $id, $html){ $html .= '<ul>'.PHP_EOL; if (isset($tree[$id]['name'])) $html .= '<li>' . $tree[$id]['name']; if (isset($tree[$id]['children'])) { $arChildren = &$tree[$id]['children']; $len = count($arChildren); for ($i=0; $i<$len; $i++) { $html .= toUL($tree, $arChildren[$i], ""); } $html .= '</li>'.PHP_EOL; } $html .= '</ul>'.PHP_EOL; return $html; } $tree = disTree($all_cats); // Display the tree echo toUL($tree, 0, ""); ?>
Единственное, что я изменил, это добавить мой собственный массив ($ all_cats).
Есть еще один способ добиться такого же эффекта, который я нахожу немного более легким (без контрольного трюка). Вы строите дерево, добавляя соответствующую информацию к текущему узлу и его родительскому объекту (предположим, что foreach выполняет итерацию по возвращенным строкам из SQL-запроса):
$tree = array(); foreach ($query->result() as $row) { $pid = $row->parent_id; $id = $row->id; $name = $row->name; // Create or add child information to the parent node if (isset($tree[$pid])) // a node for the parent exists // add another child id to this parent $tree[$pid]["children"][] = $id; else // create the first child to this parent $tree[$pid] = array("children"=>array($id)); // Create or add name information for current node if (isset($tree[$id])) // a node for the id exists: // set the name of current node $tree[$id]["name"] = $name; else // create the current node and give it a name $tree[$id] = array( "name"=>$name ); } return $tree;
и для отображения дерева:
function toUL($tree, $id, $html){ $html .= '<ul>'.PHP_EOL; if (isset($tree[$id]['name'])) $html .= '<li>' . $tree[$id]['name']; if (isset($tree[$id]['children'])) { $arChildren = &$tree[$id]['children']; $len = count($arChildren); for ($i=0; $i<$len; $i++) { $html .= toUL($tree, $arChildren[$i], ""); } $html .= '</li>'.PHP_EOL; } $html .= '</ul>'.PHP_EOL; return $html; } // Display the tree echo toUL($tree, 0, "");
Попробуйте следующий код
// подключаемся к mysql и выбираем db
$conn = mysqli_connect('localhost', 'user', 'password','database');
if( !empty($conn->connect_errno)) die("Error " . mysqli_error($conn)); //call the recursive function to print category listing category_tree(0); //Recursive php function function category_tree($catid){ global $conn; $sql = "select * from category where parent_id ='".$catid."'"; $result = $conn->query($sql); while($row = mysqli_fetch_object($result)): $i = 0; if ($i == 0) echo '<ul>'; echo '<li>' . $row->cat_name; category_tree($row->id); echo '</li>'; $i++; if ($i > 0) echo '</ul>'; endwhile; } //close the connection mysqli_close($conn); ?>
Больше…