Hébergement de sites web
Web Hosting

Construire un menu arborescent avec une fonction récursive en PHP

Un sujet assez difficile à comprendre dans le monde de la programmation web pour plusieurs webmasters qui ont appris par eux-mêmes, dont je fais parti, est la technique de récursivité, où une fonction fait appel à elle-même. Cette fonction est dit récursive dans ce cas, et elle peut être nécessaire dans plusieurs situations, telles que la création d’un menu arborescent complexe où le nombre de sous-catégories n’est pas prévisible.

Commençons par la structure d’une base de donnée MySQL simple et typique pour ces catégories. Celle-ci est une table, appelée Animaux, contenant une liste de catégories, avec leur identitification propre, leur nom, et leur lien de parenté avec une autre catégorie, si elle est en fait une sous catégorie de celle-ci dans une menu arborescent.

ID 	Parent 	Name
1 	0 	Félins
2 	1 	Grands Félins
3 	2 	Panthères
4 	2 	Lions
5 	1 	Petits Félins
6 	2 	Tigres
8 	0 	Poissons
9 	0 	Canins
10 	8 	Saumons
11 	8 	Requins
12 	9 	Loups
13 	9 	Chiens

Le champs Parent d’une sous-catégorie fait référence à l’identification ID de la catégorie dont elle fait partie. Par exemple, Panthères, avec la valeur Parent de 2, est une sous-catégorie de Grands Félins, identifiée par le code ID 2, et avec son code Parent de 1, elle est elle-même une sous-catégorie Félins, identifiée par le code ID 1. Comme Félins est une catégorie principale qui n’a pas de lien de parenté, sa valeur pour Parent est 0.

Pour saisir ces données et l’insérer dans une liste (array en anglais) afin de pouvoir l’organiser avec PHP, on fera appel à la fonction suivante:

1
2
3
4
5
6
7
8
9
10
11
12
$query = "SELECT ID, Parent, Name FROM Animaux ORDER BY Name ASC";
$result = mysql_query($query);
 
$categories = array();
 
while($row = mysql_fetch_array($result)) {
	$categories[] = array(
	'parent_id' => $row['Parent'],
	'category_id' => $row['ID'],
	'category_name' => $row['Name']
	);
}

Si on visualise les 3 premiers éléments de la liste associative en PHP qui est maintenant en ordre alphabétique, elle ressemble à ça:

(
    [0] => Array
        (
            [parent_id] => 1
            [category_id] => 5
            [category_name] => Petits Félins
        )
 
    [1] => Array
        (
            [parent_id] => 9
            [category_id] => 13
            [category_name] => Chiens
        )
 
    [2] => Array
        (
            [parent_id] => 8
            [category_id] => 10
            [category_name] => Saumons
        )
 
)

Nous avons donc maintenant le contenu de notre table dans une liste PHP organisé en ordre alphabétique. Comment l’organiser de façon à ce que la liste de menu soit affichée en mode arborescent dans une page HTML? Nous allons utiliser une fonction récursive appelée display_menu(). Dans cette version, nous allons tout simplement l’afficher en mode texte de façon à rester simple et compréhensible à ce niveau du tutoriel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function display_menu($parent, $level, $array) {
 
foreach ($array AS $node) {
 
	if ($parent == $node['parent_id']) {
 
	for ($i = 0; $i < $level; $i++) $html .= "-";
 
	$html .= " " . $node['category_name'] . "<br />";
 
	$html .= display_menu($node['category_id'], ($level + 1), $array);
 
	}
 
}
 
return $html;
 
}

Quelques explications: Alors qu’on parcoure la liste désorganisée, si on rencontre une catégorie qui a un lien de parenté avec une autre, après l’avoir ajoutée dans le code HTML (variable $html), on fait encore appel à la même fonction afin de vérifier si celle-ci n’a pas aussi une sous-catégorie, avant de continuer les instructions additionelles de la fonction, et ainsi de suite. On sauvegarde le nombre de fois que la fonction est appelée par elle-même dans la variable $level afin de déterminer combien de symboles “-” on devrait ajouter afin de démontrer sa position dans la structure arborescente.

Ensuite, nous faisons appel à cette fonction dans la page web ou nous voulons afficher le menu. Le premier 0 de la fonction pour la variable $parent indique que nous voulons afficher le menu en commençant avec les catégories principales à la racine qui ont une valeur de parenté de 0, mais au besoin, on pourrait seulement afficher une sous-catégorie avec une valeur de parenté différente. L’autre 0 initialise la valeur de $level à 0. $categories est évidemment notre liste précédente:

echo display_menu(0, 0, $categories);

Le résultat devrait être celui-ci:

Canins
- Chiens
- Loups
Félins
- Grands Félins
-- Lions
-- Panthères
-- Tigres
- Petits Félins
Poissons
- Requins
- Saumons

Maintenant, ce format n’est pas très élégant, nous allons voir comment formater ce menu textuel avec les balises <ul> et <li>, une façon sémantiquement correcte de présenter une liste en HTML, et qui peut, par la suite, être pleinement contrôlée en CSS pour créer un menu de navigation esthétiquement plaisant.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function display_menu($parent, $level, $array) {
 
if (!$level && !$previous_level) $html .= "\n<ul>\n";
 
foreach ($array AS $node) {
 
	if ($parent == $node['parent_id']) {
 
	if ($previous_level < $level) $html .= "\n<ul>\n";
 
	$html .= "<li>" . $node['category_name'];
 
	$previous_level = $level;
 
	$html .= display_menu($node['category_id'], ($level + 1), $array);
 
	}
}
 
if (($previous_level == $level) && ($previous_level != 0)) $html .= "</ul>\n</li>\n";
else if ($previous_level == $level) $html .= "</ul>\n";
else $html .= "</li>\n";
 
return $html;
 
}

Quelques explications: La variable $previous_level garde en mémoire le niveau précédent dans l’arborescence du menu, donc on peut la comparer au niveau actuel, $level, pour voir s’il y a eu un changement pour contrôler les débuts et les fins de liste avec la balise ul. À la ligne 3, si la variable est encore vide, on commence avec la balise ul de la liste principale. Ensuite, à la ligne 9, si le niveau vient d’augmenter, on peut commencer avec une nouvelle balise ul qui sera un sous-menu. On enregistre la niveau actuel à la ligne 13, et la fonction est appelée récursivement pour voir s’il y aura encore un sous-menu. Dans le cas contraire, on doit contrôler la fermeture des balises correctement.

Cette fonction va générer le code suivant:

<ul>
<li>Canins
	<ul>
	<li>Chiens</li>
	<li>Loups</li>
	</ul>
</li>
<li>Félins
	<ul>
	<li>Grands Félins
		<ul>
		<li>Lions</li>
		<li>Panthères</li>
		<li>Tigres</li>
		</ul>
	</li>
	<li>Petits Félins</li>
	</ul>
</li>
<li>Poissons
	<ul>
	<li>Requins</li>
	<li>Saumons</li>
	</ul>
</li>
</ul>

Pour ajouter des liens à chaque catégories, il suffit maintenant de modifier la ligne 11 avec celle-ci:

11
	$html .= "<li><a href=\"?category=" . $node['category_id'] . "\">" . $node['category_name'] . "</a>";

Catégories: Programmation web |

Laisser un commentaire