|
|
Sitemap |
Ein Blog-Eintrag von Christian S. (Di 01.12.09 23:48)
Views: 1141644
|
Hallo!
Einleitung
Wie Ihr hoffentlich bemerkt habt, gibt es auch dieses Jahr wieder ein Adventsgewinnspiel. Vorher wurde - in einigen Monaten mehr, in mehreren Monaten weniger - die Software überarbeitet. Nach außen hin tatsächlich eher weniger als mehr.
Doch diese Überarbeitung der Gewinnspielsoftware ist viel mehr. Sie dient mir als Test für gleich zwei große Umstellungen, die nach und nach die gesamte EE-Software erreichen werden:
1. Die Umstellung von mysql auf mysqli.
2. Die Umstellung der Software auf einen objektorientierten Ansatz.
Die Quiz-Software ist der ideale "Spielplatz", um Patterns zu entwickeln, wie beide Ansätze am Besten in der Forensoftware genutzt werden. Zum einen ist die Gewinnspielsoftware ein fast abgeschlossenes System, sodass ich nicht direkt Klassen für so ziemlich alles anlegen muss und sie ist kein kritisches System der Forensoftware. Zum anderen bietet die Gewinnspielsoftware aber eine große Menge an miteinander verbundenen Tabellen, womit ich auch testen konnte, wie man komplexe Anfragen in einer OOP-Umgebung umsetzt.
Das Problem Okay, eines der Probleme
Mein Ziel ist es, dass außerhalb der Klassen keine SQL-Abfragen mehr in den Dateien vorkommen. Alle Abfragen an die Datenbank werden aus den Klassen über Prepared Statements durchgeführt und geben Instanzen dieser Klasse zurück.
Ist dies bei einfachen Abfragen noch gut zu realiseren, z.B. mit einem einfachen
Quelltext 1:
| $quiz =& Quiz::FromID($id); |
, wird es bei SQL-Statements wie dem Folgenden schon kniffliger, das performant umzusetzen:
SQL-Anweisung 1:
| SELECT * FROM prizes, products WHERE quiz_prize_quiz_id = 20 AND quiz_prize_product_id = quiz_product_id ORDER BY quiz_product_id DESC |
Man könnte jetzt natürlich in der Prize- oder der Product-Klasse eine entsprechende Methode anlegen, welche dann das gwünschte Ergebnis liefert. Aber irgendwie "schmeckte es komisch", für jeden Spezialfall eine Methode anzulegen.
Wie also weiter machen? Meine erste Version war die folgende:
Quelltext 1: 2: 3:
| $prizes =& Prize::FromQuizId(20); $productIds = ArrayHelper::Select($prizes, "GetProductID"); $products =& Product::FromIds(productIds); |
Das ist natürlich zum einen nicht so gut lesbar (und die Sortierung ist noch nicht mal drin!), zum anderen verdoppelt es die Anzahl der nötigen SQL-Anfragen. Während das bei der Quizsoftware noch näherungsweise wurscht ist, wäre eine Verdopplung der SQL-Anfragen bei der viewtopic.php schon ziemlich übel gewesen.
Die (wahrscheinlich nicht endgültige) Lösung
Kurzzeitig habe ich mich mit der Verwendung eines fertigen ORM-Systems wie Doctrine auseinander gesetzt (dank an Kha für den Tipp), fand das dann aber doch irgendwie überdimensioniert und, für die Produktivität ein Desaster, IntelliSense für die Daten-Klassen war damit nicht möglich (zumindest, soweit ich gesucht habe, vielleicht gibt's da ja doch was).
Die aktuelle Lösung sieht nun so aus, dass ich eine eigene kleine Klasse geschrieben hat, mit der ich Abfragen an die Datenbank abwickeln kann. Man baut sich über diese Klasse das Query zusammen und nach Ausführung gibt die Klasse dann Instanzen der Datenklassen zurück. Hier mal das Beispiel von oben:
Quelltext 1: 2: 3: 4: 5:
| $rows = $query ->Select("Prize")->Where("Prize::QuizIDColumn", array("i", 20)) //der zweite Parameter (rechte Seite eines Vergleichs) ist ein Array, wird also als Parameter an das prepared statement gebunden ->Select("Product")->Where("Product::IDColumn", "Prize::ProductIDColumn") ->OrderBy("Product::IDColumn", "DESC") ->Execute(); |
Das resultierende Array sieht dann so aus, dass für jede Ergebniszeile, die MySQL ausspuckt, eine Zeile in $rows angelegt wird. Innerhalb dieser Zeile kann ich auf die dem Ergebnis entsprechenden Instanzen zugreifen: $rows[0]["Product"]->GetName(). Der Vorteil dieser Klasse ist, dass ich beliebige Queries an die Datenbank senden kann und typensicher wieder Instanzen der Datenklasse zurück bekomme.
Die Klasse ist natürlich ein "work in progress". Es gibt vieles, was sie noch nicht kann. Die Where-Statements sind aktuell auf Prüfung auf Gleichheit beschränkt, jede Klasse darf nur einmal vorkommen, usw. Aber sie ist bereits jetzt eine sehr große Hilfe.
Schlusswort
Die Quiz-Software hat sich als sinnvolles Testfeld für eine weitreichende Umstellung der Forensoftware erwiesen. Die Komplexität des Systems lässt es zu, Probleme, die auch später auftreten würden, jetzt schon zu erkennen, während die geringere Größe (= Anzahl der Klassen) es möglich macht, auch grundlegende Änderungen der Herangehensweise noch ohne allzu großen Aufwand umzusetzen.
Ich hoffe, dass mir die Quiz-Software in dieser Hinsicht noch gute Dienste leisten wird.
Grüße,
Christian
Kommentar von elundril (Di 01.12.09 23:58)
Respekt, da hast du dir einiges vorgenommen!
Kommentar von BenBE (Mi 02.12.09 00:11)
Auf jeden Fall netter Ansatz für den Bau von Statements. Da hat einer zu viel C# programmiert
Dieser Kommentar endet in gestern
Kommentar von jfheins (Sa 05.12.09 11:57)
Hab nen kleinen Bug gefunden ^^
Wenn man das Spiel ausgewählt hat (da wo man nochmal auf "spielen" klicken muss) steht oben:
"Teilnahme möglich vom 01.12.2009 00:00 Uhr bis 06.12.2009 23:55 Uhr (Endet in Gestern)"
Kommentar von Christian S. (Sa 05.12.09 12:25)
Bugmledungen bitte weiterhin über die passenden Sparten erstellen!
Ich habe den Bug (genau wie den Bug "Beginnt in gestern") unter Artenschutz gestellt. Bei "Beginnt in gestern" hatte ich sogar einen entsprechenden Hinweis hinterlassen, den gibt's jetzt bei dem Bug auch.
|
|