2009-07-23 11 views
1

arbeite ich zur Zeit ein eigenes Nachrichtensystem zum Erstellen von (PHP/MySQL), in der Benutzer-Nachricht an mehrere Empfänger gleichzeitig senden können, und die Benutzer können dann antworten entscheiden.Private Nachrichten-System mit Threading/Antworten

Hier ist, was ich zur Zeit mit gerade arbeitete:

tbl_pm tbl: 
id 
date_sent 
title 
content 
status ENUM ('unread', 'read') DEFAULT 'unread' 

tblpm_info tbl: 
id 
message_id 
sender_id 
receiver_id 

Aber ich brauche Hilfe bei der Bestimmung der Logik auf zwei Dinge:

1) Wenn eine neue Nachricht erstellt wird, soll die „id "Auto-Inkrement sein? Wenn die Spalte "id" in beiden Tabellen automatisch inkrementiert wird, wie würde ich die Spalte "message_id" in der Relationstabelle festlegen?

Zum Beispiel, wenn eine neue Nachricht erstellt wird, meine MySQL-Anweisung lautet wie folgt:

<?php 
mysql_query("INSERT INTO `tblpm` (title, content, sender_id, date_sent) VALUES ('$subject', '$message', '$sender', NOW())"); 

In der gleichen Aussage, wie würde ich den ‚auto-inkrementierte‘ Wert der tblpm in die tblpm_info eingeben " message_id "Feld?

2) Was sollte meine MySQL-Anweisung aussehen, wenn Benutzer auf Nachrichten antworten?

Vielleicht mache ich das komplizierter, als ich brauche. Jede Hilfe wird sehr geschätzt!

Antwort

1

1) Definetely ja, sollte ids sein auto-autoinkrementierten, wenn Sie ein anderes Mittel eines Primärschlüssels zur Verfügung stellen Das ist einzigartig. Sie erhalten die ID des Einsatzes entweder mit mysql_insert_id() oder LAST_INSERT_ID() von mysql direkt, also einige angeschlossenen Infos posten Sie entweder

mysql_query("INSERT INTO table1 ...") 
    $foreign_key=mysql_insert_id(); //this gives you the last auto-increment for YOUR connection 

tun können, oder, aber nur, wenn Sie absolut sicher, dass niemand sonst in der Tabelle schreibt in der Zwischenzeit oder hat die Kontrolle über die Transaktion, nachdem Einsatz tun:

$foreign_key=mysql_query("SELECT LAST_INSERT_ID()") 
INSERT INTO table2 message_id=$foreign_key 

oder ohne den FK zu php zu ziehen, die alle in einer Transaktion (I Beratung auch die SQL als eine Transaktion zu wickeln) mit etwas wie:

"INSERT INTO table1...; INSERT INTO table2 (message_id,...) VALUES(LAST_INSERT_ID(),...)" 

Abhängig von Ihrer Sprach- und MySQL-Bibliothek können Sie möglicherweise den Multi-Query-Ansatz nicht ausführen. Daher ist es besser, den ersten Ansatz zu verwenden.

2) Dies kann so viele Ansätze haben, je nachdem, ob Sie auch auf alle Empfänger antworten müssen (z. B. Konferenz), in einer Thread-/Forum-ähnlichen Weise antworten, ob die Clientseite den zuletzt abgerufenen Inhalt speichern kann Nachricht/ID (zB in einem Cookie; auch davon betroffen, ob Sie wirklich das "Lesen" -Feld benötigen). Der "private Chat" -Ansatz ist der einfachste, Sie sind wahrscheinlich besser dran, entweder die Nachricht in einer Tabelle zu speichern und die von-zu-Beziehungen in eine andere (und verwenden Sie JOINs auf ihnen) oder einfach wieder aufzufüllen die Nachricht in einer Tabelle (seit Speicher ist heutzutage billig). So würde die vereinfachte Modell eine Tabelle sein:

table: message_body,from,to 
$recepients=array(1,2,3..); 
foreach($recepients as $recepient) 
mysql_query("INSERT INTO table (...,message_body,from,to) VALUES(...,$from,$recepient)"); 

(Duplikat der Nachricht usw., nur die Recepient Änderungen)

oder

message_table: id,when,message_body 
to-from-table: id,msg_id,from,to 

$recepients=array(1,2,3,...); 
mysql_insert("INSERT INTO message_table (when,message_body) VALUES(NOW(),$body)"); 
$msg_id=mysql_insert_id(); 
foreach($recepients as $recepient) 
mysql_query("INSERT INTO to-from-table (msg_id,from,to) VALUES($msg_id,$from,$recepient)"); 

(Nachricht einmal eingefügt, speichern Sie die Beziehungen und FK für alle Empfänger)

Jeder Client speichert dann die letzte message_id, die er/sie erhalten hat (standardmäßig 0), und nimmt an, dass alle vorherigen Nachrichten bereits gelesen wurden):

"SELECT * FROM message WHERE from=$user_id OR to=$user_id WHERE $msg_id>$last_msg_id" 

oder wir nehmen nur Kenntnis von der letzten Eingabezeit von dem Benutzer und Abfrage alle neue Nachrichten von da an:

"SELECT * FROM message WHERE from=$user_id OR to=$user_id WHERE when>='".date('Y-m-d H:i:s',$last_input_time)."' " 

Wenn Sie eine Konferenz- oder Forum-Lauffläche Ähnliches Vorgehen und die Notwendigkeit, zu verfolgen, wer die Nachricht gelesen hat oder nicht, müssen Sie möglicherweise alle beteiligten Benutzer im Auge behalten.

Angenommen, es wird nicht hundert Leute in einer "Multi-User-Konferenz" geben, würde ich mit einer Tabelle für Nachrichten gehen und den "comma-separated and wrapped list" Trick verwende ich viel zum Speichern von Tags.

id autoincrement (again, no need for a separate message id) 
your usual: sent_at, title (if you need one), content 
sender (int) 
recepients (I'd go with varchar or shorter versions of TEXT; whereas TEXT or BLOB gives you unlimited number of users but may have impact on performance) 
readers (same as above) 

Das Geheimnis für recepients/Leser Feld ist sie durch Kommata getrennte ID-Liste und wickeln Sie es in Kommas wieder aufzufüllen (Ich werde in warum später dulge).

Sie müssten also IDs von Empfängern wieder in einem Array sammeln, z. $ Recepients = array (2,3,5) und ändern Sie Ihre Einlage:

"INSERT INTO table (sent_at,title,content,sender,recepients) VALUES(NOW(),'$title','$content',$sender_id,',".implode(',', $recepients).",')" 

Sie erhalten Tabellenzeilen wie
... Absender | empfänger
...           1 | , 2, // Einzelbenutzernachricht
...           1 | , 3,5, // Multi-User-Nachricht

alle Nachrichten für einen Benutzer mit der ID von $ user_id = 2 Sie mit

SELECT * FROM table WHERE sender=$user_id OR INSTR(recepients, ',$user_id,') 

Bisher gehen wählen wir die implodierte Liste der recepients gewickelt, z.B. "5,2,3" wird zu ", 5,2,3", und INSTR sagt hier, ob ', 2' irgendwo als Teilstring enthalten ist - da nach '2', ', 2' oder '2 gesucht wird, "könnte Ihnen z. B. falsche Positive geben' 34,56', '1 **, 2 34', '9,45 2, ** 89' dementsprechend - deshalb mussten wir die Liste an erster Stelle einpacken.

Wenn der Benutzer liest/seine/ihre Nachricht erhält, hängen Sie ihre ID in die Liste Lesern wie:

UPDATE table SET readers=CONCAT(',',TRIM(TRAILING ',' FROM readers),',$user_id,') WHERE id=${initial message_id here} 

die Ergebnisse:

... Absender | Empfänger | Leser
...           1 | , 2,               | , 2,
...           1 | , 3,5,           | , 3,5,2,

Oder wir können nun die erste Abfrage Hinzufügen einer Spalte „is_read“ in den Zustand ändern, ob der Benutzer zuvor die Nachricht gelesen oder nicht:

SELECT * FROM table WHERE INSTR(recepients, ',$user_id,'),INSTR(readers, ',$user_id,') AS is_read 

sammeln sich die Message-IDs aus das Ergebnis und aktualisieren Sie die "Receipents" -Felder mit einem einzigen Schritt

"UPDATE table SET readers=CONCAT(',',TRIM(TRAILING ',' FROM readers),',$user_id,') WHERE id IN (".implode(',' ,$received_msg_ids).")" 
+0

Danke für die Antwort, ich mag ein bisschen wie die "verpackte Liste" Trick, jedoch habe ich Eine Frage: Wie würde ich mit dieser Methode auch einen Zeitstempel für den Zeitpunkt erfassen, zu dem eine Nachricht tatsächlich gelesen wurde, also anders als nur "is_read" zu verfolgen, möchte ich auch "when_read" von jedem Empfänger verfolgen. – Dodinas

0

Ja. Du würdest auto_increment definitiv auf beide IDs setzen.

Um die message_id setzen Sie es programmatisch dort einfügen würde.

Ihre Abfrage würde wie folgt aussehen:

mysql_query("INSERT INTO `tblpm` (title, content, sender_id, date_sent) VALUES ('$subject', '$message', '$sender', NOW())"); 

Hinweis ist es das gleiche! Wenn die ID auf auto_increment gesetzt ist, wird es die ganze Magie für Sie tun.

+0

Vielen Dank für die Antwort. Können Sie näher erläutern, was Sie meinen, indem Sie "Message_id" programmatisch einfügen? Danke. – Dodinas

0

Im Klar PHP/Mysql nennt, mysql_insert_id() gibt den Auto-erhöhte Wert aus der vorherigen INSERT-Operation

So, können Sie die Mitteilung einzufügen, sammeln die neu ID generiert und stellen diesen Wert in der anderen Tabelle.

0

persönlich in Ihrem Fall (vorausgesetzt, das Beispiel nicht vereinfacht, und es ist nicht mehr kann ich nicht sehen) Ich würde speichern die Daten aus beiden dieser Tabelle in einer einzigen Tabelle, da sie in direktem Zusammenhang zu stehen scheinen:

tbl_pm tbl:

message_id

date_sent

Titel

Inhalt

Status ENUM ('ungelesen', 'lesen') STANDARD 'ungelesen'

SENDER_ID

receiver_id

So können Sie mit so etwas wie die oben am Ende, es nicht unbedingt nötig ist für der Join als die Beziehung wird immer 1 zu 1 sein?Sie haben in der Tabelle tbl_pm gelesen/ungelesen, was sicherlich pro Empfänger geändert werden würde, was bedeutet, dass Sie eine Kopie der Nachricht für jeden Empfänger speichern müssen. vielleicht soll staus in der tbl_pm-info-tabelle stehen.

Wenn Sie in beide Tabellen einfügen möchten, versuchen Sie es mit last_insert_id() innerhalb einer Abfrage oder mysql_insert_id() wie oben erklärt, von innerhalb von PHP.

0

ich wahrscheinlich etwas Ähnliches tun würde, in welchem ​​gavin empfohlen, aber wenn Sie Nachrichten Gewinde wollte, dann würden Sie einen anderen Schlüssel hinzufügen müssen, wie folgt aus:

private_messages 
- title (text) 
- date (timestamp) 
- content (text) 
- status (enum) 
- sender_id (int) 
- receiver_id (int) 
- parent_message_id (int) 

Dann könnte man ohne eine verschachtelte Nachrichten haben separate Tabelle oder System.

1

Sie sollten sich nicht auf automatische Inkrementierung beider IDs verlassen, da zwei Benutzer fast gleichzeitig zwei Nachrichten posten können. Wenn das erste Skript Daten in die Tabelle tbl_pm einfügt, kann das zweite Skript die beiden Einfügungen tbl_pm und tblpm_info ausführen, bevor das erste Skript seine Einfügung tblpm_info abgeschlossen hat. Die beiden Datenbankeinfügungen des ersten Skripts haben unterschiedliche IDs.

Abgesehen davon scheint Ihre Datenbankstruktur für die vorliegende Aufgabe nicht gut organisiert. Angenommen, Ihre Nachrichten könnten sehr lang sein und an eine sehr große Anzahl von Benutzern gesendet werden, wäre es ideal, den Nachrichteninhalt einmal gespeichert zu haben und für jeden Empfänger einen ungelesenen Status, eine Lesezeit usw. zu haben. Beispiel:

CREATE TABLE `pm_data` (
    `id` smallint(5) unsigned NOT NULL auto_increment, 
    `date_sent` timestamp NOT NULL, 
    `title` varchar(255) 
    `sender_id` smallint(5) unsigned, 
    `parent_message_id` smallint(5) unsigned, 
    `content` text, 
    PRIMARY_KEY (`id`) 
); 
CREATE TABLE `pm_info` (
    `id` smallint(5) unsigned NOT NULL auto_increment, 
    `pm_id` smallint(5) unsigned NOT NULL, 
    `recipient_id` smallint(5) unsigned, 
    `read` tinyint(1) unsigned default 0, 
    `read_date` timestamp, 
    PRIMARY_KEY (`id`) 
); 

Erstellen Sie diese beiden Tabellen und beachten Sie, dass beide einen ID-Wert für die automatische Inkrementierung haben, aber die Info-Tabelle hat auch ein pm_id-Feld, das die ID-Nummer der Datenzeile enthält bezieht sich darauf, dass Sie sicher sind, dass jede Zeile einen Primärschlüssel in der "Info" -Tabelle hat, aus dem Sie auswählen können.

Wenn Sie eine echte relationale Datenbank mit MySQL einrichten möchten, stellen Sie sicher, dass Ihre Engine auf InnoDB eingestellt ist. Dadurch können Beziehungen zwischen Tabellen eingerichtet werden, wenn Sie beispielsweise etwas in die 'Info' einfügen. Tabelle, die auf eine pm_id verweist, die nicht in der Tabelle 'data' vorhanden ist, wird die INSERT fehlschlagen.

Sobald Sie eine Datenbankstruktur ausgewählt haben, dann würde Ihre PHP-Code in etwa so aussehen:

<?php 
// Store these in variables such that if they change, you don't need to edit all your queries 
$data_table = 'data_table'; 
$info_table = 'info_table'; 
mysql_query("INSERT INTO `$data_table` (title, content, sender_id, date_sent) VALUES ('$subject', '$message', '$sender', NOW())"); 
$pmid = mysql_insert_id(); // Get the inserted ID 
foreach ($recipent_list as $recipient) { 
     mysql_query("INSERT INTO `$info_table` (pm_id, recipient_id) VALUES ('$pmid', '$recipient')"); 
}