Przekształcić serię relacji rodzic-dziecko w hierarchiczne drzewo?
Mam kilka par name-parentname, które chciałbym przekształcić w jak najmniej dziedzicznych struktur drzewa. Na przykład mogą to być pary:
Child : Parent
H : G
F : G
G : D
E : D
A : E
B : C
C : E
D : NULL
Które należy przekształcić w(a) drzewo (drzewa) dziedziczne:
D
├── E
│ ├── A
│ │ └── B
│ └── C
└── G
├── F
└── H
Końcowy wynik, który chcę, to zagnieżdżony zestaw elementów <ul>
, Z Każdym <li>
zawierającym imię dziecka.
Nie ma niespójności w parach (dziecko jest rodzicem własnym, rodzic jest dzieckiem dziecka itp.), więc prawdopodobnie można wykonać kilka optymalizacji.
Jak w PHP przejść z tablicy zawierającej pary child= > parent do zestawu zagnieżdżonych <ul>
s?
Mam wrażenie, że rekurencja jest zaangażowana, ale nie jestem wystarczająco przytomny, aby to przemyśleć.
8 answers
Wymaga to bardzo podstawowej funkcji rekurencyjnej, aby parować pary potomek / rodzic do struktury drzewa i innej funkcji rekurencyjnej, aby ją wydrukować. Wystarczy tylko jedna funkcja, ale tutaj są dwie dla jasności (funkcja łączona znajduje się na końcu tej odpowiedzi).
Najpierw zainicjalizuj tablicę par potomek / rodzic:
$tree = array(
'H' => 'G',
'F' => 'G',
'G' => 'D',
'E' => 'D',
'A' => 'E',
'B' => 'C',
'C' => 'E',
'D' => null
);
Następnie funkcja parsująca tablicę w hierarchiczną strukturę drzewa:
function parseTree($tree, $root = null) {
$return = array();
# Traverse the tree and search for direct children of the root
foreach($tree as $child => $parent) {
# A direct child is found
if($parent == $root) {
# Remove item from tree (we don't need to traverse this again)
unset($tree[$child]);
# Append the child into result array and parse its children
$return[] = array(
'name' => $child,
'children' => parseTree($tree, $child)
);
}
}
return empty($return) ? null : $return;
}
I funkcja, która przemierza to drzewo, aby wydrukować lista nieuporządkowana:
function printTree($tree) {
if(!is_null($tree) && count($tree) > 0) {
echo '<ul>';
foreach($tree as $node) {
echo '<li>'.$node['name'];
printTree($node['children']);
echo '</li>';
}
echo '</ul>';
}
}
I rzeczywiste użycie:
$result = parseTree($tree);
printTree($result);
Oto treść $result
:
Array(
[0] => Array(
[name] => D
[children] => Array(
[0] => Array(
[name] => G
[children] => Array(
[0] => Array(
[name] => H
[children] => NULL
)
[1] => Array(
[name] => F
[children] => NULL
)
)
)
[1] => Array(
[name] => E
[children] => Array(
[0] => Array(
[name] => A
[children] => NULL
)
[1] => Array(
[name] => C
[children] => Array(
[0] => Array(
[name] => B
[children] => NULL
)
)
)
)
)
)
)
)
Jeśli chcesz nieco większej wydajności, możesz połączyć te funkcje w jedną i zmniejszyć liczbę wykonanych iteracji:
function parseAndPrintTree($root, $tree) {
$return = array();
if(!is_null($tree) && count($tree) > 0) {
echo '<ul>';
foreach($tree as $child => $parent) {
if($parent == $root) {
unset($tree[$child]);
echo '<li>'.$child;
parseAndPrintTree($child, $tree);
echo '</li>';
}
}
echo '</ul>';
}
}
Zapiszesz tylko 8 iteracji na tak małym zbiorze danych, ale na większych zestawach może to coś zmienić.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-11 10:02:37
Yet Another Function To Make A Tree (no recursion involved, uses references instead):
$array = array('H' => 'G', 'F' => 'G', ..., 'D' => null);
function to_tree($array)
{
$flat = array();
$tree = array();
foreach ($array as $child => $parent) {
if (!isset($flat[$child])) {
$flat[$child] = array();
}
if (!empty($parent)) {
$flat[$parent][$child] =& $flat[$child];
} else {
$tree[$child] =& $flat[$child];
}
}
return $tree;
}
Zwraca tablicę hierarchiczną taką jak Ta:
Array(
[D] => Array(
[G] => Array(
[H] => Array()
[F] => Array()
)
...
)
)
, które można łatwo wydrukować jako listę HTML za pomocą funkcji rekurencyjnej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-26 19:34:28
Kolejny, bardziej uproszczony sposób przekształcania płaskiej struktury w $tree
w hierarchię. Do jej odsłonięcia potrzebna jest tylko jedna tymczasowa tablica:
// add children to parents
$flat = array(); # temporary array
foreach ($tree as $name => $parent)
{
$flat[$name]['name'] = $name; # self
if (NULL === $parent)
{
# no parent, is root element, assign it to $tree
$tree = &$flat[$name];
}
else
{
# has parent, add self as child
$flat[$parent]['children'][] = &$flat[$name];
}
}
unset($flat);
To wszystko za wprowadzenie hierarchii do wielowymiarowej tablicy:
Array
(
[children] => Array
(
[0] => Array
(
[children] => Array
(
[0] => Array
(
[name] => H
)
[1] => Array
(
[name] => F
)
)
[name] => G
)
[1] => Array
(
[name] => E
[children] => Array
(
[0] => Array
(
[name] => A
)
[1] => Array
(
[children] => Array
(
[0] => Array
(
[name] => B
)
)
[name] => C
)
)
)
)
[name] => D
)
Wyjście jest mniej trywialne, jeśli chcesz uniknąć rekurencji (może być obciążeniem przy dużych strukturach).
Zawsze chciałem rozwiązać "dylemat" UL / LI dla wyprowadzenia tablicy. Dylemat polega na tym, że każdy element nie wie, czy lub nie dzieci będą śledzić lub ile poprzedzających elementów należy zamknąć. W innej odpowiedzi rozwiązałem to używając RecursiveIteratorIterator
i szukając getDepth()
i innych meta-informacji, które moje własne pisane Iterator
dostarczyło: otrzymanie zagnieżdżonego modelu zestawu do <ul>
, ale ukrywanie "zamkniętych" podzbiorów. Odpowiedź pokazuje również, że z iteratorami jesteś dość elastyczny.
Jednak była to wstępnie posortowana lista, więc nie byłaby odpowiednia dla Twojego przykładu. Dodatkowo I zawsze chciałem to rozwiązać dla pewnego rodzaju standardowej struktury drzewa i elementów HTML <ul>
i <li>
.
Podstawowa koncepcja, którą wymyśliłem, jest następująca:
-
TreeNode
- abstrahuje każdy element w prosty typTreeNode
, który może dostarczyć jego wartość (np.Name
) i czy ma dzieci. -
TreeNodesIterator
- aRecursiveIterator
, który jest w stanie iterować nad zbiorem (tablicą) tychTreeNodes
. Jest to dość proste, ponieważ TypTreeNode
już wie, czy to ma dzieci i które. -
RecursiveListIterator
- ARecursiveIteratorIterator
, który ma wszystkie zdarzenia potrzebne, gdy rekurencyjnie iterację nad dowolnym rodzajemRecursiveIterator
:-
beginIteration
/endIteration
- początek i koniec listy głównej. -
beginElement
/endElement
- początek i koniec każdego elementu. -
beginChildren
/endChildren
- początek i koniec każdej listy dzieci. ToRecursiveListIterator
dostarcza tylko te zdarzenia w formie wywołań funkcji. listy dzieci, jak to jest typowe dla<ul><li>
List, są otwierane i zamykane wewnątrz to Element nadrzędny<li>
. Dlatego ZdarzenieendElement
jest wywoływane po zdarzeniu accordingendChildren
. Można to zmienić lub skonfigurować, aby rozszerzyć użycie tej klasy. Zdarzenia są dystrybuowane jako wywołania funkcji do obiektu dekoratora, aby zachować rzeczy osobno.
-
-
ListDecorator
- Klasa "dekoratora", która jest tylko odbiorcą wydarzeńRecursiveListIterator
.
Zaczynam od logiki wyjścia głównego. Wzięto teraz hierarchiczną tablicę $tree
, końcowy kod wygląda tak:
$root = new TreeNode($tree);
$it = new TreeNodesIterator(array($root));
$rit = new RecursiveListIterator($it);
$decor = new ListDecorator($rit);
$rit->addDecorator($decor);
foreach($rit as $item)
{
$inset = $decor->inset(1);
printf("%s%s\n", $inset, $item->getName());
}
Najpierw przyjrzyjmy się ListDecorator
, który po prostu zawija elementy <ul>
i <li>
i decyduje o tym, jak struktura listy jest wyjściowa:
class ListDecorator
{
private $iterator;
public function __construct(RecursiveListIterator $iterator)
{
$this->iterator = $iterator;
}
public function inset($add = 0)
{
return str_repeat(' ', $this->iterator->getDepth()*2+$add);
}
Konstruktor pobiera iterator listy, nad którym pracuje. inset
jest tylko funkcją pomocniczą do ładnego wcięcia wyjścia. Reszta to tylko funkcje wyjściowe dla każdego zdarzenia:
public function beginElement()
{
printf("%s<li>\n", $this->inset());
}
public function endElement()
{
printf("%s</li>\n", $this->inset());
}
public function beginChildren()
{
printf("%s<ul>\n", $this->inset(-1));
}
public function endChildren()
{
printf("%s</ul>\n", $this->inset(-1));
}
public function beginIteration()
{
printf("%s<ul>\n", $this->inset());
}
public function endIteration()
{
printf("%s</ul>\n", $this->inset());
}
}
Mając na uwadze te funkcje wyjściowe, to jest główne wyjście zawijania / pętli ponownie, idę przez to krok po kroku:
$root = new TreeNode($tree);
Utwórz root TreeNode
, który będzie używany do rozpoczęcia iteracji po:
$it = new TreeNodesIterator(array($root));
Ten TreeNodesIterator
jest RecursiveIterator
, który umożliwia rekurencyjną iterację nad pojedynczym węzłem $root
. Jest przekazywana jako tablica, ponieważ ta klasa potrzebuje czegoś do iteracji i pozwala na ponowne użycie z zestawem dzieci, który jest również tablicą elementów TreeNode
.
$rit = new RecursiveListIterator($it);
Ten RecursiveListIterator
jest RecursiveIteratorIterator
, który dostarcza wspomnianych zdarzeń. Aby z niego skorzystać, tylko ListDecorator
musi być podane (Klasa powyżej) i przypisane z addDecorator
:
$decor = new ListDecorator($rit);
$rit->addDecorator($decor);
Następnie wszystko jest ustawione tak, aby po prostu foreach
nad nim i wyjście każdego węzła:
foreach($rit as $item)
{
$inset = $decor->inset(1);
printf("%s%s\n", $inset, $item->getName());
}
Jak pokazuje ten przykład, cała logika wyjścia jest zamknięta w klasie ListDecorator
i tej pojedynczej foreach
. Cały ruch rekurencyjny został w pełni zamknięty w iteratorach rekurencyjnych SPL, które zapewniały procedurę złożoną, co oznacza, że wewnętrznie nie są wykonywane żadne wywołania funkcji rekurencyjnej.
Oparte na zdarzeniach ListDecorator
pozwala możesz zmodyfikować dane wyjściowe i zapewnić wiele typów list dla tej samej struktury danych. Można nawet zmienić dane wejściowe, ponieważ dane tablicy zostały zamknięte w TreeNode
.
Przykład pełnego kodu:
<?php
namespace My;
$tree = array('H' => 'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null);
// add children to parents
$flat = array(); # temporary array
foreach ($tree as $name => $parent)
{
$flat[$name]['name'] = $name; # self
if (NULL === $parent)
{
# no parent, is root element, assign it to $tree
$tree = &$flat[$name];
}
else
{
# has parent, add self as child
$flat[$parent]['children'][] = &$flat[$name];
}
}
unset($flat);
class TreeNode
{
protected $data;
public function __construct(array $element)
{
if (!isset($element['name']))
throw new InvalidArgumentException('Element has no name.');
if (isset($element['children']) && !is_array($element['children']))
throw new InvalidArgumentException('Element has invalid children.');
$this->data = $element;
}
public function getName()
{
return $this->data['name'];
}
public function hasChildren()
{
return isset($this->data['children']) && count($this->data['children']);
}
/**
* @return array of child TreeNode elements
*/
public function getChildren()
{
$children = $this->hasChildren() ? $this->data['children'] : array();
$class = get_called_class();
foreach($children as &$element)
{
$element = new $class($element);
}
unset($element);
return $children;
}
}
class TreeNodesIterator implements \RecursiveIterator
{
private $nodes;
public function __construct(array $nodes)
{
$this->nodes = new \ArrayIterator($nodes);
}
public function getInnerIterator()
{
return $this->nodes;
}
public function getChildren()
{
return new TreeNodesIterator($this->nodes->current()->getChildren());
}
public function hasChildren()
{
return $this->nodes->current()->hasChildren();
}
public function rewind()
{
$this->nodes->rewind();
}
public function valid()
{
return $this->nodes->valid();
}
public function current()
{
return $this->nodes->current();
}
public function key()
{
return $this->nodes->key();
}
public function next()
{
return $this->nodes->next();
}
}
class RecursiveListIterator extends \RecursiveIteratorIterator
{
private $elements;
/**
* @var ListDecorator
*/
private $decorator;
public function addDecorator(ListDecorator $decorator)
{
$this->decorator = $decorator;
}
public function __construct($iterator, $mode = \RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
{
parent::__construct($iterator, $mode, $flags);
}
private function event($name)
{
// event debug code: printf("--- %'.-20s --- (Depth: %d, Element: %d)\n", $name, $this->getDepth(), @$this->elements[$this->getDepth()]);
$callback = array($this->decorator, $name);
is_callable($callback) && call_user_func($callback);
}
public function beginElement()
{
$this->event('beginElement');
}
public function beginChildren()
{
$this->event('beginChildren');
}
public function endChildren()
{
$this->testEndElement();
$this->event('endChildren');
}
private function testEndElement($depthOffset = 0)
{
$depth = $this->getDepth() + $depthOffset;
isset($this->elements[$depth]) || $this->elements[$depth] = 0;
$this->elements[$depth] && $this->event('endElement');
}
public function nextElement()
{
$this->testEndElement();
$this->event('{nextElement}');
$this->event('beginElement');
$this->elements[$this->getDepth()] = 1;
}
public function beginIteration()
{
$this->event('beginIteration');
}
public function endIteration()
{
$this->testEndElement();
$this->event('endIteration');
}
}
class ListDecorator
{
private $iterator;
public function __construct(RecursiveListIterator $iterator)
{
$this->iterator = $iterator;
}
public function inset($add = 0)
{
return str_repeat(' ', $this->iterator->getDepth()*2+$add);
}
public function beginElement()
{
printf("%s<li>\n", $this->inset(1));
}
public function endElement()
{
printf("%s</li>\n", $this->inset(1));
}
public function beginChildren()
{
printf("%s<ul>\n", $this->inset());
}
public function endChildren()
{
printf("%s</ul>\n", $this->inset());
}
public function beginIteration()
{
printf("%s<ul>\n", $this->inset());
}
public function endIteration()
{
printf("%s</ul>\n", $this->inset());
}
}
$root = new TreeNode($tree);
$it = new TreeNodesIterator(array($root));
$rit = new RecursiveListIterator($it);
$decor = new ListDecorator($rit);
$rit->addDecorator($decor);
foreach($rit as $item)
{
$inset = $decor->inset(2);
printf("%s%s\n", $inset, $item->getName());
}
Outpupt:
<ul>
<li>
D
<ul>
<li>
G
<ul>
<li>
H
</li>
<li>
F
</li>
</ul>
</li>
<li>
E
<ul>
</li>
<li>
A
</li>
<li>
C
<ul>
<li>
B
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Ewentualnym wariantem może być iterator, który jest iteracją nad dowolnym RecursiveIterator
i zapewnia iterację nad wszystkimi zdarzeniami, które mogą wystąpić. Przełącznik / obudowa wewnątrz foreach loop może wtedy zająć się wydarzeniami.
Powiązane:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:45
Cóż, najpierw zamieniłbym prostą tablicę par klucz-wartość w tablicę hierarchiczną
function convertToHeiarchical(array $input) {
$parents = array();
$root = array();
$children = array();
foreach ($input as $item) {
$parents[$item['id']] = &$item;
if ($item['parent_id']) {
if (!isset($children[$item['parent_id']])) {
$children[$item['parent_id']] = array();
}
$children[$item['parent_id']][] = &$item;
} else {
$root = $item['id'];
}
}
foreach ($parents as $id => &$item) {
if (isset($children[$id])) {
$item['children'] = $children[$id];
} else {
$item['children'] = array();
}
}
return $parents[$root];
}
To może przekonwertować płaską tablicę z parent_id i id na hierarchiczną:
$item = array(
'id' => 'A',
'blah' => 'blah',
'children' => array(
array(
'id' => 'B',
'blah' => 'blah',
'children' => array(
array(
'id' => 'C',
'blah' => 'blah',
'children' => array(),
),
),
'id' => 'D',
'blah' => 'blah',
'children' => array(
array(
'id' => 'E',
'blah' => 'blah',
'children' => array(),
),
),
),
),
);
Następnie utwórz funkcję renderującą:
function renderItem($item) {
$out = "Your OUtput For Each Item Here";
$out .= "<ul>";
foreach ($item['children'] as $child) {
$out .= "<li>".renderItem($child)."</li>";
}
$out .= "</ul>";
return $out;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-27 19:07:05
Chociaż Alexander-Konstantinov rozwiązanie może nie wydawać się tak łatwe do odczytania na początku, jest zarówno genialne, jak i wykładniczo lepsze pod względem wydajności, to powinno zostać uznane za najlepszą odpowiedź.
Dzięki kolego, zrobiłem benchmark na twoją cześć, aby porównać 2 rozwiązania przedstawione w tym poście.
Miałem płaskie drzewo @250k z 6 poziomami, które musiałem przekonwertować i szukałem lepszego sposobu, aby to zrobić i uniknąć iteracji rekurencyjnych.
Recursion vs Odniesienie:
// Generate a 6 level flat tree
$root = null;
$lvl1 = 13;
$lvl2 = 11;
$lvl3 = 7;
$lvl4 = 5;
$lvl5 = 3;
$lvl6 = 1;
$flatTree = [];
for ($i = 1; $i <= 450000; $i++) {
if ($i % 3 == 0) { $lvl5 = $i; $flatTree[$lvl6] = $lvl5; continue; }
if ($i % 5 == 0) { $lvl4 = $i; $flatTree[$lvl5] = $lvl4; continue; }
if ($i % 7 == 0) { $lvl3 = $i; $flatTree[$lvl3] = $lvl2; continue; }
if ($i % 11 == 0) { $lvl2 = $i; $flatTree[$lvl2] = $lvl1; continue; }
if ($i % 13 == 0) { $lvl1 = $i; $flatTree[$lvl1] = $root; continue; }
$lvl6 = $i;
}
echo 'Array count: ', count($flatTree), PHP_EOL;
// Reference function
function treeByReference($flatTree)
{
$flat = [];
$tree = [];
foreach ($flatTree as $child => $parent) {
if (!isset($flat[$child])) {
$flat[$child] = [];
}
if (!empty($parent)) {
$flat[$parent][$child] =& $flat[$child];
} else {
$tree[$child] =& $flat[$child];
}
}
return $tree;
}
// Recursion function
function treeByRecursion($flatTree, $root = null)
{
$return = [];
foreach($flatTree as $child => $parent) {
if ($parent == $root) {
unset($flatTree[$child]);
$return[$child] = treeByRecursion($flatTree, $child);
}
}
return $return ?: [];
}
// Benchmark reference
$t1 = microtime(true);
$tree = treeByReference($flatTree);
echo 'Reference: ', (microtime(true) - $t1), PHP_EOL;
// Benchmark recursion
$t2 = microtime(true);
$tree = treeByRecursion($flatTree);
echo 'Recursion: ', (microtime(true) - $t2), PHP_EOL;
Wyjście mówi samo za siebie:
Array count: 255493
Reference: 0.3259289264679 (less than 0.4s)
Recursion: 6604.9865279198 (almost 2h)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:23
Cóż, aby parsować do ULs i LIs, byłoby to coś w stylu:
$array = array (
'H' => 'G'
'F' => 'G'
'G' => 'D'
'E' => 'D'
'A' => 'E'
'B' => 'C'
'C' => 'E'
'D' => 'NULL'
);
recurse_uls ($array, 'NULL');
function recurse_uls ($array, $parent)
{
echo '<ul>';
foreach ($array as $c => $p) {
if ($p != $parent) continue;
echo '<li>'.$c.'</li>';
recurse_uls ($array, $c);
}
echo '</ul>';
}
Ale chciałbym zobaczyć rozwiązanie, które nie wymaga od Ciebie iteracji przez tablicę tak często...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-26 19:05:16
Oto co wymyśliłem:
$arr = array(
'H' => 'G',
'F' => 'G',
'G' => 'D',
'E' => 'D',
'A' => 'E',
'B' => 'C',
'C' => 'E',
'D' => null );
$nested = parentChild($arr);
print_r($nested);
function parentChild(&$arr, $parent = false) {
if( !$parent) { //initial call
$rootKey = array_search( null, $arr);
return array($rootKey => parentChild($arr, $rootKey));
}else { // recursing through
$keys = array_keys($arr, $parent);
$piece = array();
if($keys) { // found children, so handle them
if( !is_array($keys) ) { // only one child
$piece = parentChild($arr, $keys);
}else{ // multiple children
foreach( $keys as $key ){
$piece[$key] = parentChild($arr, $key);
}
}
}else {
return $parent; //return the main tag (no kids)
}
return $piece; // return the array built via recursion
}
}
Wyjścia:
Array
(
[D] => Array
(
[G] => Array
(
[H] => H
[F] => F
)
[E] => Array
(
[A] => A
[C] => Array
(
[B] => B
)
)
)
)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-26 19:32:51
Jak utworzyć dynamiczny widok drzewa i Menu
Krok 1: Najpierw utworzymy tabelę treeview w bazie danych mysql. tabela zawiera cztery column.id jest ID zadania, a nazwa jest nazwą zadania.
-
-- Table structure for table `treeview_items`
--
CREATE TABLE IF NOT EXISTS `treeview_items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL,
`title` varchar(200) NOT NULL,
`parent_id` varchar(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
--
-- Dumping data for table `treeview_items`
--
INSERT INTO `treeview_items` (`id`, `name`, `title`, `parent_id`) VALUES
(1, 'task1', 'task1title', '2'),
(2, 'task2', 'task2title', '0'),
(3, 'task3', 'task1title3', '0'),
(4, 'task4', 'task2title4', '3'),
(5, 'task4', 'task1title4', '3'),
(6, 'task5', 'task2title5', '5');
Krok 2: metoda rekurencyjna widoku drzewa Poniżej drzewa utworzyłem metodę createTreeView (), która wywołuje rekurencyjnie, Jeśli bieżący ID zadania jest większy niż poprzedni ID zadania.
function createTreeView($array, $currentParent, $currLevel = 0, $prevLevel = -1) {
foreach ($array as $categoryId => $category) {
if ($currentParent == $category['parent_id']) {
if ($currLevel > $prevLevel) echo " <ol class='tree'> ";
if ($currLevel == $prevLevel) echo " </li> ";
echo '<li> <label for="subfolder2">'.$category['name'].'</label> <input type="checkbox" name="subfolder2"/>';
if ($currLevel > $prevLevel) { $prevLevel = $currLevel; }
$currLevel++;
createTreeView ($array, $categoryId, $currLevel, $prevLevel);
$currLevel--;
}
}
if ($currLevel == $prevLevel) echo " </li> </ol> ";
}
Krok 3: Utwórz plik indeksu, aby wyświetlić widok drzewa. To jest główny plik przykładu treeview tutaj będziemy wywołanie metody createTreeView () z wymaganymi parametrami.
<body>
<link rel="stylesheet" type="text/css" href="_styles.css" media="screen">
<?php
mysql_connect('localhost', 'root');
mysql_select_db('test');
$qry="SELECT * FROM treeview_items";
$result=mysql_query($qry);
$arrayCategories = array();
while($row = mysql_fetch_assoc($result)){
$arrayCategories[$row['id']] = array("parent_id" => $row['parent_id'], "name" =>
$row['name']);
}
?>
<div id="content" class="general-style1">
<?php
if(mysql_num_rows($result)!=0)
{
?>
<?php
createTreeView($arrayCategories, 0); ?>
<?php
}
?>
</div>
</body>
Krok 4: Utwórz styl pliku CSS.css Tutaj napiszemy wszystkie klasy związane z css, obecnie używam listy zamówień do tworzenia widoku drzewa. możesz również zmienić ścieżkę obrazu tutaj.
img { border: none; }
input, select, textarea, th, td { font-size: 1em; }
/* CSS Tree menu styles */
ol.tree
{
padding: 0 0 0 30px;
width: 300px;
}
li
{
position: relative;
margin-left: -15px;
list-style: none;
}
li.file
{
margin-left: -1px !important;
}
li.file a
{
background: url(document.png) 0 0 no-repeat;
color: #fff;
padding-left: 21px;
text-decoration: none;
display: block;
}
li.file a[href *= '.pdf'] { background: url(document.png) 0 0 no-repeat; }
li.file a[href *= '.html'] { background: url(document.png) 0 0 no-repeat; }
li.file a[href $= '.css'] { background: url(document.png) 0 0 no-repeat; }
li.file a[href $= '.js'] { background: url(document.png) 0 0 no-repeat; }
li input
{
position: absolute;
left: 0;
margin-left: 0;
opacity: 0;
z-index: 2;
cursor: pointer;
height: 1em;
width: 1em;
top: 0;
}
li input + ol
{
background: url(toggle-small-expand.png) 40px 0 no-repeat;
margin: -0.938em 0 0 -44px; /* 15px */
height: 1em;
}
li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
li label
{
background: url(folder-horizontal.png) 15px 1px no-repeat;
cursor: pointer;
display: block;
padding-left: 37px;
}
li input:checked + ol
{
background: url(toggle-small.png) 40px 5px no-repeat;
margin: -1.25em 0 0 -44px; /* 20px */
padding: 1.563em 0 0 80px;
height: auto;
}
li input:checked + ol > li { display: block; margin: 0 0 0.125em; /* 2px */}
li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }