Avant de commencer, j'aimerais insister sur le fait qu'il existe un très bon tuto sur la question ici-même :
lien.
Mais ici, on va voir comment faire un système plus à la SDZ, avec possibilité de se rendre au dernier message non-lu.
Comment on s'y prend ?
Pour faire un système de ce type, on va avoir besoin d'une nouvelle table, qui s'appelle
forum_topic_view (

) ; voici comment elle se compose :
- un champ tv_id qui contient l'id du membre
- un champ tv_topic_id qui contient l'id du topic
- un champ tv_post_id qui contient l'id du dernier post lu du topic
- un champ tv_poste, qui contient 0 ou 1 si on a posté ou non dans le topic.
Vous pouvez comprendre qu'elle va servir à relier les id de chaque membre avec les topics qu'ils ont consultés, mais elle peut aussi faire plein d'autres choses qu'on verra en leur temps

.
Voici la requête pour créer la table :
Code : SQL | CREATE TABLE `forum_topic_view` (
`tv_id` INT( 11 ) NOT NULL ,
`tv_topic_id` INT( 11 ) NOT NULL ,
`tv_forum_id` INT( 11 ) NOT NULL ,
`tv_post_id` INT( 11 ) NOT NULL ,
`tv_poste` ENUM( '0', '1' ) NOT NULL,
PRIMARY KEY (`tv_id`,`tv_topic_id`)
) TYPE = MYISAM ;
|
Ensuite, il va vous falloir 5 images,
une pour les messages non-lus,
une pour les messages lus dans un topic où le membre a posté,
une pour les messages non-lus dans un topic où le membre a posté,
une pour les messages non-lus dans un topic que le membre a consulté
et une pour les messages déjà lus.
Je les ai appelées respectivement :
| message_non_lu.gif |
 |
| messagep_lu.gif |
 |
| messagep_non_lu.gif |
 |
| messagec_non_lus.gif |
 |
| message.gif |
 |
Voici pour les correspondances avec le SDZ, on peut remarquer que le site ne fait pas de distinction entre message simple non lu et message consulté non lu (en réalité une petite flèche est ajoutée nous permettant d'aller au dernier post lu).
Modification des pages php (Information)
Bon. Jusqu'ici tout va bien, c'est maintenant qu'il va falloir s'accrocher un peu

. On va tout d'abord s'occuper de la récupération d'informations, puis on verra l'affichage ensuite.
Page voirtopic.php
Donc, il faut ouvrir la page
voirtopic.php : c'est en visitant celle-ci que le membre consulte un topic, et on va tout simplement faire une requête qui envoie le résultat à savoir :
- l'id du membre qu'on obtient avec
$id
- l'id du topic qui est obtenu en
GET (elle est contenu dans la variable
$topic)
- et enfin, l'id du dernier message qui est connue grâce à la requête placée au début, et qui récupère des infos sur le topic, la variable est donc
$data['topic_last_post'].
Pensez à vous assurer que le membre est bien connecté avant de faire cette requête
Mais ce n'est pas tout : il faut également regarder s'il n'existe pas déjà une entrée avec ce topic et ce membre ; si c'est le cas, c'est-à-dire si le membre a déjà visité le topic, il faudra simplement mettre à jour la valeur du champ
tv_post_id.
Voici le script :
Code : PHP 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
27
28
29
30
31
32
33 | <?php
//Topic déjà consulté ?
$query=$db->prepare('SELECT COUNT(*) FROM forum_topic_view WHERE tv_topic_id = :topic AND tv_id = :id');
$query->bindValue(':topic',$topic,PDO::PARAM_INT);
$query->bindValue(':id',$id,PDO::PARAM_INT);
$query->execute();
$nbr_vu=$query->fetchColumn();
$query->CloseCursor();
if ($nbr_vu == 0) //Si c'est la première fois on insère une ligne entière
{
$query=$db->prepare('INSERT INTO forum_topic_view
(tv_id, tv_topic_id, tv_forum_id, tv_post_id)
VALUES (:id, :topic, :forum, :last_post)');
$query->bindValue(':id',$id,PDO::PARAM_INT);
$query->bindValue(':topic',$topic,PDO::PARAM_INT);
$query->bindValue(':forum',$forum,PDO::PARAM_INT);
$query->bindValue(':last_post',$data['topic_last_post'],PDO::PARAM_INT);
$query->execute();
$query->CloseCursor();
}
else //Sinon, on met simplement à jour
{
$query=$db->prepare('UPDATE forum_topic_view SET tv_post_id = :last_post
WHERE tv_topic_id = :topic
AND tv_id = :id');
$query->bindValue(':last_post',$data['topic_last_post'],PDO::PARAM_INT);
$query->bindValue(':topic',$topic,PDO::PARAM_INT);
$query->bindValue(':id',$id,PDO::PARAM_INT);
$query->execute();
$query->CloseCursor();
}
?>
|
Il est inutile de s'occuper ici du champ
tv_poste, il reste à 0, mais on se chargera de son cas dans 2 secondes

.
Page postok.php
Sur cette page, il va falloir faire deux choses : si on crée un nouveau topic, il faudra ajouter une ligne dans la table
forum_topic_view, exactement comme on vient de le faire. Par contre, si on envoie une réponse, il faudra mettre à jour cette table, on changera ainsi la valeur de
tv_post_id et
tv_poste.
Donc, dans la partie du switch traitant d'un nouveau topic, vous devez placer, juste avant le
echo, le code suivant :
Page : postok.php
Code : PHP 1
2
3
4
5
6
7
8
9
10
11
12
13 | <?php
//On ajoute une ligne dans la table forum_topic_view
$query=$db->prepare('INSERT INTO forum_topic_view
(tv_id, tv_topic_id, tv_forum_id, tv_post_id, tv_poste)
VALUES(:id, :topic, :forum, :post, :poste)');
$query->bindValue(':id',$id,PDO::PARAM_INT);
$query->bindValue(':topic',$nouveautopic,PDO::PARAM_INT);
$query->bindValue(':forum',$forum ,PDO::PARAM_INT);
$query->bindValue(':post',$nouveaupost,PDO::PARAM_INT);
$query->bindValue(':poste','1',PDO::PARAM_STR);
$query->execute();
$query->CloseCursor();
?>
|
Et de même, dans la partie traitant des réponses :
Code : PHP 1
2
3
4
5
6
7
8
9
10
11
12 | <?php
//On update la table forum_topic_view
$query=$db->prepare('UPDATE forum_topic_view
SET tv_post_id = :post, tv_poste = :poste
WHERE tv_id = :id AND tv_topic_id = :topic')
$query->bindValue(':post',$nouveaupost,PDO::PARAM_INT);
$query->bindValue(':poste','1',PDO::PARAM_STR);
$query->bindValue(':id',$id,PDO::PARAM_INT);
$query->bindValue(':topic',$topic,PDO::PARAM_INT);
$query->execute();
$query->CloseCursor();
?>
|
Si vous ne vous souvenez plus des variables utilisées, regardez un coup votre code, ou alors reprenez le chapitre en question. Vous voyez que tout est déjà en place : en fait, il ne reste plus qu'à appliquer ce qu'on a dit plus haut

.
Bon, c'en est terminé pour la première partie ; on va maintenant passer à la gestion de l'affichage, qui est un peu plus tordue.
Modification des pages php (Affichage)
Page voirforum.php
Alors, j'espère que vous êtes prêts, parce que la suite va demander un peu plus d'attention.
Déjà ouvrez la page
voirforum.php : il va falloir modifier les deux requêtes qui listent les sujets, afin d'y associer la table
forum_topic_view.
Pour cela, une jointure sera très utile : on pourra récupérer la valeur de
tv_id et de
tv_topic_id, et tout se déroulera parfaitement ; mais il ne faut pas oublier une chose :
un visiteur n'est pas forcément connecté, et c'est là que ça se corse un peu, il va falloir discerner les cas une fois de plus.
En fait, la requête va être modifiée à deux endroits, selon qu'on est connecté ou non (pour la sélection des champs et pour la jointure) ; en effet, si on est un simple invité, inutile d'inclure la table
forum_topic_view, puisqu'on marquera alors tous les messages comme déjà lus.
Donc, ce que l'on va faire, c'est créer deux variables : elles contiendront une portion de la requête si le membre est connecté, et rien si ce n'est pas le cas.
J'imagine que c'est difficile à comprendre avec des mots, alors je vous montre la première partie du script : elle se trouve juste avant la première grosse requête qui liste les annonces

.
Code : PHP 1
2
3
4
5
6
7
8
9
10
11
12 | <?php
$add1='';
$add2='';
if ($id!=0) //on est connecté
{
//Premièrement, sélection des champs
$add1 = 'tv_id, tv_post_id, tv_poste';
//Deuxièmement, jointure
$add2 = 'LEFT JOIN forum_topic_view
ON forum_topic.topic_id = forum_topic_view.tv_topic_id AND forum_topic_view.tv_id = :id';
}
?>
|
Les variables
$add1 et
$add2 contiennent donc une partie de la requête : s'ils ne sont pas renseignés, alors la jointure ne se fera pas, et on n'y verra que du feu

.
J'en profite pour expliquer un peu cette ligne :
Code : SQL | ON forum_topic.topic_id = forum_topic_view.tv_topic_id AND forum_topic_view.tv_id = blablabla
|
En fait, on veut inclure la table
forum_topic_view, mais pas entièrement ; sinon, lors de l'affichage, on aurait sur la page autant de fois un topic qu'il a été vu par les membres, ce qui n'est pas forcément très intéressant, quand on y pense

. Donc, on ajoute une condition sur le
ON, qui récupère uniquement les lignes de la table qui nous intéressent, à savoir celles qui concernent le membre en question.
Pour la suite, il va falloir reprendre la requête de cette façon :
Code : PHP 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | <?php
$query=$db->prepare('SELECT forum_topic.topic_id, topic_titre, topic_createur, topic_vu, topic_post, topic_time, topic_last_post, topic_locked,
Mb.membre_pseudo AS membre_pseudo_createur, post_createur, post_time, Ma.membre_pseudo AS membre_pseudo_last_posteur,
'.$add1.' post_id FROM forum_topic
LEFT JOIN forum_membres Mb ON Mb.membre_id = forum_topic.topic_createur
LEFT JOIN forum_post ON forum_topic.topic_last_post = forum_post.post_id
LEFT JOIN forum_membres Ma ON Ma.membre_id = forum_post.post_createur
'.$add2.'
WHERE topic_genre = "Annonce" AND forum_topic.forum_id = :forum
ORDER BY topic_last_post DESC');
$query->bindValue(':forum',$forum,PDO::PARAM_INT);
if ($id!=0) $query->bindValue(':id',$id,PDO::PARAM_INT);
$query->execute();
?>
|
Ainsi, il n'y aura plus d'erreurs si vous visitez la page en tant qu'invité !
Je vous laisse faire de même pour les topics normaux.
Passons à présent à la sélection de l'icône à afficher. Il s'agit d'un gros enchevêtrement de
if / else, donc il ne faut surtout pas perdre de vue ce que l'on fait.
Code : PHP 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
27
28
29
30
31
32
33
34
35
36
37
38
39 | <?php
//Gestion de l'image à afficher
if (!empty($id)) // Si le membre est connecté
{
if ($data['tv_id'] == $id) //S'il a lu le topic
{
if ($data['tv_poste'] == '0') // S'il n'a pas posté
{
if ($data['tv_post_id'] == $data['topic_last_post']) //S'il n'y a pas de nouveau message
{
$ico_mess = 'message.gif';
}
else
{
$ico_mess = 'messagec_non_lus.gif'; //S'il y a un nouveau message
}
}
else // S'il a posté
{
if ($data['tv_post_id'] == $data['topic_last_post']) //S'il n'y a pas de nouveau message
{
$ico_mess = 'messagep_lu.gif';
}
else //S'il y a un nouveau message
{
$ico_mess = 'messagep_non_lu.gif';
}
}
}
else //S'il n'a pas lu le topic
{
$ico_mess = 'message_non_lu.gif';
}
} //S'il n'est pas connecté
else
{
$ico_mess = 'message.gif';
}
?>
|
Piuf, ça fait des cas différents, mais au moins tout est pris en compte. J'espère que les commentaires vous ont aidés à comprendre comment ça fonctionne ; sinon, essayez avec des topics, et vous verrez que ça marche

.
Il ne vous reste maintenant plus qu'à afficher la valeur de
$ico_mess de la façon suivante :
Code : PHP | echo'<tr><td><img src="./images/'.$ico_mess.'"></td>';
|
Et ce, à la place de l'ancien
echo, qui faisait simplement
Code : PHP | echo'<tr><td><img src="./images/annonce.gif"></td>';
|
N'hésitez surtout pas à relire le code, et à essayer de le refaire (d'ailleurs, il faut que vos le refassiez pour la liste des topics "normaux" ; je rappelle qu'ici il ne s'agit que des annonces).
Maintenant, comme sur le SDZ, vous pouvez repérer plus facilement les topics où vous avez posté par rapport à ceux que vous avez simplement consultés.
Page index.php
Bon bah pour la page d'index, c'est la même affaire, je vais donc vous laisser vous débrouiller un peu seuls. La seule différence, c'est que cette fois on utilise le dernier post du forum, et non pas du topic. Il faut utiliser le champ tv_forum_id tout simplement.
Donc, une fois la condition faite, vous entrez le résultat dans la variable
$ico_mess, et puis le tour est joué : il vous suffit de recopier la série de conditions !
Faire des liens sympas
Le gros avantage de cette méthode est qu'il est possible de faire, encore une fois comme sur le SdZ, des liens qui nous listent directement les topics où l'on a posté, ceux que l'on a visités, etc.
Donc, n'hésitez pas à vous amuser à en faire : non seulement ça sera un bon entraînement si vous avez compris la méthode, mais c'est toujours un plus pour les visiteurs (personnellement, j'utilise très souvent cette option et je suis très content qu'elle existe

).
Si vous avez un peu digéré, on va passer à une partie plus tranquille qui est la réalisation de la fonction "Qui est en ligne ?".