threaded forum mit db(mysql) und perl
jörg
- programmiertechnik
Hi,
ich versuche ein threaded forum zu realisieren (perl) und stecke bei der thread-darstellung fest. ich speichere die beiträge in einer mysql-db ab. mein erster gedanke war ein tabelle zu verwenden, irgendwas in der art:
CREATE TABLE forum (
frm_id int, # primärschlüssel
parent_id int, # fremdschlüssel auf den vater
thread_id int, # fremdschlüssel auf den gesamten thread
pckgs_id int, # fremdschlüssel auf das forumsthema
# -> soll verschiedene themen geben
name text,
posting text,
...
)
thread_id ist vom datenbanktechnischen nicht unbedingt nötig, ist aber einfacher, wenn ich es mitabspeichere.
ich würde gerne das ganz mit den richtigen einrückungen in html darstellen, kriege das script aber nicht hin.
hat jemand eine idee (skript oder ablaufplan) oder einen link?
gruss und danke
jörg
Hi,
ich würde gerne das ganz mit den richtigen einrückungen in html darstellen, kriege das script aber nicht hin.
Sorry für die evtl. blöde Nachfrage, aber was genau willst du wissen?
Blind geraten:
Du hast ein Forum mit Hauptthreads und diese Hauptthreads haben Unterthreads, welche
sich entweder auf den Hauptthread beziehen oder auf einen anderen Unterthread innerhalb des
Hauptthreads. Und nun willst du wissen, wie du aus dem Hinweis auf den Vorgänger auf
die Einrückung schließen kannst?
bye eddie
hi,
mein problem liegt in der darstellung eines thread. die darstellung soll ähnlich dem selfhtml-forum sein - also mit einrückungen in der art, dass man den richtigen vater und die dazugehörigen kinder richtig gruppiert sieht. dabei ist es erstmal egal, ob ich verschiedene threads habe, dass kann ich ja einfach im sql statement mit einer
... where thread_id = $variable
einschränken.
also mein problem liegt tatsächlich nur in der darstellung des threads und in der (praktikalbelsten) db-abbildung.
cu und danke,
jörg
Hi,
mein problem liegt in der darstellung eines thread. die darstellung soll ähnlich dem selfhtml-forum sein - also mit einrückungen in der art, dass man den richtigen vater und die dazugehörigen kinder richtig gruppiert sieht.
dann würde ich es wie dieses Forum machen: hier werden definitionslisten misbraucht.
Meiner meinung nach reicht die verwendug verschachtelter <ul></ul> aus, auch wenn es
wohl nicht 4.01 validierbar ist.
Also,
<ul>Vaterthread
<ul>Erster sohn</ul>
<ul>Zweiter Sohn
<ul>Sohn des Zeiten</ul>
</ul> <!-- zweiten schliessen -->
</ul> <!-- ersten schliessen -->
wichtig ist nur, dass du alle wieder zumachst.
<ul> verträgt sich mit css somit kannst die dem Vater noch andere fonts, color, etc. zuweisen
als den Söhnen. Ich schreib mal Söhnen/Töchtern, nicht dass es noch ärger gibt ;-)
HTH,
bye eddie
Hi,
<ul>Vaterthread
<ul>Erster sohn</ul>
<ul>Zweiter Sohn
<ul>Sohn des Zeiten</ul>
</ul> <!-- zweiten schliessen -->
</ul> <!-- ersten schliessen -->
danke, wie muss mein script aber aussehen, damit ich weiss, welche eintrag sohn des zweiten etc ist. darin liegt das problem: die einträge in der richtigen sortierung und die richtige hierarchiestufe der einträge rauszubekommen.
danke
jörg
Hallo !
danke, wie muss mein script aber aussehen, damit ich weiss, welche eintrag sohn des zweiten etc ist. darin liegt das problem: die einträge in der richtigen sortierung und die richtige hierarchiestufe der einträge rauszubekommen.
Vielleicht hilft es dir, dich an einem bereits existierenden Skript zu orientieren.
Mein Tip: http://www.phorum.org, eines der wenigen PHP-/MySQL-Forumskripte, die auch eine Darstellung in Baumstruktur anbieten.
Dieses ist zwar - wie gesagt - in PHP programmiert, aber dir ging es ja in erster Linie um den Aufbau der DB und SQL-Abfragen.
Und wer Perl-Quelltexte versteht, sollte auch PHP-Quelltexte durchschauen können. ;-)
Vielleicht kannst du dir ja etwas passendes abschauen.
HTH
Gruß,
kerki
Hallo,
Dieses ist zwar - wie gesagt - in PHP programmiert, aber dir ging es ja in erster Linie um den Aufbau der DB und SQL-Abfragen.
Und wer Perl-Quelltexte versteht, sollte auch PHP-Quelltexte durchschauen können. ;-)
Vielleicht kannst du dir ja etwas passendes abschauen.
Vielen Dank!
Auf den ersten Blick scheinen die Sourcen einiges herzugeben (was ich auch verstehe). Ich werde mal in mich gehen und heute abend ein bissle schmökern.
Viele Grüsse
jörg
Hi Jörg,
ich hatte deine Anfrage bezüglich des gesuchten Algorithmuses ganz vergessen, sorry. Kerki hat dir nun vorgeschlagen, die Infos aus den Quelltexten zum "PHP-phorum" zu ziehen.
Ich hatte mich mal mit dem Problem rumgeschlagen und hatte mir diesen Algorithmus hier ausgedacht.
Der erste Teil ist eine theoretische Abhandlung im 2.Teil gehts dann mittels einer HTML-JS-Datei um ein programmiertechnisches Beispiel. Das Problem ist es dann, die Daten in einer passenden Form aus der DB zu holen und sie dem Algorithmus zur Verfügung zu stellen, was aber gehen sollte.
Sei nicht böse, dass ich erst so vorsichtig gefragt habe, aber dir zu erklären, was zu tun ist, ist 'ne heiden arbeit. Ich weis, wie es geht, aber es jemanden zu erklären ist besonders bei dieser Sache ein Problem. Es ist ein typischer Fall von eine Nacht wach liegen, und dann auf die Lösung kommen, nachdem man schon 14 Tage drüber nachdenkt. Nicht erschrecken, der Thread ist lang, sehr lang. Lies ihn dir bitte genau durch und frag dann nach.
Ich kann dir keine Perllösung aus dem Ärmel schütteln, aber ich habe das Problem mal mit JavaScript gelöst, da ich der Meinenug war/bin: der User hat RechenPower - soll er sie auch nutzen :-)
Nur zur Vorwarnung, die Lösung ist zu 100% auf meinem Mist gewachsen, d.h. möglicherweise gibt es deutlich performantere oder einfachere, Ich habe sie von niemanden nachprüfen lassen. Allerdings habe ich auch nie einen anderen Algorithmus gefunden. Aber sie funktioniert, ich habe sie in 3 Foren im Einsatz. Meine Foren sind nicht SQL-basiert, die Daten werden in Form von JavaScript-Arrays an den User gesendet und bei diesem clientseitig in Divs geschrieben, wie gesagt um den Server zu entlasten. Es ändert nichts am Prinzip: Du hast den Vaterthread und seine Söhne und diese Söhne haben einen Zeiger auf den Thread, auf den sie sich beziehen.
Die Katze beist sich in den Schwanz. Warum? Du musst als erstes die Reihenfolge der Söhne ermitteln. Das ist so schwierig, weil du beim Vater anfängst und dann theoretisch jeden weiteren fragen musst, ob er sich auf den Vater bezieht. Aus denen, die sich auf den Vater beziehen, musst du dann den aktuellsten aussieben. Diese Prozedur ist für jeden Sohn zu wiederholen. Dass das natürlich Wahnsinn ist, kannst du dir vorstellen. Ein Performancekiller vom Feinsten. Einfacher wäre es, beim Letzten anzufangen. Allerdings muss man vorher rausfinden, welcher der Letzte (in der Baumansicht) ist. Und das kannst du unmöglich wissen, womit sich die Katze in den Schwanz beist.
Der folgende Ansatz soll zeigen wie es trotzdem, und sogar erstaunlich schnell geht, wenn man das Problem 2-dimensional angeht.
-->Bekannt sein muss die Ordnugsnummer des Sohnes, die sich aus der Postingreihenfolge ergibt.
-->Bekannt sein muss die Ordnungsnummer des Sohnes, bzw. Vaters, auf den sich das aktuelle Posting bezieht, im Nachfolgenden als Referer bezeichnet
( 0.) Vaterthread (kein Bezug, als -1 gekennzeichnet) (12.) Sohn ( 0) ( 4.) Sohn ( 0) ( 8.) Sohn) ( 4) ( 2.) Sohn ( 0) (19.) Sohn ( 2) (23.) Sohn (19) (25.) Sohn EOF(19) (14.) Sohn ( 2) ( 9.) Sohn ( 2) (11.) Sohn ( 9) (10.) Sohn ( 9) (17.) Sohn (10) ( 3.) Sohn ( 2) ( 5.) Sohn ( 3) ( 6.) Sohn ( 5) (11.) Sohn ( 6) (15.) Sohn (13) (16.) Sohn (15) (18.) Sohn (16) (20.) Sohn (18) (21.) Sohn (20) (22.) Sohn (21) (24.) Sohn (22) ( 1.) Sohn ( 0) ( 7.) Sohn ( 1)
Weitere logische Bedingung ist, dass sich die Nummer 3 zB. unmöglich auf die Nummer 7 beziehen kann, da die 3 ja vor der 7 geschrieben wurde. Nun kommt der schwierige Teil, die Sortierung. Nach langer Überlegung bin ich auf die Idee gekommen, dass eine eindimensionale Variante zu lange dauert, d.h. zu viele if()-abfragen. Deshalb habe ich das Problem 2-Dimensional gelöst. Ich versuche dir den Ansatz mal grafisch zu vermitteln. Wir beginnen mit einem leeren 2-dimensionalen Array, welches so groß ist, wie die Anzahl der Söhne + den Vater, also im Beispiel = 25, aber beginnend mit 0 also 0-24, ok. Um genau zu sein, erzeugen wir ein Array, dass 25 Elemente lang ist, und jedes Element ist wieder ein Array, welches bislang nur einen Eintrag hat: sein 0.Element ist seine Ordnungszahl.
structure[ 0] = [ 0] structure[ 1] = [ 1] structure[ 2] = [ 2] structure[ 3] = [ 3] structure[ 4] = [ 4] structure[ 5] = [ 5] structure[ 6] = [ 6] structure[ 7] = [ 7] structure[ 8] = [ 8] structure[ 9] = [ 9] structure[10] = [10] structure[11] = [11] structure[12] = [12] structure[13] = [13] structure[14] = [14] structure[15] = [15] structure[16] = [16] structure[17] = [17] structure[18] = [18] structure[19] = [19] structure[20] = [20] structure[21] = [21] structure[22] = [22] structure[23] = [23] structure[24] = [24] structure[25] = [25]
Jetzt passiert folgendes, wir arbeiten rückwärts, und hängen das jeweilige Array an das jenige an, auf welches es referenziert(siehe Samplethread). Also die 25 referenziert auf die 19, die 24 auf die 22, 23->19, 22->21, 21->20, 20->18, 19->2 usw.:
[ 0] [ 0] [ 0] [ 0] [ 0] [ 0] [ 0] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 1] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2] [ 2,19,25,23] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 3] [ 4] [ 4] [ 4] [ 4] [ 4] [ 4] [ 4] [ 5] [ 5] [ 5] [ 5] [ 5] [ 5] [ 5] [ 6] [ 6] [ 6] [ 6] [ 6] [ 6] [ 6] [ 7] [ 7] [ 7] [ 7] [ 7] [ 7] [ 7] [ 8] [ 8] [ 8] [ 8] [ 8] [ 8] [ 8] [ 9] [ 9] [ 9] [ 9] [ 9] [ 9] [ 9] [10] [10] [10] [10] [10] [10] [10] [11] [11] [11] [11] [11] [11] [11] [12] [12] [12] [12] [12] [12] [12] [13] [13] [13] [13] [13] [13] [13] [14] [14] [14] [14] [14] [14] [14] [15] [15] [15] [15] [15] [15] [15] [16] [16] [16] [16] [16] [16] [16] [17] [17] [17] [17] [17] [17] [17] [18] [18] [18] [18] [18] [18,20,21,22,24] [18,20,21,22,24] [19] [19,25] [19,25] [19,25,23] [19,25,23] [19,25,23] [20] [20] [20] [20] [20] [21] [21] [21] [21] [21,22,24] [22] [22] [22,24] [22,24] [23] [23] [23] [24] [24] [25]
wichtig ist immer, dass das ganze Array an das Referenzierende angehangen wird.
Aus der erfolgten Sortierung ergibt sich 1 Array, welches in sich nun die Reihenfolge der Söhne beinhaltet, dieses Array ist das erste Array in structure, also structure[0].
Sehen wir uns das an: erste Spalte ist die Reihenfole, dahinter kommt die Abbildung:
0 | ( 0.) Vaterthread (kein bezug, als -1 gekennzeichnet) 12 | (12.) Sohn ( 0) 4 | ( 4.) Sohn ( 0) 8 | ( 8.) Sohn) ( 4) 2 | ( 2.) Sohn ( 0) 19 | (19.) Sohn ( 2) 23 | (23.) Sohn (19) 25 | (25.) Sohn EOF(19) 14 | (14.) Sohn ( 2) 9 | ( 9.) Sohn ( 2) 11 | (11.) Sohn ( 9) 10 | (10.) Sohn ( 9) 17 | (17.) Sohn (10) 3 | ( 3.) Sohn ( 2) 5 | ( 5.) Sohn ( 3) 6 | ( 6.) Sohn ( 5) 13 | (13.) Sohn ( 6) 15 | (15.) Sohn (13) 16 | (16.) Sohn (15) 18 | (18.) Sohn (16) 20 | (20.) Sohn (18) 21 | (21.) Sohn (20) 22 | (22.) Sohn (21) 24 | (24.) Sohn (22) 1 | ( 1.) Sohn ( 0) 7 | ( 7.) Sohn ( 1)
Nun stellt sich ja vielleicht die Frage, warum haben wir dabei nicht gleich die Einrückunstiefe mitermittelt und z.B einen Array "level" geschaffen, den wir bei der Ausgabe nur abfragen müssen. Der Grund liegt in der Performance: Wenn wir zum Beispiel von Sohn 2 zu Sohn 19 gehen, brauchen wir keinerlei Information über die Einrückung, denn da sich die 19 auf die 2 bezieht ist klar, dass wir nur eine Stufe tiefer gehen müssen. Wir merken uns nur, wie oft wir das machen - in der Variable "level". Die wird jedesmal um einen erhöht.
Nur wenn wir z.B. von der 17 auf die 3 gehen, müssen wir die Einrücktiefe gesondert ermitteln, um die Anzahl der schließenden "</ul>"'s zu rauszubekommen. So geht's:
Wir setzen einen Wert "nextlevel = 0". Dieser Wert wird am Ende der Prozedur den level des folgenden Sohnes haben. Wir erfragen den referer des naechsten Sohns, dann erfragen wir den referer von dem und so weiter bis wir beim Vater sind (referer-Wert = -1), jedes mal zaehlen wir dabei den nextlevel-Wert einen hoch. Aus der Differenz des aktuellen level und dem nextlevel erhalten wir die Anzahl der schliessenden </ul>'s.
That's it. Puh, damit sind wir mit der Theorie durch :-). Im nächsten Thread steht eine auskommentierte HTML-Datei. Komplett in den Editor kopieren, abspeichern, austesten. Diese beinhaltet das programmiertechnische Konzept. Dieses Konzept sollte IMHO recht einfach auf jede andere Sprache umsetzbar sein. Das Problem besteht also mehr oder minder darin, die Daten in der benötigten Form aus der DB zu ziehen. Zur Erinnerung: du brauchst die Ordnungsnummer(Reihenfolge) und zu jedem Sohn die Nummer von dem, auf den er sich bezieht.
Viel Spass beim Probieren, bye eddie
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Baumerzeuger von Ed X</title>
<script>
// Das ist Samplecode, der noch im Betastadium ist
// brought to you by tobias kieslich, www.justdreams.de
/* #############################################################################
das sind Variablen, wie du solche Daten aus der DB kriegst, musst du selber
wissen ;-)
############################################################################# */
var thread = new Array(
"ich bin der Vater",
"ich bin der 1. Sohn",
"ich bin der 2. Sohn",
"ich bin der 3. Sohn",
"ich bin der 4. Sohn",
"ich bin der 5. Sohn",
"ich bin der 6. Sohn",
"ich bin der 7. Sohn",
"ich bin der 8. Sohn",
"ich bin der 9. Sohn",
"ich bin der 10. Sohn",
"ich bin der 11. Sohn",
"ich bin der 12. Sohn",
"ich bin der 13. Sohn",
"ich bin der 14. Sohn",
"ich bin der 15. Sohn",
"ich bin der 16. Sohn",
"ich bin der 17. Sohn",
"ich bin der 18. Sohn",
"ich bin der 19. Sohn",
"ich bin der 20. Sohn",
"ich bin der 21. Sohn",
"ich bin der 22. Sohn",
"ich bin der 23. Sohn",
"ich bin der 24. Sohn",
"ich bin der 25. Sohn (EOF)")
// hier drinne werden die Bezuege gespeichert, also thread[14] bezieht sich auf referer[14], alles klar?
var referer= new Array (-1,0,0,2,0,3,5,1,4,2,9,9,0,6,2,13,15,10,16,2,18,20,21,19,22,19);
/* #############################################################################
damit wird der Baum erzeugt
############################################################################# */
function buildStructure() {
var structure = []; // das 2 dimensionale array zur Ermittlung der Reihenfolge
for (var i=0; i<thread.length; i++) { // vorbereiten der arrays
structure[i] = []; // initialisieren des leeren structure-Arrays
structure[i][0] = i; // jedes einzelne Array hat als 0. Wert seine Ordnungsnummer
}
// diese einfache Schleife ermittelt die Reihenfolge der anzuzeigenden threads
// durch Anhaengen des jeweiligen Arrays an seinen Referer
for (var k=thread.length-1; k>0; k--) {
structure[referer[k]] = structure[referer[k]].concat(structure[k]);
}
// erzeuge einen order-Array um Uebersicht zu behalten
var order = structure[0];
// Testweise Ausgabe der Reihenfolge
alert(structure[0]);
// erzeuge eine mitlaufende Variable, die sich die aktuelle Einruecktife merkt
var level = 0;
// tree ist an dieser Stelle normalerweise leer; der besseren Lesbarkeit halber
// habe ich mal ein paar stylesheets spendiert
tree = "<style>\n ul {font: 12px Arial,Helvetica,sans-serif; color: #000000;}\n span.name{font: bold 13px Arial,Helvetica,sans-serif; color: #cc6600;}\n span.referer {font: bold 13px Arial,Helvetica,sans-serif; color: #6600cc;}\n span.tiefe {font: bold 13px Arial,Helvetica,sans-serif; color: #009900;}</style>\n\n";
// diese schleife zeichnet fuer die Zusammenstellung des HTML-codes verantwortlich
for (var i=0; i<thread.length; i++) {
// listeneintrag erzeugen - nicht schliessen !!
tree += "<ul><span class="name">" + thread[order[i]] + "</span> - bezieht sich auf: <span class="referer">" + referer[order[i]] + "</span> - Tiefe: <span class="tiefe">" + level + "</span><br>\n";
// Ausnahme wenn der Nachfolgende in der Reihenfolge sich nicht auf Aktuellen bezieht,
// muessen schliessende </ul>'s erzeugt werden, die Frage ist wieviele?
if ((i+1 != thread.length) && (referer[order[i+1]] != order[i])) {
// in diese Variable schreiben wir den ermittelten level des folgenden threads,
// denn die differenz des aktuellen level zum level des folgenden ergibt die
// Anzahl der schliessenden </ul>'s; nextlevel wird hier vorerst nur initialisert
var nextlevel = 0;
// Ab hier ermitteln wir den level des naechsten Sohns. Wie? Wir erfragen den referer
// des naechsten Sohns, dann erfragen wir den referer von dem und so weiter bis wir beim
// Vater sind (referer-Wert = -1), jedes mal zaehlen wir dabei den nextlevel wert einen hoch
var next = referer[order[i+1]];
while (next != -1) {
nextlevel++;
next = referer[next];
}
// Aus der differenz von level-nextlevel ergibt sich die Anzahl der schliessenden </ul>'s
// mittels einer for schleife wird das an "tree" angehangen
for (var c=0; c<=(level-nextlevel); c++) {
tree += "</ul>\n";
}
// Aktueller level ist natuerlich der des naechsten sohns
level=nextlevel;
} else {
// wenn wir die prozedur nicht brauchen, muss der level um 1 erhoeht werden,
// da ja ein neuer <ul> aufgemacht wurde
level++;
}
}
// Zum Schluss alle offenen <ul>'s schliessen !!
for (var c=0; c<level; c++) {
tree += "</ul>\n";
}
// Ausgabe
document.open;
document.write(tree);
document.close;
}
</script>
</head>
<body onload="buildStructure()">
</body>
</html>
Hallo Tobias!
WOW! Das nenn ich ein Posting! :-)
Vielen Dank für deine ausführlichen Erläuterungen.
Die werde ich mir auf jeden Fall ausdrucken und mal in Ruhe zu Gemüte führen.
Eine kleine Anmerkung aus Valid-HTML-Sicht:
<ol>/<ul> ohne <li> sind pfui! :-)
Eine Verschachtelung der Threads geht in jedem Fall valide durch
<ul>
<li>Thread 1 | Nein hier fehlt kein </li>
<ul>
<li>Antwort 1.1 | hier auch nicht
<ul>
<li>Antwort 1.1.1</li>
<li>Antwort 1.1.2</li>
</ul>
</li> | das steht hier
<li>Antwort 1.2</li>
</ul>
</li> | Das kommt erst hier!
<li>Thread 2
<ul>
<li>Antwort 2.1</li>
</ul>
</li>
<li>Thread 3</li>
</ul>
Es könnte allerdings sein, dass dadurch die Programmierung etwas schwieriger gerät. Da muss ich drüber schlafen.
Gruß,
kerki
Hi, Kerki,
Die werde ich mir auf jeden Fall ausdrucken und mal in Ruhe zu Gemüte führen.
wenn du dir schon die Mühe machst das ding zutesten ich sende dir mal
den Source etwas lesbarer zu.
Ansonsten liegt er auch hier:
http://www.justdreams.de/download/forumbaum.zip
Eine kleine Anmerkung aus Valid-HTML-Sicht:
<ol>/<ul> ohne <li> sind pfui! :-)
Ich weis, es ist auch erstmal nur zu testzwecken.
Es könnte allerdings sein, dass dadurch die Programmierung etwas schwieriger gerät. Da muss ich drüber schlafen.
Genau, deshalb habe ich mir mal die Variante hier im Forum angesehen.
das schein auf Dauer einfacher zu sein (man muss nicht so viele
Variablen mitlaufen lassen)
bye eddie, der sich auf jeden auf auf 'ne Meinung freut