web-dev-qa-db-fra.com

Convertir une série de relations parent-enfant en une arborescence hiérarchique?

J'ai un tas de paires nom-parent, que j'aimerais transformer en aussi peu d'arborescences hiérarchiques que possible. Ainsi, par exemple, il pourrait s'agir des appariements:

Child : Parent
    H : G
    F : G
    G : D
    E : D
    A : E
    B : C
    C : E
    D : NULL

Ce qui doit être transformé en un (s) arbre (s) hiérarchique (s):

D
├── E
│   ├── A
│   │   └── B
│   └── C   
└── G
    ├── F
    └── H

Le résultat final que je veux est un ensemble imbriqué d'éléments <ul>, chaque <li> contenant le nom de l'enfant.

Il n’ya pas d’incohérences dans les appariements (l’enfant est son propre parent, le parent est l’enfant de l’enfant, etc.), ce qui permet probablement de nombreuses optimisations.

Comment, en PHP, passerais-je d'un tableau contenant des paires enfant => à un ensemble de <ul>s imbriqués?

J'ai l'impression que la récursivité est impliquée, mais je ne suis pas assez réveillé pour y réfléchir.

92
Eric

Cela nécessite une fonction récursive très basique pour analyser les paires enfant/parent en une arborescence et une autre fonction récursive pour l’imprimer. Une seule fonction suffirait, mais en voici deux pour plus de clarté (une fonction combinée se trouve à la fin de cette réponse).

Commencez par initialiser le tableau des paires enfant/parent:

$tree = array(
    'H' => 'G',
    'F' => 'G',
    'G' => 'D',
    'E' => 'D',
    'A' => 'E',
    'B' => 'C',
    'C' => 'E',
    'D' => null
);

Ensuite, la fonction qui analyse ce tableau dans une arborescence hiérarchique:

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;    
}

Et une fonction qui traverse cette arborescence pour imprimer une liste non ordonnée:

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>';
    }
}

Et l'utilisation réelle:

$result = parseTree($tree);
printTree($result);

Voici le contenu de $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
                            )
                        )
                    )
                )
            )
        )
    )
)

Si vous voulez un peu plus d’efficacité, vous pouvez combiner ces fonctions en une seule et réduire le nombre d’itérations effectuées:

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>';
    }
}

Vous ne sauvegarderez que 8 itérations sur un ensemble de données aussi petit que cela, mais sur des ensembles plus importants, cela pourrait faire la différence.

119
Tatu Ulmanen

Encore une autre fonction pour créer un arbre (pas de récursivité, utilise des références)

$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;
}

Retourne un tableau hiérarchique comme celui-ci:

Array(
    [D] => Array(
        [G] => Array(
            [H] => Array()
            [F] => Array()
        )
        ...
    )
)

Ce qui peut facilement être imprimé sous forme de liste HTML en utilisant la fonction récursive.

52

Une autre façon plus simplifiée de convertir la structure à plat du $tree en une hiérarchie. Un seul tableau temporaire est nécessaire pour l'exposer:

// 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);

C'est tout pour obtenir la hiérarchie dans un tableau multidimensionnel:

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
)

Le résultat est moins trivial si vous voulez éviter la récursivité (cela peut être un fardeau pour les grandes structures).

J'ai toujours voulu résoudre le "dilemme" UL/LI pour la sortie d'un tableau. Le dilemme est que chaque élément ne sait pas si les enfants feront un suivi ou combien d'éléments précédents doivent être fermés. Dans une autre réponse, j'ai déjà résolu ce problème en utilisant un RecursiveIteratorIterator et en recherchant getDepth() et d'autres méta-informations fournies par ma propre Iterator: Mise en place d'un modèle d'ensemble imbriqué dans un <ul> mais masquant les sous-arbres «fermés» . Ce réponse montre également qu'avec les itérateurs, vous êtes assez flexible.

Cependant, il s’agissait d’une liste présélectionnée, elle ne conviendrait donc pas à votre exemple. De plus, j'ai toujours voulu résoudre ce problème pour une sorte d'arborescence standard et les éléments HTML <ul> et <li> de HTML.

Le concept de base que j'ai évoqué est le suivant:

  1. TreeNode - Abstrait chaque élément dans un type TreeNode simple pouvant fournir sa valeur (par exemple Name) et indiquer s'il a ou non des enfants.
  2. TreeNodesIterator - Une RecursiveIterator capable de parcourir un ensemble (tableau) de ces TreeNodes. C'est assez simple car le type TreeNode sait déjà s'il a des enfants et lesquels.
  3. RecursiveListIterator - Une RecursiveIteratorIterator qui contient tous les événements nécessaires pour effectuer une itération récursive sur tout type de RecursiveIterator:
    • beginIterationendIteration - D&EACUTE;BUT ET FIN DE LA LISTE PRINCIPALE.
    • beginElement/endElement - D&EACUTE;BUT ET FIN DE CHAQUE &EACUTE;L&EACUTE;MENT.
    • beginChildren/endChildren - D&EACUTE;BUT ET FIN DE CHAQUE LISTE D'ENFANTS ..__ CETTE RecursiveListIterator FOURNIT UNIQUEMENT CES &EACUTE;V&EACUTE;NEMENTS SOUS FORME D'APPELS DE FONCTION. LES LISTES D'ENFANTS, COMME C'EST LE CAS POUR LES LISTES <ul><li>, SONT OUVERTES ET FERM&EACUTE;ES &AGRAVE; L'INT&EACUTE;RIEUR DE SON &EACUTE;L&EACUTE;MENT <li> PARENT. PAR CONS&EACUTE;QUENT, L'&EACUTE;V&EACUTE;NEMENT endElement EST D&EACUTE;CLENCH&EACUTE; APR&EGRAVE;S L'&EACUTE;V&EACUTE;NEMENT endChildren CORRESPONDANT. CELA POURRAIT &ECIRC;TRE MODIFI&EACUTE; OU CONFIGUR&EACUTE; POUR &EACUTE;LARGIR L'UTILISATION DE CETTE CLASSE. LES &EACUTE;V&EACUTE;NEMENTS SONT ENSUITE DISTRIBU&EACUTE;S EN TANT QU'APPELS DE FONCTION &AGRAVE; UN OBJET DE D&EACUTE;CORATEUR, AFIN DE S&EACUTE;PARER LES &EACUTE;L&EACUTE;MENTS.
  4. _/ListDecorator - Une classe de "décorateur" qui n'est qu'un récepteur des événements de RecursiveListIterator.

Je commence par la logique de sortie principale. Dans le tableau maintenant hiérarchique $tree, le code final se présente comme suit:

$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());
}

Voyons d’abord la variable ListDecorator qui englobe simplement les éléments <ul> et <li> et détermine le mode de sortie de la structure de liste:

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);
    }

Le constructeur prend l'itérateur de liste sur lequel il travaille. inset est juste une fonction d'assistance pour une bonne indentation de la sortie. Le reste ne sont que les fonctions de sortie pour chaque événement:

    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());
    }
}

Avec ces fonctions de sortie à l’esprit, c’est à nouveau la boucle principale de sortie/boucle de sortie, je la parcoure pas à pas:

$root = new TreeNode($tree);

Créez la racine TreeNode qui sera utilisée pour démarrer l'itération lorsque:

$it = new TreeNodesIterator(array($root));

Cette TreeNodesIterator est une RecursiveIterator qui active l'itération récursive sur le seul noeud $root. Il est passé comme un tableau car cette classe a besoin de quelque chose d'itérer et permet la réutilisation avec un ensemble d'enfants qui est aussi un tableau d'éléments TreeNode.

$rit = new RecursiveListIterator($it);

Cette RecursiveListIterator est une RecursiveIteratorIterator qui fournit lesdits événements. Pour l'utiliser, il suffit de fournir une ListDecorator (la classe ci-dessus) et de lui associer addDecorator:

$decor = new ListDecorator($rit);
$rit->addDecorator($decor);

Ensuite, tout est configuré pour que foreach soit créé et génère chaque noeud:

foreach($rit as $item)
{
    $inset = $decor->inset(1);
    printf("%s%s\n", $inset, $item->getName());
}

Comme le montre cet exemple, toute la logique de sortie est encapsulée dans la classe ListDecorator et dans cette unique foreach. La totalité de la parcours récursif a été entièrement encapsulée dans des itérateurs récursifs SPL fournissant une procédure empilée, ce qui signifie qu'aucun appel de fonction de récursion n'est effectué en interne.

La variable ListDecorator basée sur les événements vous permet de modifier la sortie de manière spécifique et de fournir plusieurs types de listes pour la même structure de données. Il est même possible de modifier l'entrée car les données du tableau ont été encapsulées dans TreeNode.

L'exemple de code complet:

<?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>

_ { Démo (variante de PHP 5.2) } _

Une variante possible serait un itérateur qui itère sur une variable RecursiveIterator et fournit une itération sur tous les événements pouvant se produire. Un commutateur/boîtier dans la boucle foreach pourrait alors gérer les événements.

En relation:

27
hakre

Eh bien, tout d’abord, je transformerais le tableau droit de paires clé-valeur en un tableau hiérarchique

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];
}

Cela peut convertir un tableau plat avec parent_id et id en un tableau hiérarchique:

$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(),
                ),
            ),
        ),
    ),
);

Ensuite, créez simplement une fonction de rendu:

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;
}
8
ircmaxell

Bien que la solution de Alexander-Konstantinov puisse sembler moins lisible au début, elle est à la fois géniale et plus performante, mais elle aurait dû être votée comme la meilleure réponse.

Merci mec, j'ai fait un point de repère en votre honneur pour comparer les 2 solutions présentées dans ce post.

J'avais un arbre @ 250k plat avec 6 niveaux que je devais convertir et je cherchais un meilleur moyen de le faire et d'éviter les itérations récursives.

Récursion vs référence:

// 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;

La sortie parle d'elle-même:

Array count: 255493
Reference: 0.3259289264679 (less than 0.4s)
Recursion: 6604.9865279198 (almost 2h)
5
ntt

Eh bien, pour analyser les UL et les LI, ce serait quelque chose comme:

$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>';
}

Mais j'aimerais voir une solution qui ne vous oblige pas à parcourir le tableau aussi souvent ...

2
arnorhs

Voici ce que je suis venu avec:

$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
      }
    }

les sorties:

Array
(
    [D] => Array
        (
            [G] => Array
                (
                    [H] => H
                    [F] => F
                )

            [E] => Array
                (
                    [A] => A
                    [C] => Array
                        (
                            [B] => B
                        )    
                )    
        )    
)
2
Dan Heberden

Comment créer une vue et un menu d'arborescence dynamique

Etape 1: Nous allons d’abord créer une table d’arbres dans la base de données mysql. cette table contient quatre column.id est l'ID de la tâche et nom est le nom de la tâche.

-
-- 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');

Étape 2: Méthode récursive dans l'arborescence J'ai créé ci-dessous la méthode createTreeView () qui appelle récursive si l'id de la tâche en cours est supérieur à celui de la tâche précédente.

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> ";

}

Étape 3: Créer un fichier d’index pour afficher l’arborescence . Ceci est le fichier principal de l’exemple de treeview. Nous appellerons ici la méthode createTreeView () avec les paramètres requis.

 <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>

Étape 4: Créer un fichier CSS style.cssVoici, nous écrirons toutes les classes liées à css. J'utilise actuellement la liste de commande pour créer une vue en arborescence. vous pouvez aussi changer le chemin de l'image ici.

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 */ }

Plus de détails

0
user1364100