Hello, I’m Vinch

And this is my website.

Comment créer un nuage de tags en PHP/MySQL ?

01/28/07

This post is more than 10 years old. It might not reflect my current skills and convictions.

Les tags sont devenus un élément incontournable pour toute application Web 2.0 qui se respecte. Ils permettent une organisation qui va plus loin que la catégorisation classique (catégorie > sous-catégorie > etc.). Cette classification est appelée Folksonomie.

Un nuage de tags, quant à lui, est une façon de représenter un groupe de tags, en jouant visuellement sur la taille et la couleur de la police. Les exemples les plus marquants de nuages de tags sont ceux de Flickr, de Technorati ou encore de del.icio.us.

Dans ce billet, je vais tenter de vous montrer comment on peut réaliser son propre nuage de tags en PHP/MySQL.

Tout d’abord, vous avez besoin d’une table dans votre base de données, qui se présente à peu près de cette façon :

+---------+
| tags    |
+---------+
| id      |
| tag     |
| item_id |
+---------+

* id est l’identifiant unique du tag
* tag est le tag à proprement parler
* item_id est l’élément auquel vous attachez le tag, par exemple un billet de votre blog, un lien, une vidéo, etc. Il s’agit d’une clé étrangère vers l’identifiant unique de la table concernée.

Une fois remplie, votre table doit ressembler à quelque chose de ce genre :

+-----+------+---------+
| id  | tag  | item_id |
+-----+------+---------+
| 1   | fun  | 1       |
| 2   | html | 1       |
| 3   | css  | 1       |
| 4   | html | 2       |
| 5   | php  | 2       |
| 6   | css  | 3       |
| 7   | php  | 3       |
| 8   | php  | 4       |
+-----+------+---------+

Voyons maintenant le code PHP qui va nous permettre de recolter les données utiles à la création de notre nuage. Je vous épargne les lignes concernant la connexion à la base de données.

<?php

define("MIN_SIZE", 9);
define("MAX_SIZE", 36);

$result = mysql_query("SELECT tag, count(*) as number FROM tags GROUP BY tag ORDER BY tag") or die(mysql_error());

$min = MAX_INT;
$max = -MAX_INT;

while ($tag = mysql_fetch_assoc($result)) {
	if ($tag['number'] < $min) $min = $tag['number'];
	if ($tag['number'] > $max) $max = $tag['number'];
	$tags[] = $tag;
}

$min_size = MIN_SIZE;
$max_size = MAX_SIZE;

foreach ($tags as $tag) {
	$tag['size'] = intval($min_size + (($tag['number'] - $min) * (($max_size - $min_size) / ($max - $min))));
	$tags_extended[] = $tag;
}

?>

Les deux premières lignes servent à définir les tailles minimum et maximum. La taille minimum sera assignée aux élements ayant la plus petite fréquence (ici fun avec une fréquence 1) et la taille maximum aux éléments ayant la plus grande fréquence (ici php avec une fréquence 3). Ce sont des tailles en pixels, vous pouvez bien sûr changer ces valeurs ou adapter l’algorithme pour travailler en pourcentages.

Ensuite, on réalise une requête SQL qui extrait chaque tag distinct accompagné de sa fréquence.

La boucle while sert à récupérer la fréquence minimum et la fréquence maximum (dans notre exemple, respectivement 1 et 3). Avant la boucle, on associe à $min et $max des valeurs de départ (très grande pour le minimum et inversément) qui seront remplacées dès le premier passage dans la boucle.

Dans le foreach, on calcule la taille qui sera associée à chaque tag grâce à une formule magique. Cette formule ajoute à la taille minimum la fréquence moins la fréquence minimum fois un certain ratio. Ce ratio correspond à l’écart de tailles entre deux fréquences voisines. Dans notre exemple, la différence de taille entre deux fréquences voisines est de 12,5 (36-9/3-1).

Cela donne donc le résultat suivant : la taille des éléments de fréquence 1 est 9, la taille des éléments de fréquence 2 est 21 (9+12,5 arrondi à l’unité inférieure via intval), la taille des éléments de fréquence 3 est 36 (9+(2*12,5)). On est parfaitement retombé sur nos pattes.

Au niveau de l’affichage, il vous suffit de passer le tableau $tags_extended à votre vue et de boucler dessus pour afficher les tags, en utilisant un style en ligne pour les tailles :

<?php foreach ($tags_extended as $tag) : ?>
<a href="/tags/<?php echo $tag['tag']; ?>" style="font-size:<?php echo $tag['size']; ?>px" title="<?php echo $tag['tag']; ?>"><?php echo $tag['tag']; ?></a>
<?php endforeach; ?>

Si vous utilisez le moteur de templates Smarty (ce que je vous conseille), cela donne :

{foreach from=$tags_extended item=tag}
<a href="/tags/{$tag.tag}" style="font-size:{$tag.size}px" title="{$tag.tag}">{$tag.tag}</a>
{/foreach}

Voici le résultat auquel on arrive. Vous pouvez également voir le contenu des tableaux $tags et $tags_extended sur cette page.

Pour les techniciens, sachez que la complexité de cet algorithme est en O(2*n)n est le nombre de tags distincts dans la base de données.

Dans un prochain billet, j’essaierai de rendre ce nuage de tags accessible ! (je n’ai pas encore de solutions miracles mais j’y travaille)

46 comments

Leave a comment