Status: On Hold

No Comments

Im Augenblick ist nicht viel los hier. Ich habe alle Features soweit implementiert und warte nun auf weitere API-Veröffentlichungen von Seiten Blizzards. ;-)

Lediglich das Wiki ist noch aufzuarbeiten und zu übersetzen. :-P

Datenkanal Klassennamen als Arrayschlüssel = bad

No Comments

Heute nur eine Kleinigkeit… ;-)

Ich habe den Initialisierungsprozess des Moduls leicht angepasst. Die Klassennamen der Datenkanäle sind nun nicht mehr der Schlüssel des assoziativen Arrays der Datenkanäle. Somit können nun auch mehrere Datenkanäle der gleichen Klasse registriert werden.

Ich frage mich inzwischen sowieso wie ich auf diese seltsame Idee gekommen bin. :-D

Mehrfachabfragen, Revisited

No Comments

Der gestrige Abend war sehr produktiv. Ich habe das Konzept des Hashings wieder über den Haufen geworfen und bin einen Schritt zurück gegangen um die Konsistenz zu wahren. Dies resultierte in folgender erfolgreichen Herangehensweise:

  1. Da ich die Parameter-Tupel ja als indiziertes Array erwarte, sind die Tupel somit schon vom externen System aus eindeutig identifiziert, selbst wenn dies nur implizit durch ein Weglassen der Schlüssel geschiet.
  2. Somit wäre die Konsistenz und auch der Bedienkomfort am größten wenn diese Schlüssel bei der Rückgabe der Datenobjekte identisch mit denen der zugeordneten Parameter wären.
  3. Um dies zu erreichen muss ich ein Ergebniss Objekt mit einem Parameter-Tupel vergleichen können, um zu ermitteln ob diese zusammen gehören:
    1. Erweiterung der Metadaten einer Daten ID um ein optionales Feld “param”, welches angibt ob dieser Daten ID ein Eingabeparameter zugeordnet ist, und falls ja, welcher Eingabeparameter dies ist.
    2. Eine öffentliche Methode “matchParams()” die zur WowData Klasse gehört. Diese erwartet ein Parameter-Tupel und prüft ob alle im Datenobjekt definierten Eingabeparameter auch im Tupel vorhanden sind und ob die Werte übereinstimmen.
  4. Nachdem diese Überprüfung nun stattfinden kann, habe ich eine Methode in “WowDataAccess” geschrieben welche ein Kanal-Ergebnis nimmt und mit einem Array von Parameter-Tupeln vergleicht und einen Ausschnitt aus diesem Array zurückliefert welches nur die Tupel enthält die auf kein Datenobjekt in der Ergebnismenge gepasst haben.
  5. Diese Teilmenge der Parameter-Tupel wird nun an den nächsten Datenkanal weiter gereicht. Und gleichzeitig werden die Schlüssel dieser Tupel gespeichert, um beim Schreibdurchlauf später auch nur die Daten zurück zu schreiben die in diesem Kanal nicht präsent waren.

Damit wären wir auch schon am Ziel angekommen. :-)

Mehrfachabfragen, Lazy oder Greedy

No Comments

Da ich mich in der letzten Woche mit Mehrfachabfragen beschäftigt habe, hier ein paar Eindrücke und Erkenntnisse zum Thema. :-)

Unter Mehrfachabfragen verstehe ich in diesem Zusammenhang ein Mitgeben von mehreren Parameter Tupeln, welche jeweils ein Datenobjekt eindeutig identifizieren. Diese werden dann an den Handler weitergegeben und dieser entscheidet dann ob er mit Mehrfachabfragen umgehen kann, oder nicht. Falls nicht, so wird die effektive Handler-Funktion durch den Wrapper pro Tupel einmal explizit aufgerufen, dies ist natürlich nicht performat, aber es simuliert ein identisches Verhalten für den Fall dass Mehrfachabfragen nicht supported werden.

Jetzt muss natürlich wieder auf den effektiven Wrapper der Handler geschaut werden. Denn sobald Mehrfachabfragen möglich sind muss man sich überlegen ob das Ganze “lazy” oder “greedy” ablaufen soll. ;-)

“Lazy” bedeutet in diesem Fall, dass eine Abfrage die mindestens ein Ergebnis findet einen Ausstieg aus der Kanaliteration gewirkt und nur die gefundenen Daten zurückgegebenen werden. Alle Daten die in diesem Kanal nicht vorhanden waren, werden nicht in tiefer liegenden Kanälen gesucht.

Wenn man jetzt “Greedy” Abfragen will, so muss man sich einigen Herausforderungen stellen:

  1. Identifizieren von Parameter Tupeln
  2. Zuordnen von Query Ergebnissen zu den Parameter Tupeln
  3. Zwischenspeichern von Ergebnissen bei der Kanaliteration damit das Modul weiß welche Datenobjekte in welchen Kanal gespeichert werden müssen

Lösungen:

  1. Eine Tupel ID wird per md5() und implode() erzeugt:
    $id = md5(implode($params));
  2. Das hier ist sozusagen gerade “Work in progress”. ;-)
    Am direktesten wäre es wohl diese Verknüpfung im Datenkanal zu handhaben, allerdings wäre dass dann ein Entwicklungs-Overhead beim Schreiben von neuen Datenkanälen. Ich werde wohl versuchen die Zuordnung tiefer im System einzubauen um die zusätzliche Logik aus den Datenkanälen heraus zu halten.
  3. Dies sollte sich nicht schwierig gestalten, man muss bei Writeback nur abfragen welche Datenobjekte relevant sind für den Kanal. Dies werde ich wohl über ein assoziatives Array abwickeln.

Adieu Interface, Hallo Handler

No Comments

Ich habe heute einen großen Block der bisher fest definierten Basisstruktur des Moduls ausgetauscht. Die Interfaces und Basisklassen der Datenkanäle, welche die einheitlichen Öffnen- und Schließen-Methoden definierten wurde entfernt und durch eine zentrale, vererbte, Methode in WowDataChannel mit dem verheißungsvollen Namen “handleWowData()” ersetzt.

Durch das Entfernen der abstrakten Vordefinition entfallen 2 Interfaces (TemplateWowDataChannelRead & TemplateWowDataChannelWrite) und 2 abstrakte Klassen (WowDataChannelRead & WowDataChannelReadWrite). Zudem ist es nun nicht mehr nötig sich für einen Kanaltyp beim Schreiben der Klasse zu entscheiden (Read oder ReadWrite).

An der Stelle dieser starren Hierarchie tritt die Methode “handleWowData()”. Diese durchläuft alle im Kanal registrierten Handler für eine bestimmte WowData Subklasse und Zugriffsmodus (“read” oder “write”) und ruft diese Handler mit den Parametern auf die von WowDataAccess übergeben wurden. Somit ist es nun möglich mehr als einen Handler auf eine WowData Subklasse und Zugriffsart zu registrieren. Dies ermöglicht zB dem Datenkanal WowDataChannelMySQL bestimmte Daten in eine Backup-Tabelle zu schreiben, oder zB. eine Log-Tabelle mit Daten über die durchgeführten Lese- und Schreibvorgänge zu führen ohne umständliche Programmierarbeit.

Im alten Konstrukt war es nötig für jeden möglichen, im Interface definierten, Datentyp eine (oder zwei im Falle von ReadWrite Kanälen) Methode anzulegen. Wenn der Datentyp vom Kanal nicht unterstützt wurde, musste man eben Dummymethoden mit “return(false);” schreiben damit sich PHP nicht wegen abstrakten Methoden bei der Instanziierung in die Ecke stellte. ;-)

Das neue Modell erlaubt es einem nur genau die Handler zu definieren die man auch wirklich braucht. Dies geschiet derzeit noch in der “init()” Methode des jeweiligen Datenkanals, aber ich denke ich werde das noch auslagern.

Hier ist der Ausschnitt aus der derzeitigen “init()” Methode des Battle.net Datenkanals:

/**
 * Registers the handlers for WowData subclasses
 */
$this->registerWowDataHandler(
	'WowDataRealm',
	'read',
	array(
		'multiSupport' => false,
		'handler'      => 'openRealm'
	)
);
$this->registerWowDataHandler(
	'WowDataIcon',
	'read',
	array(
		'multiSupport' => false,
		'handler'      => 'openIcon'
	)
);

Die beiden hier in “handler” referenzierten Methoden müssen natürlich im Datenkanal definiert worden sein. Hier ist die Parameter Signatur fest vorgegeben: Parameter 1 enthält den Klassennamen der WowData Subklasse und Parameter 2 die Eingabeparameter.