[RESOLU] forum : comment repérer pour un user les messages non lus ?

Eléphanteau du PHP | 16 Messages

09 juin 2014, 11:40

Bonjour à tous,

je suis en train de faire un genre de mini forum

une table 'sujets' (idsujet, sujet, idmembre, pseudo, texte, date (date de dernière modification par le créateur du sujet), lastreponse (date de la dernière réponse apportée à ce sujet)

une table 'messages' (idmessage, idsujet, idmembre, pseudo , texte, date (datetime de la création de ce message)

une table 'user' : dans cette table, il y a entre autre un champs : lastconnect (datetime de dernière connexion à forum)

Voici mon soucis : comment peut on repérer pour un User les messages qu'il n'a pas encore lu ?

Pour un instant 't' (ou plutot 'i') je sais faire : comparaison entre les 'datetime' : celui de la connexion du user au forum et ceux des messages du forum, on sort ensuite les messages créés après le datetime de dernière connexion du user au forum.

Mais une fois que l'un des messages de cette liste des 'nouveaux messages à lire' est lu... je ne sais pas quoi modifier pour que ce message n'apparaisse plus ds la liste des 'nouveaux messages'.
Si je modifie la date de dernière connexion du user après la lecture de ce premier message non lu, et pour peu que ce message soit le plus récent ds la liste, les autres 'messages non lus' n'apparaitront plus ds la liste, etc...

Suis je clair ?

Ce n'est pas vraiment du code qui m'est nécessaire, mais plutôt un principe de fonctionnement...

Merci o)

Mammouth du PHP | 571 Messages

09 juin 2014, 13:49

bonjour,
Voici mon soucis : comment peut on repérer pour un User les messages qu'il n'a pas encore lu ?
tout simplement en ajoutant un champ(ex :lu) de type boolean prenant pour valeur 0(pour message non lu) ou 1 (pour message lu). si un utilisateur clique sur "lire le message" alors tu exécute une requête sql qui doit mettre à jour le champ lu.cette mise àjour force ce champ de passer à 1.
Pour différencier les messages lus aux messages non lus il suffit de donner un nom au sélecteur de classe correspondant à chaque message(lu ou non lu) afin d'appliquer un style css à chaque sélecteur:
<?php
while($row = $bd->fetch() ) {
<div class="lu_<?php  echo $row['lu'] ?>">
<h3>sujet </h3>

</div>

<?php } ?>
puis dans un fichier css tu peux mettre en gras les titres des massages non lu
.lu_0 33 {
 font-weight:bold;
}
(si tu veux afficher que les messages non lus tu peux filtrer ta requête sql avec la clause where lu=0)

Eléphanteau du PHP | 16 Messages

09 juin 2014, 15:00

merci pour cette réponse

je comprends tout à fait le principe du champ boolean qui passe de 0 à 1 et inversement, mais...

à quelle table ajouter ce champ ??

si c à la table messages, cela implique alors qu'une fois 'lu' par un user, le champ de ce message passe à '1' et qu'il devient marqué 'lu' pour tous les autres User... non ?

Je me suis peut être mal fait comprendre :
lorsque sur le forum php france un nouveau message est créé, je le repère moi grâce au changement de couleur de l'icône (jaune vif), si je le lis, l'icône reprend sa couleur de base, mais le message reste à lire pour tous les autres Users du forum qui ne l'ont pas encore eux même lu.... comment ça fonctionne ça ? o)

ViPHP
xTG
ViPHP | 7331 Messages

09 juin 2014, 15:42

Il me semble que c'est une sorte de booléen du même type qu'expliqué.
C'est juste que c'est un champs où sont sérialisé les id des membres qui l'ont lu.
"1;3;4;6" => les membres 1, 3, 4 et 6 ont lu le message

Eléphanteau du PHP | 16 Messages

09 juin 2014, 16:05

ah ok... je vois ce que tu veux dire.
donc un champ 'lu' ds la table messages, puis une petite fonction qui me regarde si l'id du membre est dedans (lu) ou pas (non lu), et qui me renvoie true ou false par ex

Adjugé, je vais partir la dessus, et si y'a mieux je m'adapterai o)

merci messieurs pour votre concours ;-)

Mammouth du PHP | 571 Messages

09 juin 2014, 16:22

ah ok... je vois ce que tu veux dire.
donc un champ 'lu' ds la table messages, puis une petite fonction qui me regarde si l'id du membre est dedans (lu) ou pas (non lu), et qui me renvoie true ou false par ex

Adjugé, je vais partir la dessus, et si y'a mieux je m'adapterai o)

merci messieurs pour votre concours ;-)
de rien.
le champ lu ne peut pas être dans la table messages il faut créer une table associative entre la table messages et la table user:
messages-user(
lu boolean,
user_id int,
messages_id);



le type boolean c'est l'équivalent de TINYINT. ce type occupe moins de place mémoire qu'un integer(1) .

Eléphanteau du PHP | 16 Messages

09 juin 2014, 16:27

ça implique que potentiellement cette table pourrait avoir comme nbr d'enregistrements, dans le 'pire' des cas, le nombre de message x le nombre d'User du forum ?? ça peut faire des milliers de lignes ça lol, pas grave ?

Eléphanteau du PHP | 16 Messages

09 juin 2014, 16:31

bonjour,
puis dans un fichier css tu peux mettre en gras les titres des massages non lu
.lu_0 33 {
 font-weight:bold;
}
c'est koi le 33 ?.....

Mammouth du PHP | 571 Messages

09 juin 2014, 16:35

bonjour,
puis dans un fichier css tu peux mettre en gras les titres des massages non lu
.lu_0  {
 font-weight:bold;
}
c'est koi le 33 ?.....

suis désolé ça n'a aucune signification, c'est une coquille
.lu_0  {
 font-weight:bold;
}

Eléphanteau du PHP | 16 Messages

09 juin 2014, 16:39

bon, faut donc que je me plonge ds la notion de table associative...

j'y vais de ce pas

A plus tard alors o)

Eléphanteau du PHP | 16 Messages

09 juin 2014, 18:11

bon, je suis désolé, mais je sèche....

une fois cette table 'associative' créée... comment doit on la mettre à jour ?
quand un User crée un nouveau message, que dois je faire par rapport à cette table 'messages-user', faut il par exemple créer ds cette table autant de ligne qu'il existe de membres sur ce forum pour chaque nouveau message ???

Pour interroger cette table faut il par exemple :

les messages qu'un membre n'a pas lu :
SELECT idmessage, texte
FROM messages
JOIN messages-user
ON messages.idmessage = messages-user.idmessage
WHERE idmembre = '$un-id-de-membre' AND messages-user.lu = '0'

pas facile tout ça ma fois....
Modifié en dernier par moresk24 le 09 juin 2014, 18:22, modifié 1 fois.

ViPHP
xTG
ViPHP | 7331 Messages

09 juin 2014, 18:14

Si tu pars sur une table associative il faut créer un enregistrement uniquement quand l'utilisateur lit le topic.
Donc tu peux même dégager le champ booléen de cette table. ;)

Eléphanteau du PHP | 16 Messages

09 juin 2014, 18:50

Si tu pars sur une table associative il faut créer un enregistrement uniquement quand l'utilisateur lit le topic.
Donc tu peux même dégager le champ booléen de cette table. ;)
et lorsque qu'un message est rajouté à ce topic (sujet ?) il faut détruite toutes les lignes ayant l'id_topic pour que de nouveau il soit 'à lire' ?

bon :
je crée une table topic_lu ( champs : id, id_topic, idmembre)

lorsqu'un membre accède au forum, je liste les topics et avec une requete 'JOIN' je recherche les éventuels enregistrement ds la table topic_lu ; quand il n'y a pas de correspondance entre l'id_topic de la table topic (qui est la tables sujets chez moi) et de la table topic_lu pour cet id_topic et l'idmembre du membre connecté alors c que le topic contient un (au moins) message non lu
quand le membre ouvre ce topic et donc lit les message qu'il contient, je crée ds la table l'enregistrement => 'id_topic, idmembre'.
quand un utilisateur lambda rajoute un message à un topic :
- je supprime toutes les lignes de la table topic_lu qui ont l'idtopic de ce topic pour obligé le site à le donner comme à lire aux autres membres)
- j'ajoute l'enregistrement 'id_topic, idmembre' de ce membre lambda dans la table 'topic_lu' afin que ça ne soit pas un topic 'à lire' pour ce membre lambda, vu que c lui qu'il l'aura alimenté. (et je fais même pareil à la création d'un topic, afin que le créateur d'un topic n'ait pas ds sa liste 'nouveau message' ce topic).

Mais bon.... je vois pas bien ou est et à koi sert alors ma table associative (auquel je ne comprends pas grand chose)

malgré tout... suis je sur la bonne voie ?...

Merci de l'aide o)

Mammouth du PHP | 571 Messages

09 juin 2014, 19:04

une fois cette table 'associative' créée... comment doit on la mettre à jour ?
encore une fois suis désolé logiquement il faut plutôt insérer l'id du message et l'id de l'utilisateur dans la table user-message(merci XTG ) et non mettre à jour. Dans le cas d'espère l'id de l'utilisateur est connu(stocké en session au moment de de l'authentification) et l'id du message est transmis dans l'url.

dans la page html où tu affiche l'ensemble des messages(y compris les messages lus):
<?php while ($row = $dbh->fetch() ) { ?>
<a href="message-lu.php?message_id=<?php echo $row['message_id']?>"><?php echo $row['sujet'] ?> </a>

<?php } ?>

côté php pour on récupère l'id du message transmis via l'url puis on insère cet id et l'id de l’utilisateur dans la table message-user.
<?php
//script d'insertion id message et id user
//message-user.php
 $dbh = new PDO('mysql:host=localhost;dbname=nom_bd;charset=utf8', 'user', 'password');  
$user_id=$_SESSION['user_id'];
if( isset($_GET['message_id']) ){
    $stmt = $dbh->prepare("INSERT INTO messages-user VALUES(:user_id, :message_id)");

    $stmt->execute(array(':user_id' => $user_id, ':message_id'=> $_GET['message_id']));


}
?
Pour afficher les messages non lus ou lus une simple requête avec jointure sur les tables :user, messages-user et messages.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

09 juin 2014, 19:47

Pour répondre au fonctionnement de la table associative :

En fait les tables associatives répondent à un besoin relationnel de type N::N, c'est à dire que pour chacun des enregistrements d'une table (chacun de tes utilisateurs) on peut retrouver de 0 à N correspondance dans une autre table (un utilisateur peut avoir lu ou non, tout ou partie ou même aucun des messages de ton forum).

Pour des relations 1::N (ou 0::N), on ajoute simplement un champ dans la seconde table, faisant référence à la clé primaire de la première :
Un utilisateur appartient à une et une seule société (1), mais une société peut employer de 1 à N collaborateurs. On ajoute donc un id_société dans la table des utilisateurs pour savoir dans quelle société il travail.

Pour les relations N::N, on utilise une table intermédiaire de relation dans laquelle on va retrouver uniquement deux informations : la clé primaire de la première table et la clé primaire de la seconde table (id_utilisateur, id_message). On ajoutera ensuite un enregistrement dans cette table pour chaque relation entre un utilisateur et un message.
En gros, si l'utilisateur n°5 lit le message 42, tu ajoutes un enregistrement (5, 42), s'il lit ensuite le 65, tu ajoutes de même (5, 65). Tu peux ainsi connaitre les messages lus par cet utilisateurs (tous les messages dont l'id est associé à l'utilisateur 5 dans cette table). Et de même, tu peux retrouver les messages non lus en cherchant tous les messages qui n'ont aucune référence dans cette table pour l'utilisateur d'id 5.

Tu pourrais même ainsi gérer la notion de "marquer le message comme non lu" en retirant l'enregistrement correspondant de cette table.

J'espère que c'est plus clair comme ça :)

Après le nombre élevé d'enregistrement dans cette table n'est pas un soucis (enfin ça dépendra du nombre d'utilisateurs et de messages). Les BDD sont conçues pour gérer des millions d'enregistrements. C'est beaucoup d'insertions à chaque fois que quelqu'un consulte un topic puisque tous les messages qu'il découvre doivent être ajoutés, mais l'avantage, c'est que s'il ne lit que les messages de la première page, les autres ne seront pas marqués comme lus. :)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...