Die Windeit-Software GmbH wird in der nächsten Zeit eine neue Version des Automatic XML-Export Shopware-Plugins veröffentlichen. Es hat nun die Version 2.0.0 erreicht und kann jetzt selbstständig per SCP XML-Dateien auf einen anderen Server laden.
Dafür muss die php-ssh2 Extension installiert sein, was unter Ubuntu sehr einfach geht:
sudo apt-get install php7.2-ssh2
Auf dem Ziel Server muss der Openssh-Server installiert sein.
Danach müssen nur noch die Verbindungsdaten eingegeben werden und der SCP-Upload aktiviert werden.
Dropshipping mit Shopware ist ja nicht immer ganz einfach, wenn man nicht direkt alle Produkte von einem Vendor bezieht. Wenn man nur einen für alles hat ist alles ganz einfach weil man direkt, die gesamte Bestellung an diesen senden kann. Hat man nur einen, aber der auch nur bestimmte Produkte liefert geht es jetzt auch bzw. der erste Testdurchlauf für diesen Use-Case lief sauber durch.
Für Multi-Vendor Orders muss man eine Bestellung in mehrere kleine pro Distributor/Vendor/Lieferant aufteilen. Wenn man nur einmal alle 2h oder so die Bestellungen übermittelt und die Waren an sich selbst liefern lassen möchte, kann man diese sogar noch mal vorher wieder mergen, weil dann Lieferant und Empfänger bei allen Bestellungen immer gleich sind. Aber das ist schon ein Ausnahmefall.
Natürlich kann jeder Vendor einen eigenen Endpoint für die Bestellungen bereitstellen. Entweder per Email, Datei-Upload oder REST-API können die Daten in immer unterschiedlichen XML-Formaten übertragen werden. Das macht dann mehr Probleme.
Mein Shopware-Plugin kann nun aber immerhin verschiedene Vendor/Hersteller bei diesem Splitting ignorieren. Damit ist es nun möglich, wenn man nur einen Vendor für bestimmte Produkte hat, diesen auch mit dem Plugin die Bestellungen automatisch zu zustellen. Bei mehr als einem muss mein Plugin noch leider passen.
Das Plugin kann also momentan folgende Fälle komplett abdecken:
- Übertragung von allen Bestellungen in ein ERP-System oder ähnliches
- Übertragung von allen Bestellungen an einen Vendor (mit oder ohne Dropshipping)
- Übertragung von bestimmten Bestellungen oder auch nur Teil-Bestellungen an einen Vendor (mit oder ohne Dropshipping)
ob es sich um eine einfache Order bei dem Vendor handelt oder um Dropshipping, muss man sich teilweise im XSLT für das Order-XML selbst zusammen bauen (oder mich damit beauftragen). Für die openTRANS-Formate versuche ich momentan eine Lösung zu entwickeln, die dann z.B. die Lieferadresse automatisch nach Konfiguration mit den eigenen Adress- oder den Kunden-Adressdaten befüllt.
Für den Export zulassen
An einer vollständigen Lösung, um beliebig viele Vendor mit jeweils eigenen Übertragungsarten und XML-Formaten anzubinden, arbeite ich auch nebenbei. Gerne würde ich eine Shop-System unabhängige Lösung bauen.. leider fehlt dafür aber Zeit und Geld... bzw. hauptsächlich Geld.. weil wenn man das Geld hat, hat man auch die Zeit.
In den letzten Wochen hat sich doch einiges beim meinem XML-Export Plugin getan. Langsam aber zielstrebig geht es in die Bereiche Dropshipping und Bestellung-Konsolidierung. Dadurch wird es zu einem wichtigen B2B-Baustein.
Mit der Version 0.4.1 ist nun viel mehr in dem Bereich möglich (Veröffentlichung folgt in den nächsten Tagen)
Als erstes Beispiel wie man das Plugin nicht nur dafür verwenden kann für das eigene ERP Bestellungen zu exportieren, habe ich hier erotikgrosshandel.de . Deren Schnittstellen-Doku ist ziemlich gut und sie haben ein sehr minimalistisches Format, so dass man relativ schnell zum Ziel kommt. Die Voraussetzung waren:
- Ein eigenes passendes XSLT-Template (nach deren Doku)
- Der ApiClient muss FORM-Data per Post senden können (nicht nur wie bisher JSON)
- CronJob und CLI-Command müssen den Push an eine API auslösen
- Das Model muss die Lieferanten spezifischen Bestellnummern der Artikel enthalten (Puchase-Preise kamen gleich mit dazu...)
Das ganze war dann eigentlich nur viel Kleinkram und der POST als FORM-Data. War also an sich relativ schnell umgesetzt und lies sich gut testen.
Eingestellt muss sein:
- Format: eigene XSLT-Transformation
- Den Pfad zur eigenen XSLT angeben (absoluter Pfad vom /-Root aus!)
- Export-Pfad ist nicht nötig, aber sollte man doch setzen, falls man als Kontrolle die XML-Daten doch selbst noch mal vorhalten möchte (auch hier der absolute Pfad)
- nie automatisch exportieren (nur per CLI, CronJob oder API), man sollte den CronJob verwenden
- CronJob soll nur Bestellungen mit dem Status 0 und 12 (offen und vollständig bezahlt) verarbeiten: "0,!1,!2,!3,!4,!5,!6,!7,!8,!9,!10,!11,12,!13,!14"
- nach dem Export auf Status 1 (in Bearbeitung) setzen
- Host und URL setzen für erotikgrosshandel.de
- Content-Feldname auf "data" ändern
- Post-Format auf "FORM" setzen, damit in "data" die XML-Daten zu finden sind
Damit sendet er per CLI oder CronJob alle 0+12 Bestellungen im Lieferanten eigenen XML-Format an deren Schnittstelle und setzt danach die Bestellung auf 1+12, damit sie beim nächsten Durchlauf kein weiteres mal übertragen wird.
Den CronJob auf 10min stellen und dann sollten alle 10 Minuten alle "offenen" Bestellungen an den Server übertragen.
Über XSLT-Dateien kann man in anderen Fällen natürlich dann auch andere Formate wie GS1 oder OCI implementieren. Um die Daten zu den anderen Systemen übertragen zu können stehen der API-Client, Emails, Abruf über die Shopware-API oder der Export als Datei (und dann Übertragung per FTP oder SCP) zur Verfügung.
In den nächsten Wochen steht bei mir auf dem Plan, Bestellungen konsolidieren zu können, so dass bei einem CronJob-Lauf alle 2h nicht alle Bestellungen einzeln übertragen werden müssen, sondern auch zusammen gefasst werden können, wenn die Bestellungen für den selben Empfänger vorgesehen sind.
Die neue Version vom automatischen XML Order-Export, nutzt für openTrans2.1 XSLT und keinen PHP-Code mehr. Der Vorteil davon ist, dass so für jeden Anpassungen an der Ausgabe sehr viel einfacher werden. Man kopiert sich die vorhandene XSLT-Datei und kann die Kopie so anpassen wie man will. Im Plugin kann man die Datei dann angeben und diese anstelle der originalen XSLT-Datei verwenden.
Wenn man z.B. ein Attribute-Field zusätzlich als offiziellen openTRANS2.1 XML-Tag einbinden:
Es hat doch ein paar Tage länger gedauert, als gedacht und ich habe am Ende doch mehr geändert als ich zu Anfang wollte, aber ich habe bei dem Plugin jetzt ein besseres Gefühl als vorher. Es ist moderner und flexibler als die alte Version. Änderungen gehen auch viel schneller.
An openTRANS 1.0 hat sich garnichts geändert und wird wohl demnächst mal auf XSLT umgestellt. Bei openTRANS 2.1 hat sich mehr geändert. Zuvor fehlende Felder sind hinzu gekommen. Datum und Zeit der Bestellung ist nun getrennt vom Datum der Erzeugung des Dokuments.
Und das Wichtigste, was hinzu kam, ist, dass nun auch Updates auf Bestellungen exportiert werden. Der UDX.EDI-Block enthält dann die Information, ob es sich um ein CREATE UPDATE handelt. Wer den Export in eine Datei schreibt oder den Push-Client verwendet bekommt jetzt diese Informationen geliefert. Dateien haben nun einen Timestamp im Namen, so dass alle Änderungen linear exportiert werden können.
Wer eine alte Version verwendet sollte nicht einfach updaten, sondern erst einmal ausgiebig Testen!
Wie schon gesagt, habe ich bei dem Plugin jetzt ein wirklich gutes Gefühl.
Version 0.3.1 sollte demnächst im Store verfügbar sein.
Ich wollte ja das Order-Export in Richtung XSLT bearbeiten... nun wird alle sehr vollständige Überarbeitung daraus. Besseres Export verhalten nach Änderungen an Bestellungen.. auf über das Backend. Insgesamt soll alles etwas flexibler werden und für mehr B2B-Anwendungsfälle passend gemacht werden.
Andere Projekte gehen auch nicht so wirklich weiter. Das Cashless-Paymentsystem ist erst einmal auf HOLD. Ich habe zwar schon fertige Pläne, um es auch als ganz normale Kasse (mit Barcode-Scanner) nutzen zu können und auch die Bons dokumenten-echt als signierte PDF parallel zum Druck speichern zu können.
Auch wollte ich mal eine wirkliche Präsentation (vielleicht mit Video) dafür basteln. Am Ende könnte ich mit wenig Zeit noch ein gutes und fertiges Produkt daraus machen. Leider fehlt die Zeit oder das Geld um bei der Zeit das Projekt neu zu priorisieren.
Aber erst einmal steht auch wieder Bremen am 30.6. an. Diesmal bewaffnet mit unter anderen 2 ThinkPad T500 für echt wenig Geld (Die sind für mich da auch Verbrauchsmaterial.. bei höheren Stückzahlen einfach mal wegen dem Preis direkt anfragen. Auch wegen den passenden Akkus und WLAN-Karten dazu).
Im Hintergrund bei der Artikelseite läuft mein "Eigenschaften im Listing" Plugin als Dataprovider ohne eigene Ausgabe.
Bis jetzt konnte das Plugin neben dem Shopware-Model als XML auch openTRANS 1.0 und 2.1 exportieren. Das war aber rein in PHP implementiert. Zusätzlich konnte man eigene XML-Formate über XSLT ausgeben.
Nun werde ich nach und nach den PHP Anteil reduzieren und auch openTRANS in XSLT implementieren. Erste Schritte sind getan.
Ich rechne damit dass ich so in 2 Wochen, dann alles so weit auf XSLT migriert haben werde.
Wenn in einem Node kein Text ist, soll der Text eines anderen Nodes verwendet werden.
/ITEM/TEXT_SHORT[text()]/text() | /ITEM/TEXT_LONG[text() and not(/ITEM/TEXT_SHORT[text()])]/text()
Hier wird vorrangig der TEXT_SHORT verwendet. Sollte dieser aber leer sein, wird auf den TEXT_LONG zurück gegriffen.
Ich habe mir das auch aus anderen Beispielen so lange hin und her gebastelt bis es ging. Aber so erspart man sich zusätzlichen Code der später die beiden Texte abgleicht und es wird gleich richtig eingelesen.
Nächstes Jahr werde ich wirklich mal das Adventskalender-Projekt nach vorne bringen. Mit Shopware Emotion-Element und so. Erstmal stehen jetzt für Ende diesen und Anfang nächsten Jahres folgende Dinge auf meiner Todo-Liste:
- Shopware-Plugin: Warnung bei unnatürlichen Preisänderungen
- Shopware-Plugin: Globale Smarty-Variablen für Kundendaten
- Shopware-Plugin: XML-Order Export für ERP-Integration
Dann kommt noch die Planung/Konzeptionierung für ein Projekt mit RFID Technik in Kombination mit vielleicht Shopware.
Und auch SMS2X soll noch mal verbessert werden, so dass es vielleicht mal zum Einsatz kommen kann.
Auch Zeitmessung ab von RFID wird mich wohl noch mal beschäftigen.
Wenn man mit dem XML-Parser von jcabi-xml arbeitet und der direkt am Anfang der Datei behauptet, es würde nicht nach einer XML aussehen, kann es am UTF8-BOM liegen.
Mit dieser build.xml kann man eine Zip-Datei bauen, die von Shopware für Plugins akzeptiert wird. Wenn man Phing und nicht Ant verwendet, muss man ${basedir} durch ${project.basedir} ersetzen.
Ich hatte es schon fertig und dachte ich könnte es später auch mal im Community Store anbieten.. aber dann kam mir schon jemand zu vor und dann auch noch kosten los.
Also hier einfach mein Plugin als Code für jeden:
<?php
namespace HPrExportAttrExtend;
use Doctrine\DBAL\Connection;
use Shopware\Components\Plugin;
Gehen wir mal davon aus wir hätten noch ein Legacy-Plugin mit einer Bootstrap-php, die einen Service registriert, den wir dekorieren wollen. Über die services.xml geht so etwas nicht.
class HprTest extends Plugin{
public static function getSubscribedEvents(){
return [
'Enlight_Bootstrap_AfterInitResource_hpr_legacy.the_service' => 'decorateService',
];
}
public function decorateService()
{
$coreService = Shopware()->Container()->get('hpr_legacy.the_service');
$refl = new \ReflectionClass(get_class($coreService));
$service = new TheNewService($config);
Shopware()->Container()->set('hpr_legacy.the_service', $service;
}
}
Sehr sehr unschön.. aber es funktioniert so. Der Weg über die XML ist natürlich sehr viel schöner, gerade weil die Injection der Constructor Arguments vom ursprünglichen Service übernommen werden man nicht diese per Reflections erst einmal wieder aus dem ursprünglichen Service heraus gepult werden müssen.
Ich habe mich jetzt die letzten 2-3 Monate doch relativ ausführlich mit Shopware beschäftigt. Das erste Projekt das live ging war das Creditfair Fair-Vereinsprogramm. Dafür mussten 2 Plugins geschrieben und einige Theme-Anpassungen vorgenommen werden.
Die Plugin-API mit den Events ist wirklich einfach zu erlernen. Einzig die Suche nach dem passenden Event kann immer etwas länger dauern, wobei am Ende weniger die Frage ist, ob es das richtige Event ist, sondern ob es das beste Event ist. Events für jeden Fall gibt es mehr als genug, wobei die Unterschiede wirklich oft in Feinheiten zu suchen sind.
Nebenbei habe ich als Test ein kleines Plugin geschrieben, das das Kunden-Objekt (wenn denn ein Kunde eingeloggt) ist auch beim Versenden von Forms im Template verfügbar macht. Forms verwenden eine eigene kleine und sehr einfache Template Engine. Für die Erweiterung um den Kunden kommt aber dann Smarty3 zum Einsatz. Damit kann man bei Anfragen über Forms, die nur angemeldeten Kunden zur Verfügung stehen, die Kundendaten direkt zur Email hinzufügen, ohne dass der Kunde es selber tun muss.
Insgesamt macht es viel Spass mit Shopware zu entwickeln.. nur.. nur eine Sache gibt.. die bereitet mir noch Kopfzerbrechen.
STAGING
Mit der 5.3 kann man wenigstens Einkaufwelten exportieren und wieder importieren. Das ist schon mal wirklich eine große Hilfe, da so Designer auf dem lokalen System arbeiten und testen können und man erst dann nach der Freigabe die Einkaufwelten auf das produktive System verschieben kann.
Themes kann auch relativ einfach kopieren. Plugins aus dem Community-Store sollte man so oder so nicht durch ein Staging laufen lassen, sondern auf dem produktiven Server neu installieren und konfigurieren.
Content-Seiten sind der Punkt, wo ich noch am Überlegen bin wie man damit umgehen soll. Hier fehlt eine vergleichbare Import/Export Funktion wie bei den Einkaufwelten.
Ein anderes Thema betrifft Shopware aber auch fast alle anderen Shop-Systeme. Das Problem beginnt damit Produkte, Hersteller, etc in das Shop-System zu bekommen. Denn wenn man keinen winzigen Shop mit 10-50 Artikeln hat, wird man sicher die Produkte aus einem Waren-Wirtschafts-System beziehen wollen. Die REST-API von Shopware ist toll und man kommt schnell zu Ergebnissen. Der CSV-Import ist auch nicht schlecht. Aber das Problem ist, dass man dann immer eine Lösung für Shopware baut. Bei anderen Shops eben für das jeweilige System.
Es gibt wohl kaum Shop-Systeme (oder ich konnte sie nicht finden), die Standard-Formate als Core-Feature lesen oder schreiben können.
Bei der Arbeit dürfte ich nun mit CSV, XML und IDocs aus SAP kämpfen. IDocs sind für den Datenaustausch wirklich nicht toll. Jedenfalls nicht, wenn man die SAP-Welt verlässt. In dem Artikel Warum Sie beim Datenaustausch im E-Commerce auf Standardformate setzen sollten von Daniel Peters trifft es sehr gut gut. Ich stimme da zu 100% zu und er trifft wirklich den Punkt, den ich schon seit Jahren nicht verstehe. Wenn ich ein neues System entwickle, dass mit anderen Systemen kommunizieren und Daten austauschen muss. Warum baue ich mir dann immer wieder ein eigenes Format und nehme mir nicht von Anfang an ein Standard-Format. Damit habe ich auch schon mal eine Art Blaupause, wie man mit dieser Art von Daten umgehen kann und sollte mal ein System ausgewechselt werden, muss ich hoffentlich nicht wieder ein neues proprietäres Format in eine Schnittstelle für mein System umwandeln.
Ich hatte mir ein kleines Plugin geschrieben, dass Bestellungen direkt nach dem Speichern als JSON auf dem Server abgelegt hat. Es war zuerst zur Kontrolle und zum Debuggen auf dem Live-Server da. Es hat nicht lange gedauert und ich hatte auch einen XML-Export und 2 Stunden später auch einen rudimentären [url=]OpenTrans[/url] 1.0 export. Auch wenn der Standard sicher noch nicht zu 100% korrekt umgesetzt ist, habe ich doch schon mal ein Export-Format für Bestellungen, das alles enthält was man braucht, strukturiert ist und auch einfach wieder gelesen werden kann.
Ich werde auf jeden Fall an dem Plugin noch mal weiter rumbauen und vielleicht nochmal OpenTrans 2.1 implementieren.
Ich glaube auch das man einfacher eine OpenTrans zu IDoc Lösung findet, ohne selbst was machen zu müssen, als eine Shopware-internes-Format zu IDoc.
Auch der Import der Produkte... warum kann ich nicht einfach OCI oder BMEcat verwenden, um meinen Shop mit Daten zu befüllen. WWS und andere ERP-Systeme können ja diese Format ausgeben. Die Formate, gerade OCI, sind ja auch sehr verbreitet. Warum kann der Shop diese also nicht nativ lesen und benötigt Zusatzsoftware oder Plugins?
Auf der Roadmap von Shopware-Enterprise steht bei B2B jetzt OCI in der "Unsere Visionen für die Zukunft". Richtiges Punchout muss ja nicht mal sein.
Aber die OCI-XML Daten importieren zu können wäre schon einfach toll und würde an vielen Stellen sehr viel Arbeit und Geld sparen.
Das wohl gerade an einem Import für Kunden aus Drittsystemen gearbeitet wird kommt wohl für mich auch zu spät, aber ist schon mal eine tolle Sache.
Momentan überlege ich einen kleines Plugin zu schreiben, dass BMEcat versteht. Nichts all umfassendes mit User-Data-Extensions und so. Ein einfaches kleines, dass nur dafür sorgt, dass Systeme die BMEcat ausgeben können, grundlegend den Shop mit Produkten befüllen können. Wenn ich dann mal wieder Daten aus einem System in Shopware importieren soll, würde ich einfach die Daten auf BMEcat umbiegen können (mit einer Middleware oder XSLT oder so) und müsste an Shopware nichts mehr ändern. Shopware hätte dann eine stabile Schnittstelle, die nicht nur für mich sondern allgemein genutzt werden kann und sogar ein sehr gut dokumentiertes Format nutzt.
Sich der Welt mit Standard-Formaten als Core-Feature zu öffnen, würde vielen Shop sehr gut tun. ... aber wohl auch einen Markt der sich nur auf das verschieben von Daten zwischen Systemen spezialisiert hat, empfindlich treffen können. Für den normalen Entwickler und seinen Shop wäre es aber wirklich ein großer Vorteil.
In letzter Zeit habe ich CodeMirror lieben gelernt. Ich mag es nicht mit TinyMCE zu arbeiten und normale TextAreas sind für HTML-Coding wirklich schrecklich. Wenn man in einem System HTML-Templates bearbeitet, will man Einrückungen und Syntax-Highlighting.
Mit Code-Mirror hat man da und es ist wirklich leicht zu verwenden. Man hat eine Variable pro Editor und das einbringen von Code von Außen (z.B. das hinzufügen von Bilder-Links durch ein Klick auf ein Bild) ist sehr einfach.
Und es gibt sogar einen Mode für BBCode. Damit wird jetzt das Blog-Modul betrieben, wenn man sich gegen HTML mit TinyMCE entscheidet.
Wer also XML oder HTML Code in seiner Web-Anwendung bearbeiten muss oder seinen Benutzern BBCode anbietet kann das mit CodeMirror wirklich leicht und schnell einbauen.
REST-Services sind ja nicht mehr neu und haben gerade die klassischen WebServices (SOAP) an vielen Stellen ersetzt. Wer mal mit SOAP, auch auf einen niedrigeren Level, gearbeitet hat, wird dies nicht als Verlust sehen. Es gibt viele Frameworks für REST-Services und auch lassen sich die meisten anderen Frameworks ohne Probleme so anpassen, dass sie keine HTML-Seite zurück liefern sondern das Ergebnis als JSON. XML wäre auch möglich als Ausgabeformat, aber ist sehr sehr wenig verbreitet. XML ist meistens sehr viel größer, da "name":"value" viel kürzer ist als <name>value</name> oder <attribute name="name" value="value"/>.
Meine Erfahrungen mit dem Parsen von XML und JSON in PHP ist aber, dass beide eigentlich gleich schnell sind. Ein Wechsel bei Config-Files von XML auf JSON hat keine Verbesserung der Ladezeiten ergeben. Auch die Serialisierung von Objekten bei Java war mit JSON nur minimal schneller als mit XML, wobei es dort auch sehr vom Verwendeten Framework abhängig war. Also kann es sein, das es in neueren PHP-Versionen doch Unterschiede geben wird, wenn dort noch mehr optimiert wird.
Mit das größte Problem auf dass ich bei REST-Services in PHP gestoßen bin ist das Parsen der URLs. Hier besteht einfach das Problem, dass es immer viele Methoden pro Service gibt und das einlesen der Mapping-Patterns somit doch relativ aufwendig sein kann. Während man in einem Java-Servlet nur einmal am Anfang alles parsen muss, muss man in PHP bei jeden Request von vorne beginnen. Eine Lösung wäre das Speichern der Ergebnisse in der Session, wobei hier dann aber das Problem bleibt, dass man bei Änderungen diese erkennen und den Inhalt der Session erneuern muss. Man kann das XML als String lesen und einen MD5-Hash bilden. Damit könnte man verschiedene Versionen des Services in der Session identifizieren. Am schönsten wäre natürlich den Zugriff auf das Dateisystem komplett einsparen zu können, aber dass scheint erstmal so nicht machbar zu sein.
Das Gleiche gilt auch für das Objekt, dass die Methoden enthält auf die die URLs gemappt werden. Man muss sich auch deutlich machen, dass ein REST-Service im Grunde kein Konstrukt der objekt-orientierten Programmierung ist, sondern die Facade im Grund klassischen prozedualen Prinzipen folgt. Gerade wenn man Sicherheits-Token und so verwendet und nicht die Session für die Speicherung des eingelogten Benutzer verwendet, merkt man dass man auch ohne Klasse mit einfachen functions hier genau so gut arbeiten könnte. Aber wir verwenden eine Klasse, die den Service beschreibt, um auch keinen Stilbruch zu haben. Ein Objekt zu erzeugen ist teuer und theoretisch könnte man sich dieses hier ersparen.
Mein AFP2-Framework benutzt die selben Klassen wie mein älteres aoop-Framework. Es implementiert momentan noch kein wirkliches Routing sondern nutzt einfach Regex-Ausdrücke um die gesamte URL mit einem Match auf die richtige Methode zu mappen. Hier wird also einfach von oben nach unten die Liste durch laufen und immer ein preg_match durchgeführt. Routing mit beliebig tiefer Verschachtelung und Sub-Routen, würde hier viel Zeit ersparen, da damit die Anfangs-Liste relativ klein wäre und schnell abzuprüfen wäre und erst dann in der nächsten Liste weiter geprüft wird. Das kommt dann später nochmal um etwas schneller zu werden.
Wie man erkennt wird im service-Tag die Klasse angeben, auf die die URLs gemappt werden sollen. Das Mapping der einzelnen Methoden wird dann innerhalb genauer definiert. Jede Method einen grundlegenden Pattern, der für ein Match auf die URL verwendet wird. Wenn dieser passt wird versucht die Argument (die Reihenfolge in der XML muss der Reihenfolge in PHP entsprechen!) aus der URL oder dem Request zu rekonstruieren. Jedes Argument kann ein eigenes Pattern haben. Wenn es ein Request-Value ist, entspricht das Pattern dem Namen im Request. Sollte kein Pattern angeben sein, wird dass Pattern der Method verwendet. Das erspart viel Text, weil man so nur ein allgemein gültiges Pattern schreiben muss. Mit group wird die Gruppe beim preg_replace angeben. Also die die den benötigten Wert enthält, der als Argument übergeben werden soll. Im Pattern der Method können also schon alle Werte in Gruppen markiert werden und bei den Arguments muss immer nur noch angegeben werden, welche Gruppe verwendet werden soll.
URLs zu REST-Services folgen in aoop und APF2 folgender Regel:
http://..../rest/{modulename}/.....
Über den Modul-Namen wird gesteuert welche rest.xml geladen wird. /rest/ ist die Markierung, dass hier ein REST-Service angesprochen werden soll. Der Rest der URL kann nach Belieben definiert werden.
Für unser Beispiel wäre z.B. folgende URL lauffähig:
Das Ergebnis der Methode wird dann in JSON umgewandelt und auch der Header entsprechend auf "text/json" gesetzt.
Damit lässen sich nun pro Modul REST-Services definieren und deployen. Bei PHP hat man zum Glück nicht das Problem, dass sich ändernde Klasse von anderen REST-Services anderer Module zu Laufzeitfehlern führen können. Wenn man ein Modul ändert, wird die Klasse ja beim nächsten Request erneut geladen und nicht wie bei Java in der VM gehalten. Probleme kann es nur geben, wenn man die Session verwendet und versucht dort gespeicherte serialisierte Daten einer alten Version in ein Objekt der neuen Version der Klasse zu deserialisieren.
Das macht diese Umgebung in PHP für Microservices interessant. Da man hier wirklich einzelne Module zur Laufzeit austauschen kann, ohne dabei die anderen Module zu beeinflussen (wenn man natürlich vorher drauf geachtet hat, dass Klassen, die auch von anderen Modulen verwendet werden, nicht zu Fehlern bei diesen führen). Zu überlegen wäre auch diese Klassen zwischen den Services als JSON und nur über eine URL dem anderen Service verfügbar zu machen. Also die URL auch zu Intra-Service Kommunikation zu verwenden.
Und den JSON-String dann auf eine eigene Klasse zu mappen. So etwas werde ich für die nächste Version dann einbauen.
Das war jetzt ein grober Überblick wie meine Frameworks REST-Services implementieren und versuchen dabei möglichst flexibel zu sein, aber auch nicht dabei zu sehr auf Kosten der Performance zu arbeiten. Die Arbeiten an APF2 sind noch in Gange und deswegen kann sich da auch noch einiges Ändern und vielleicht lerne ich von anderer Seite noch einiges, wie sich auch die letzten Probleme lösen lassen, um so REST-Services noch besser implementieren zu können.
Momentan überlege ich die auf XML basierenden Config-Dateien in meinem PHP-Framework durch JSON-Dateien
zu ersetzen. Das Parsing bei JSON scheint gefühlt schneller zu sein. Gerade bei der Implementierung der
REST-Services muss die XML-Datei mit den Mappings bei jeden Aufruf neu geparst werden und ich vermute, dass es sehr viel schneller gehen würde, wenn man mit JSON und einen assoc-Array arbeiten würde.
Ich werde wohl demnächst mal paar Tests durchführen. In Java hatte man den Vorteil, dass man die Objekte im Servlet halten konnte und es deswegen relativ egal war wie lange das Parsen dauerte, da es nureinmal erledigt werden musste. Bei PHP kann man die Methoden Mappings in der Session halten, muss aber das Object, dass als Service Endpoint agiert, jedes Mal neu aus der XML lesen.
Die neue Page-Implementierung des Framework verwendet JSON und ist alles andere als langsam dabei.
Blog-entries by search-pattern/Tags:
Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?