echo $begrüßung;
Models/Board/ // hier sind die Models vom Board drin.
Ein Model ist immer eine Klasse und bekommt nur eine Aufgabe zugewiesen wie "hole mir alle Postings aus der Datenbank" oder?
Letztlich ist es deine Entscheidung. Zerhack das Model nicht zu sehr. Welche Zusammenhänge und welche Unterschiede bestehen zwischen den Aufgaben der Board-Models? Es wird sicher eine Tabelle Kategorien und eine für Postings geben. Alle Kategorien-Aufgaben kommen in eine Klasse, alle Posting-Aufgaben in eine andere. Wenn die beiden am Ende zu wenig Code ergeben, als dass eigenen Klassen gerechtfertigt sind, wäre auch eine Zusammenlegung in eine Board-Klasse möglich. Wenn sich allerdings durch die anderen Teile des Projekts ergibt, dass dort einzelne Klassen sinnvoll sind, sollte man das Prinzip aus Konsistenzgründen überall anwenden.
Ich habe ja den diktatorischen FrontController. Sollte ich noch eine FrontView-Klasse anlegen?
Eine Front-Model klasse halte ich wohl für unsinnig.
Arbeitet ein Diktator selbst? Zumindest hat er für den Kleinkram sein Personal. Der vom ZF verteilt noch nicht mal die Requests selber sondern übergibt diese Aufgabe an Router und Dispatcher. Wenn im Gesamtlayout eine Navigation enthalten ist, deren Daten aus einer Datenhaltung ausgelesen werden, dann wäre das eine Aufgabe für einen Layout-ActionController. Wenn der FrontController die Ergebnisse aller Einzelaufgaben eingesammelt und sie mit einer leichten Handbewegung in das Gesamtkunstwerk eingebettet hat, steht er immer noch als großer Held da.
Alle Klassen im Ordner Helper sind statisch aber die DB_klasse setzt auf lazy Connect.
Arbeit die liegen bleibt ist nie vergebens. Man kann sogar einen Lazy Fetch implementieren.
Normalerweise fetcht die MySQL-API nach einem SELECT im Hintergrund still und leise sämtliche Daten der Ergebnismenge in einen Zwischenpuffer. Nur so sind ihr Aussagen wie die Anzahl der Ergebniszeilen möglich. Auf diesen Zwischenpuffer kann man nicht direkt zugreifen. Man muss immer brav selbst fetchen und bekommt Stück für Stück die Daten aus dem Zwischenpuffer. Als Model will man ja die Implementierungsdetails der Datenabfrage verbergen, also legt man ein Array an, in das man die Datensätze ablegt und schafft sich so einen zweiten Zwischenpuffer. Die View <del>rödelt</del><ins>iteriert</ins> meist nur einmal drüber und das wars. Klingt nach Verschwendung? Und besonders bei größeren Datenmengen nicht nach Performance-Optimum? Da widerspreche ich (mir) nicht. Den ersten Zwischenpuffer bekommt man weg, indem man eine ungepufferte Abfrage startet. mysql_unbuffered_query() lassen wir links liegen, wer mit Design Pattern hantiert kann auch mit der mysqli-Extension arbeiten. Leider ist die Prepared-Statements-Implementierung in mysqli für Wald- und Wiesen-Scripte optimiert und für eine generische API nicht besonders geeignet [1], also bleibt es beim mysqli::query(). Das bekommt als resultmode-Parameter MYSQLI_USE_RESULT verpasst. Die Fetch-Funktionen fetchen dann die Datensätze direkt vom Server. Der eigene Zwischenpuffer lässt sich umgehen, indem man sich der SPL bedient. Die bietet unter anderem das Iterator-Interface an. Das Model gibt also kein Array zurück sondern ein Objekt einer Klasse, die das Iterator-Interface implementiert hat. Beim Instantiieren bekommt das Objekt ein MySQLi_Result-Objekt übergeben. Und bei jedem next() wird davon ein Datensatz gefetcht. Ein foreach über ein Objekt einer Iterator implementierenden Klasse führt zu next()-Aufrufen. Ergebnis ist, dass die View "denkt", sie bekäme wie üblich ein Array mit Datensätzen und "foreacht" sie in die Ausgabe. Stattdessen macht es next() und fetch() direkt vom MySQL-Server.
Die Sache hat allerdings mindestens drei Haken. Wie implizit erwähnt, geht mit einer ungepufferten Abfrage kein mysqli_result->num_rows. Das heißt, es geht schon, liefert aber erst dann ein richtiges Ergebnis, wenn man alle Datensätze abgeholt hat. Und man muss ein Resultset erst komplett gefetcht haben, bevor man eine weitere Query absetzen kann. Wenn mehrere Querys von einem oder mehreren ActionControllern veranlasst werden sollen, muss man immer die passende View rendern lassen, bevor man die nächste Query starten kann. Doch damit hätten wir wieder einen Zwischenpuffer gefüllt. Der dritte Nachteil ist, man kann über das Ergebnis genau einmal iterieren, dann ist es weg, wenn man es sich nicht irgendwohin ablegt (zwischenpuffert).
Wenn also mehr als eine Query abgearbeitet werden soll, kommt man um einen Zwischenpuffer nicht umhin, aber es müssen nicht zwei werden. Nehmen wir also doch eine gepufferte Abfrage und verlagern nur den eigenen Fetch-Vorgang in das Iterator-Interface. Dann kann man auch mehrfach drüber iterieren, indem man beim rewind() ein mysqli_result::data_seek(0) ausführt.
[1] Prepared Statements wollen "echte" Variablen für das Bind der Platzhalterparameter und für das Bind des Resultsets. Ein Array anzubinden, um eine beliebige Anzahl an Parametern übergeben und eine beliebige Anzahl an Spalten im Resultset auffangen zu können, ist recht umständlich zu lösen. Zudem ist der Prepared-Statements-Mehraufwand gegenüber einem herkömmlichen Query-Fetch zu beachten, der sich erst bei Massendaten lohnt/rentiert.
echo "$verabschiedung $name";