2012-04-23 1 views
4

У меня есть две функции, которые вместе создают список древовидных изображений на моем веб-сайте. Он основан на рекурсии и позволяет построить древовидную структуру с неограниченным количеством узлов.Возможно ли построить сборный древовидный список, используя только PHP (нет JS)

Но я не могу сделать его разборным. Например: сценарий должен определить, $_GET['node'] == $node_id или нет, и если это так, элемент блокировки (разворачивания) и все его родители. Итак, мне нужно передать этот параметр «отображения» сверху, в корень.

Дело в $display и $display2 vars.

  • У меня есть классическая таблица db с тремя столбцами (id, parent_id, name). Корневые узлы не имеют поля parent_id.
  • ссылки hrefs только для параметров GET. Параметр GET означает номер узла.

Мне просто нужна эта сворачивающаяся техника, основанная на том, какой узел был выбран.

ОБНОВЛЕНИЕ: Хорошо, есть полная и очищенная информация. Я создал php-файл, работающий с базой данных, содержащий только одну таблицу. только для понимания проблемы:

1 Я использую формат базы данных sqlite3. это дамп БД:

 

     # sqlite3 catalog.sqlite .dump 
    PRAGMA foreign_keys=OFF; 
    BEGIN TRANSACTION; 
    CREATE TABLE groups(id INTEGER PRIMARY KEY NOT NULL, name 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); 
    INSERT INTO "groups" VALUES(6,'sub3',3); 
    INSERT INTO "groups" VALUES(7,'subsub1',5); 
    INSERT INTO "groups" VALUES(8,'subsubsub1',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> 
+0

Вы упомянули, что ваш родительский столбец называется 'parent_id', но использовал скрипт' parend_id'. Вы уверены, что это правильно? – halfer

+0

да, все в порядке. это была ошибка, когда я создал таблицу в БД. в любом случае это черновик. логика работает нормально, но мне нужно передать информацию об отображении или не отображать блок на верхние уровни, чтобы сделать его разворачивающимся динамически. теперь все узлы отображаются по умолчанию, поэтому у меня есть незапакованный список всех подкатегорий. – remort

+0

Я могу предоставить дополнительную информацию. структуру таблицы, скриншоты и так далее. скажите мне, если это необходимо, потому что я знаю, рекурсия - это трудная для понимания вещь)) – remort

ответ

3

Вот быстрое решение вашей проблемы, сохраняя тот же 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 и построить индекс parent_id. Тогда создание каталога было бы намного проще.

+0

ах, дерьмо! он работает просто отлично! большое спасибо, вы настоящий профессионал)) tomorow я углубись в ваш код более подробно ... Пожалуйста, скажите мне, что вы имели в виду, говоря о «оптимизировать логику, если» группы «маленькие»? эта таблица может быть огромной и содержать много детей, например, каталог интернет-магазина со многими категориями. – remort

+0

Хорошее усилие, +1. – halfer

+1

Идея состоит в том, чтобы свести к минимуму количество запросов, сделанных в базе данных. В этом примере и для узла глубины 3 код будет делать 2 * 4 запросов к базе данных, на каждом просмотре страницы и, IMHO, это плохо. Я вижу по крайней мере два способа оптимизации этого. 1) Создайте дерево с левыми, правыми и глубинными столбцами (например, поведение Doctrine Tree, сложный запрос и логика вставки). 2) Извлечь всю таблицу в массив (ест память). Категории для интернет-магазина не так «огромны». Допустим, у вас есть 100 категорий, это уже неплохой каталог ... – smrtl

 Смежные вопросы

  • Нет связанных вопросов^_^