Event-gesteuertes Export-Modul

Hallo zusammen,

ich bin ein kompletter Oxid-neuling und stehe vor der Aufgabe, ein Modul zum Datenexport von Kategorien und Produkten zu entwickeln.

Das Modul soll einerseits einen Komplett-Export aller Kategorien/Produkten erstellen können, andererseits aber auch inkrementelle Updates erzeugen.

Ich habe nun durch diverse Tutorials und Posts verstanden (hoffe ich), dass Oxid kein Event-Hanling-Mechanismus anbietet, der mich z.B. über Update-Vorgänge im Datenbestand unterrichtet. Nun war mein erster Gedanke, einfach die entsprechenden Speicher-Methoden (z.B. oxArticle::save()) der zugehöärigen Model-Klassen (t.B. oxArticle) zu überschreiben, damit ich - sobald ein Artikel aktualisiert wurde - dessen Daten an die Empfänger-Stelle weiterleiten kann.

Mir ist nur nicht ganz klar, wie das Oxid-Vererbungsmodell konkret arbeitet. Wenn der Shop z.B. noch ein weiteres Modul verwendet, welches ebenfalls die oxArticle-Klasse erweitert und dabei evtl. auch dieselben Methoden überschreibt, welcher Code wird dann konkret ausgeführt?
Meiner? Code vom anderen Modul? Beides? immer das vom zuletzt installierten Model? Oder kann ich das irgendwie steuern (vgl. final class oder important! in css)?

Für Hinweise zum sinnvollen Vorgehen bedanke ich mich schon mal im Voraus.

Marco

Hi Marco,

[QUOTE=neuwaerts;123218]Ich habe nun durch diverse Tutorials und Posts verstanden (hoffe ich), dass Oxid kein Event-Hanling-Mechanismus anbietet, der mich z.B. über Update-Vorgänge im Datenbestand unterrichtet[/QUOTE]
Ja, das hast du richtig verstanden! :slight_smile:

[QUOTE=neuwaerts;123218]Nun war mein erster Gedanke, einfach die entsprechenden Speicher-Methoden (z.B. oxArticle::save()) der zugehöärigen Model-Klassen (t.B. oxArticle) zu überschreiben, damit ich - sobald ein Artikel aktualisiert wurde - dessen Daten an die Empfänger-Stelle weiterleiten kann.[/QUOTE]
Würde ich auch so machen, guter Ansatz.

[QUOTE=neuwaerts;123218]Mir ist nur nicht ganz klar, wie das Oxid-Vererbungsmodell konkret arbeitet. Wenn der Shop z.B. noch ein weiteres Modul verwendet, welches ebenfalls die oxArticle-Klasse erweitert und dabei evtl. auch dieselben Methoden überschreibt, welcher Code wird dann konkret ausgeführt?
Meiner? Code vom anderen Modul? Beides? immer das vom zuletzt installierten Model? Oder kann ich das irgendwie steuern (vgl. final class oder important! in css)?[/QUOTE]
Bei den Vererbungen von OXID wird der Code aller Klassen ausgeführt, die eine Klasse extenden. Die Reihenfolge der Ausführung kannst du über den Adminbereich beeinflussen, indem du die Reihenfolge der Vererbungen änderst.

Beachten musst du nur, dass dein Klassenname natürlich unique ist.

Ich hoffe, das hilft dir erst mal weiter. :wink:

Moin, Kai.
Das hilft mir auf jeden Fall.

… mit Deinem Nachnamen würdest Du perfekt zu unserem Laden passen!

Eine Sache fällt mir da aber noch ein:

Wenn ich also oxArticle::save überschreibe mit ungefähr so etwas


public function save() {

    $ret = parent::save();

    // do magic export stuff here ...

    return $ret;
}

Und irgend ein anderes Modul überschreibt ebenfalls die save-Methode und ruft auch parent::save() auf, wird dann der Artikel nicht mehrfach gespeichert? Oder verstehe ich da was falsch?

Gruß,

Marco

[QUOTE=neuwaerts;123223]Und irgend ein anderes Modul überschreibt ebenfalls die save-Methode und ruft auch parent::save() auf, wird dann der Artikel nicht mehrfach gespeichert? Oder verstehe ich da was falsch?[/QUOTE]

Vollkommen korrekt :wink:

Das kann man jetzt so oder so verstehen ;). Wird nicht mehrfach gespeichert, wirklich gespeichert wird ja nur in oxbase, die Module bilden eine Vererbungskette, aufgerufen wird die save-Methode des letzten Moduls in der Kette, parent::save ruft das nächsthöhere auf, etc, bis zu oxbase, und das speichert dann.

Aber die Module erben ja nicht voneinander, sondern (in meinem Beispiel) alle von oxArticle.
D.h., wenn es zwei Module gibt, die jeweils oxArticle::save überschreiben und beide parent::save() aufrufen, wird doch die Verarbeitungskette zweimal durchlaufen. Folglich wird auch oxBase:.save() zweimal ausgeführt.

Ansonsten habe ich den Vererbungsansatz von Oxid wohl noch nicht richtig begriffen.

Ich reite da deswegen so darauf herum, weil ich für mein Modul unterscheiden können muss, ob ein Artikel beim Speichern gerade neu erzeugt oder lediglich aktualisiert wurde. Soweit ich das sehe, wird aber beides über oxArticle::save() abgehandelt.

Sollte also mein Modul nicht als erstes in der Verarbeitungskette sein, und ein anderes Modul existieren, welches im Falle eines neu erzeugten Artikels zuerst parent::save() aufruft, dann müsste in meinem Modul doch kein INSERT, sondern ein UPDATE erfolgen. Ansonsten gäbe es den neuen Artikel ja gleich doppelt.

Und hier befürchte ich jetzt das Problem, dass mein Modul (in bestimmten Fällen), gar nicht mitbekommt, dass es sich um einen neuen Artikel und nicht um eine Aktualisierung handelt.

Ich hoffe, ihr könnt dieser Beschreibung irgendwie folgen …

[QUOTE=neuwaerts;123239]… weil ich für mein Modul unterscheiden können muss, ob ein Artikel beim Speichern gerade neu erzeugt oder lediglich aktualisiert wurde.

Und hier befürchte ich jetzt das Problem, dass mein Modul (in bestimmten Fällen), gar nicht mitbekommt, dass es sich um einen neuen Artikel und nicht um eine Aktualisierung handelt.[/QUOTE]

Das kannst du sehr wohl erkennen. Nämlich an der mitgelieferten OXID. Diese ist beim erstellen “-1”.

EDIT:
Um vielleicht kleiner anzufangen, schau mal in der Klasse /application/controllers/admin/article_main.php in die Save-Methode… Da wird eine Überprüfung gemacht, ob es ein neuer Artikel ist oder nicht.

Ist die auch noch “-1”, wenn ein anderes Modul den neuen Artikel bereits per parent::save() gespeichert hat?

[QUOTE=neuwaerts;123243]Ist die auch noch “-1”, wenn ein anderes Modul den neuen Artikel bereits per parent::save() gespeichert hat?[/QUOTE]

Der Artikel wird ja nicht sofort gespeichert, sondern erst am Ende. Es wird immer die Save-Methode des nächsten vererbten Objektes aufgerufen. Erst ganz zum Schluss kommt dann oxarticle und darin wiederum auch nochmal parent::save() (parent = oxBase)… Erst da passiert wirklich etwas in der Datenbank.

Ich bin gerade am Grübeln, ob man oxBase überladen kann, weil dann könntest du alles mögliche Loggen und mitkriegen, wenn save() ausgeführt wird… Ansonsten musst du jede Save-Methode von jedem Model überladen, welches du loggen möchtest.

Ich habe gerade einen kleinen Test gemacht, der zeigte, dass es anscheinend kein Problem damit geben wird.

Ich habe zwei Module mit jeweils einer Erweiterung von oxArticle::save erstellt und auch aktiviert.
In beiden Modulen habe ich mir jeweils vor und nach dem parent::save()-Call pper $this->getId() die Oxid-ID des Artikels geben lassen.

Mit dieser Anordnung habe ich dann einen neuen Artikel erstellt.
In den Logs beider Module war vor dem parent::save()-Call das Ergebnis von $this->getId() leer und nach dem parent::save()-Call mit derselben, durch das Speichern neu erzeugten Oxid-ID gefüllt.

Das Ergebnis ist natürlich gut für mich, da es zeigt, dass es offenbar nicht darauf ankommt, in welcher Reihenfolge der jeweilige Modul-Code ausgeführt wird.

Aus OOP-Sicht finde ich das Phänomen jedoch eigenartig.
Ich hätte jetzt erwartet, dass es sich bei den beiden Modul-Instanzen um separate Objekte (beides mit oxArticle als parent) handelt, die unabhängig voneinander parent::call() aufrufen, wodurch jeweils eine eindeutige Oxid-Id für einen neuen Artikeldatensatz erstellt wird.
In diesem Fall “wissen” die beiden Module aber entweder von einander, oder aber die Oxid-Id wird irgendwie “berechnet” und ist demnach vielleicht nicht so eindeutig, wie sie sein sollte.

Die Klassen der Module bilden wie gesagt eine Vererbungskette und daher hast du nur eine Instanz:
oxarticle_modul1
oxarticle_modul1_parent
oxarticle_modul2
oxarticle_modul2_parent
oxarticle
oxI18n
oxBase

Die _parent-Klassen werden dabei von Oxid on-the-fly generiert.

Oxbase hat auch eine onChange-Methode die die Art der Aktion übergeben bekommt.