Можно ли построить свертываемый список в виде дерева, используя только PHP (без JS)
У меня есть две функции, которые вместе создают список дерева на моем сайте. Он основан на рекурсии и позволяет строить древовидную структуру с неограниченным количеством узлов.
Но я не могу сделать его разборным. Например: скрипт должен определить, $_GET['node'] == $node_id
или нет, и если это так, отобразить (развернуть) элемент блока и все его родители. Итак, мне нужно передать этот "отображающий" параметр сверху, в корень.
Дело в $display
а также $display2
вары.
- У меня есть классическая таблица БД с тремя столбцами (id, parent_id, name). У корневых узлов не заполнено поле parent_id.
- hrefs ссылки только на параметры GET. Параметр GET означает номер узла.
Мне просто нужна эта техника свертывания, основанная на том, какой узел я выбрал.
ОБНОВЛЕНИЕ: Хорошо, есть полная и очищенная информация. я создал файл php, работая с базой данных, содержащей только одну таблицу. просто для понимания вопроса:
1 Я использую формат базы данных sqlite3. это дамп БД:
# sqlite3 catalog.sqlite.dump PRAGMA foreign_keys = OFF; НАЧАЛО СДЕЛКИ; CREATE TABLE groups(идентификатор INTEGER PRIMARY KEY NOT NULL, имя TEXT, parent_id INTEGER); INSERT INTO "groups" VALUES(1,'root1',''); INSERT INTO "groups" VALUES(2,'root2',''); INSERT INTO "groups" VALUES(3,'root3',''); INSERT INTO "groups" VALUES(4,'root4',''); INSERT INTO "groups" VALUES(5,'sub1',1); ВСТАВЬТЕ В ЗНАЧЕНИЯ "групп" (6,'sub3',3); INSERT INTO "groups" VALUES(7,'subub1',5); INSERT INTO "groups" VALUES(8,'sububsub1', 7); INSERT INTO "groups" VALUES (9, 'subb1', 1); COMMIT;
2 это файл PHP, имеющий дело с базой данных.
<?php
$db = new SQLite3('catalog.sqlite');
function build_catalog($db){ //build roots and diggs for childnodes for every root in a loop
//$content_root="<ul id='collapsedlist'>";
$content_root = '';
$roots = $db->query('SELECT * from groups WHERE parent_id="" OR parent_id is null');
while($root = $roots->fetchArray()){
list ($content,$display)=get_children_of_node($db,$root['id']);
$content_root .= "<li id='".$root['id']."' ><a href='/?node=".$root['id']."'>".$root['name']."</a>";
$content_root .= $content;
$content_root .= "</li>\n";
}
$content_root = "<ul id='collapsedlist'>".$content_root."</ul>\n";
return $content_root;
}
function get_children_of_node($db,$node_id){
if(!isset($content)) $content = '';
$display = (isset($_GET['node']) && $_GET['node'] == $node_id)? "style='display:block'" : "style='display:none'";
$query = $db->querySingle('SELECT count(*) from groups WHERE parent_id='.$node_id);
if ($query > 0){
//$content .= "<ul class='subcategories'>\n";
$children = $db->query('SELECT * from groups WHERE parent_id =\''.$node_id.'\'');
while ($child = $children->fetchArray()){
list($content2,$display)=get_children_of_node($db,$child['id']);
$content .= "<li id='".$child['id']."' ".$display.">";
$content .= "<a href='/?node=".$child['id']."'>".$child['name']."</a>";
$content .= $content2;
$content .= "</li>\n";
}
$content = "<ul class='subcategories' ".$display.">".$content."</ul>\n";
}
return array($content,$display);
}
?>
Здесь файл php заканчивается чистым HTML-толчком выше. я разделил его здесь один на другой, поэтому редактор не может сразу разобрать синтаксис HTML+PHP. но это тот же файл index.php. HTML часть:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Collapsible Nested List</title>
</head>
<body>
<div id="sidebar">
<?=build_catalog($db);?>
</div>
</body>
</html>
1 ответ
Вот быстрое решение вашей проблемы, сохраняя тот же HTML, просто замените ваш PHP следующим кодом.
function get_children($db, $parent_id) {
$res = $db->query("SELECT * FROM groups WHERE parent_id='$parent_id'");
if (!$res) return array();
$out = array();
while ($row = $res->fetchArray(SQLITE3_ASSOC)) $out[$row['id']] = $row;
return $out;
}
function get_parent_id($db, $node_id) {
return $db->querySingle("SELECT parent_id FROM groups WHERE id='$node_id'");
}
function get_menu($db, $node_id) {
$menu = get_children($db, $node_id);
while (($parent_id = get_parent_id($db, $node_id)) !== null) {
$temp = get_children($db, $parent_id);
$temp[$node_id]['children'] = $menu;
$menu = $temp;
$node_id = $parent_id;
}
return $menu;
}
function build_html(array $menu) {
$str = '';
foreach ($menu as $id => $item) {
$str .= sprintf('<li><a href="?node=%s">%s</a></li>', $id, $item['name']);
if (isset($item['children']))
$str .= build_html($item['children']);
}
return "<ul>$str</ul>";
}
function build_catalog($db) {
$menu = get_menu($db, isset($_GET['node']) ? intval($_GET['node']) : '');
return build_html($menu);
}
Этот код может быть действительно оптимизирован, если ваша таблица "groups" довольно мала. Идея состоит в том, чтобы получить все записи в массиве $groups и построить индекс parent_id. Построение каталога было бы намного проще.