| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 17520 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.xmlrpc.server">
- <title>Zend_XmlRpc_Server</title>
- <sect2 id="zend.xmlrpc.server.introduction">
- <title>Einführung</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> ist als vollständiger
- <acronym>XML-RPC</acronym> Server geplant, der den <ulink
- url="http://www.xmlrpc.com/spec">Spezifikationen auf www.xmlrpc.com</ulink> folgt.
- Des Weiteren implementiert er die Methode <command>system.multicall()</command>, welche
- dem Entwickler erlaubt, mehrere Anfragen aufzureihen.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.usage">
- <title>Grundlegende Benutzung</title>
- <para>
- Ein Beispiel der grundlegendsten Benutzung:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_XmlRpc_Server();
- $server->setClass('My_Service_Class');
- echo $server->handle();
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.xmlrpc.server.structure">
- <title>Server-Struktur</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> ist aus einer Vielfalt von Komponenten
- zusammengesetzt, die vom Server selbst über Anfrage-, Antwort- und bis hin zu
- Fehler-Objekten reicht.
- </para>
- <para>
- Um den <classname>Zend_XmlRpc_Server</classname> zu erstellen, muss der Entwickler dem
- Server eine oder mehrere Klassen oder Funktionen durch die Methoden
- <methodname>setClass()</methodname> und <methodname>addFunction()</methodname>
- hinzufügen.
- </para>
- <para>
- Wenn dieses erstmal erledigt wurde, kann man entweder der Methode
- <methodname>Zend_XmlRpc_Server::handle()</methodname> ein
- <classname>Zend_XmlRpc_Request</classname>-Objekt übergeben oder es wird ein
- <classname>Zend_XmlRpc_Request_Http</classname> instanziert, falls keines angegeben
- wurde - die Anfrage wird also aus <filename>php://input</filename> geladen.
- </para>
- <para>
- <methodname>Zend_XmlRpc_Server::handle()</methodname> versucht daraufhin, den
- zuständigen Handler, der durch die angeforderte Methode bestimmt wird,
- auszuführen. Es wird entweder ein <classname>Zend_XmlRpc_Response</classname>-
- oder ein <classname>Zend_XmlRpc_Server_Fault</classname>-Objekt zurückgegeben.
- Beide Objekte besitzen eine Methode <methodname>__toString()</methodname>, die eine
- gültige <acronym>XML-RPC</acronym> Antwort im <acronym>XML</acronym>-Format zurückgibt,
- die direkt ausgegeben werden kann.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.conventions">
- <title>Konventionen</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> ermöglicht es dem Entwickler, Funktionen und
- Methodenaufrufe als ausführbare <acronym>XML-RPC</acronym> Methoden anzufügen. Durch
- <classname>Zend_Server_Reflection</classname> wird die Überwachung aller angefügten
- Methoden - durch Nutzung der DocBlocks der Methoden und Funktionen
- werden deren Hilfstexte und Signaturen ermittelt - ermöglicht.
- </para>
- <para>
- <acronym>XML-RPC</acronym> Typen werden nicht zwingend 1:1 zu <acronym>PHP</acronym>
- Typen konvertiert. Dennoch wird versucht, einen passenden Typ, anhand der in
- @param- und @return-Zeilen enthaltenen Werte, zu ermitteln. Einige
- <acronym>XML-RPC</acronym> Typen besitzen jedoch kein direktes Äquivalent und sollten
- deshalb mittels <acronym>PHP</acronym>doc auf einen <acronym>XML-RPC</acronym> Typen
- hinweisen. Diese beinhalten:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis><property>dateTime.iso8601</property></emphasis>, ein String, der das
- Format YYYYMMDDTHH:mm:ss besitzt
- </para>
- </listitem>
- <listitem><para><emphasis>base64</emphasis>, base64-kodierte Daten</para></listitem>
- <listitem><para>struct, jegliches assoziatives Array</para></listitem>
- </itemizedlist>
- <para>
- 'Anbei ein Beispiel für einen solchen Hinweis:
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Dies ist eine Beispielfunktion.
- *
- * @param base64 $val1 Base64-kodierte Daten
- * @param dateTime.iso8601 $val2 Ein ISO-Datum
- * @param struct $val3 ein assoziatives Array
- * @return struct
- */
- function myFunc($val1, $val2, $val3)
- {
- }
- ]]></programlisting>
- <para>
- PhpDocumentor validiert keine Typen, die in Parameter- oder
- Rückgabewerten angegeben sind, weshalb dies keinen Einfluss auf
- die <acronym>API</acronym> Dokumentation hat. Das Angeben der Hinweise ist notwendig,
- da der Server die, dem Methodenaufruf zugewiesenen, Parameter
- validiert.
- </para>
- <para>
- Es ist genauso gut möglich, mehrere Werte als Parameter oder für
- die Rückgabe anzugeben; die <acronym>XML-RPC</acronym> Spezifikation schlägt sogar
- vor, dass system.methodeSignatur ein Array, das alle möglichen
- Methodensignaturen (d.h. jegliche Kombination aus Parametern und
- Rückgabewerten) enthält, zurückgibt. Um dies zu erreichen, kann
- man, wie man es normalerweise auch beim PhpDocumentor auch tun würde,
- einfach den '|'-Operator nutzen.
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Dies ist eine Beispiel-Funktion.
- *
- * @param string|base64 $val1 String oder base64-kodierte Daten
- * @param string|dateTime.iso8601 $val2 String oder ein ISO-Datum
- * @param array|struct $val3 Normal indiziertes oder assoziatives Array
- * @return boolean|struct
- */
- function myFunc($val1, $val2, $val3)
- {
- }
- ]]></programlisting>
- <para>
- Dennoch eine Anmerkung: Das Erlaubung von vielen Signaturen kann
- zu Verwirrung für Entwickler führen, wenn Sie diese Services nutzen;
- man sollte einer <acronym>XML-RPC</acronym> Methode deshalb nur eine Signatur zuweisen.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.namespaces">
- <title>Nutzen von Namensräumen</title>
- <para>
- <acronym>XML-RPC</acronym> besitzt ein Konzept für Namensräume; Grundlegend erlaubt es
- das Gruppieren von <acronym>XML-RPC</acronym> Methoden durch Punkt-separierte
- Namensräume. Dies hilft, Namenkollisionen zwischen Methoden, die durch verschiedene
- Klassen offeriert werden, zu verhindern. Beispielsweise kann der
- <acronym>XML-RPC</acronym> Server mehrere Methoden im 'system'-Namensraum nutzen:
- </para>
- <itemizedlist>
- <listitem><para>system.listMethods</para></listitem>
- <listitem><para>system.methodHelp</para></listitem>
- <listitem><para>system.methodSignature</para></listitem>
- </itemizedlist>
- <para>
- Intern werden die Methoden zu Methoden desselben Namens in der
- Klasse <classname>Zend_XmlRpc_Server</classname> umgeleitet.
- </para>
- <para>
- Um angebotenen Methoden Namensräume hinzuzufügen, muss man lediglich beim
- Hinzufügen der gewünschten Klasse oder Funktion einen Namensraum angeben:
- </para>
- <programlisting language="php"><![CDATA[
- // Alle öffentlichten Methoden in My_Service_Class sind als
- // myservice.METHODNAME verfügbar
- $server->setClass('My_Service_Class', 'myservice');
- // Funktion 'somefunc' ist als funcs.somefunc ansprechbar.
- $server->addFunction('somefunc', 'funcs');
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.xmlrpc.server.request">
- <title>Eigene Request-Objekte</title>
- <para>
- Die meiste Zeit wird man einfach den Standard-Anfragetyp
- <classname>Zend_XmlRpc_Request_Http</classname>, welcher im
- <classname>Zend_XmlRpc_Server</classname> enthalten ist, nutzen. Jedoch gibt es
- gelegentlich Fälle, in denen <acronym>XML-RPC</acronym> über die Kommandozeile
- (<acronym>CLI</acronym>), ein grafisches Benutzerinterface (<acronym>GUI</acronym>),
- eine andere Umgebung oder beim Protokollieren von ankommenden Anfragen erreichbar sein
- muss. Um dies zu bewerkstelligen, muss man ein eigenes Anfrage-Objekt kreieren, das
- <classname>Zend_XmlRpc_Request</classname> erweitert. Die wichtigste Sache, die man
- sich merken muss, ist sicherzustellen, dass die Methoden
- <methodname>getMethod()</methodname> und <methodname>getParams()</methodname>
- implementiert sind, so dass der <acronym>XML-RPC</acronym> Server Informationen erhält,
- die er für das Abfertigen einer Anfrage benötigt.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.response">
- <title>Eigene Antwort-Objekte</title>
- <para>
- Ähnlich wie bei den Anfrage-Objekten, kann der <classname>Zend_XmlRpc_Server</classname>
- auch eigene Antwortobjekte ausliefern; standardmäßig ist dies ein
- <classname>Zend_XmlRpc_Response_Http-Objekt</classname>, das einen passenden
- Content-Type <acronym>HTTP</acronym>-Header sendet, der für <acronym>XML-RPC</acronym>
- genutzt wird. Mögliche Nutzungen eines eigenen Objekts sind z.B. das Protokollieren von
- Antworten oder das Senden der Antworten zu <constant>STDOUT</constant>.
- </para>
- <para>
- Um eine eigene Antwortklasse zu nutzen, muss
- <methodname>Zend_XmlRpc_Server::setResponseClass()</methodname> vor dem Aufruf von
- <methodname>handle()</methodname> aufgerufen werden.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.fault">
- <title>Verarbeiten von Exceptions durch Fehler</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> fängt die, durch eine ausgeführte Methode
- erzeugten, Exceptions and generiert daraus einen <acronym>XML-RPC</acronym> Fehler als
- Antwort, wenn eine Exception gefangen wurde. Normalerweise werden die
- Exceptionnachrichten und -codes nicht in der Fehler-Antwort genutzt. Dies ist eine
- gewollte Entscheidung um den Code zu schützen; viele Exceptions entblößen mehr
- Informationen über den Code oder die Umgebung als der Entwickler
- wünscht (ein Paradebeispiel beinhaltet Datenbankabstraktion- oder
- die Zugriffsschichten-Exceptions).
- </para>
- <para>
- Exception-Klassen können jedoch anhand einer Weißliste (Whitelist) als
- Fehler-Antworten zurückgegeben werden. Dazu muss man lediglich die gewünschte
- Exception mittels
- <methodname>Zend_XmlRpc_Server_Fault::attachFaultException()</methodname> zur
- Weißliste hinzufügen:
- </para>
- <programlisting language="php"><![CDATA[
- Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');
- ]]></programlisting>
- <para>
- Abgeleitete Exceptions lassen sich als ganze Familie von Exceptions
- hinzufügen, indem man deren Basisklasse angibt.
- <classname>Zend_XmlRpc_Server_Exception</classname>'s sind immer auf der Weißliste zu
- finden, da sie spezielle Serverfehler berichten (undefinierte Methoden, etc.).
- </para>
- <para>
- Jede Exception, die nicht auf der Weißliste zu finden ist, generiert
- eine Antwort mit dem '404' Code und der Nachricht 'Unknown error'.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.caching">
- <title>Zwischenspeichern von Serverdefinitionen zwischen den Anfragen</title>
- <para>
- Das Hinzufügen einer Vielzahl von Klassen zu einer <acronym>XML-RPC</acronym> Server
- Instanz kann zu einem großen Ressourcenverbrauch führen; jede Klasse muss via Reflection
- <acronym>API</acronym> (<classname>Zend_Server_Reflection</classname>) inspiziert
- werden, welche eine Liste von allen möglichen Signaturen, die der Server verwenden kann,
- zurückgibt.
- </para>
- <para>
- Um die Einbußen zu reduzieren, kann <classname>Zend_XmlRpc_Server_Cache</classname>
- genutzt werden, welche die Serverdefinitionen zwischen den Anfragen zwischenspeichert.
- Wenn dies mit <methodname>__autoload()</methodname> kombiniert wird, kann es zu einem
- großen Geschwindigkeitsschub kommen.
- </para>
- <para>
- Ein Beispiel folgt:
- </para>
- <programlisting language="php"><![CDATA[
- function __autoload($class)
- {
- Zend_Loader::loadClass($class);
- }
- $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
- $server = new Zend_XmlRpc_Server();
- if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
- require_once 'My/Services/Glue.php';
- require_once 'My/Services/Paste.php';
- require_once 'My/Services/Tape.php';
- $server->setClass('My_Services_Glue', 'glue'); // glue. Namensraum
- $server->setClass('My_Services_Paste', 'paste'); // paste. Namensraum
- $server->setClass('My_Services_Tape', 'tape'); // tape. Namensraum
- Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
- }
- echo $server->handle();
- ]]></programlisting>
- <para>
- Obiges Beispiel zeigt, wie der Server versucht, eine Definition
- aus der Datei <property>xmlrpc.cache</property>, welches sich im selben Ordner wie das
- Skript befindet, zu laden. Wenn dies nicht erfolgreich ist,
- lädt es die Server-Klassen, die es benötigt, und fügt sie zum
- Server hinzu. Danach wird versucht, die Cache-Datei mit der
- Serverdefinition zu erstellen.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.use">
- <title>Nutzungsbeispiele</title>
- <para>
- Unten finden sich etliche Beispiele für eine Nutzung, die das
- gesamte Spektrum der verfügbaren Optionen für den Entwickler darstellen.
- These Beispiele bauen immer auf den vorangegangenen Beispielen auf.
- </para>
- <sect3 id="zend.xmlrpc.server.use.case1">
- <title>Grundlegende Benutzung</title>
- <para>
- Folgendes Beispiel fügt eine Funktion als ausführbare
- <acronym>XML-RPC</acronym> Methode hinzu und verarbeitet eingehende Aufrufe.
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Gibt die MD5-Summe eines Strings zurück.
- *
- * @param string $value Wert aus dem die MD5-Summe errechnet wird
- * @return string MD5-Summe des Werts
- */
- function md5Value($value)
- {
- return md5($value);
- }
- $server = new Zend_XmlRpc_Server();
- $server->addFunction('md5Value');
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case2">
- <title>Hinzufügen einer Klasse</title>
- <para>
- Das nächste Beispiel illustriert, wie man die öffentlichen Methoden
- eienr Klasse als ausführbare <acronym>XML-RPC</acronym> Methoden hinzufügt.
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb');
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case3">
- <title>Mehrere Klassen unter der Nutzung von Namensräumen hinzufügen</title>
- <para>
- Das nächste Beispiel zeigt, wie man mehrer Klassen mit ihren eigenen
- Namensräumen hinzufügt.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case4">
- <title>Bestimmen von Exceptions als valide Fehler-Antwort</title>
- <para>
- Im nächsten Beispiel wird gezeigt, wie man jede Exception, die von
- <classname>Services_Exception</classname> abgeleitet wurde, als Fehler-Antwort
- nutzen kann, dessen Nachricht und Code erhalten bleibt.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Exception.php';
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case5">
- <title>Nutzen eines eigenen Anfrage-Objekts</title>
- <para>
- Im folgenden Beispiel wird ein eigenes Anfrage-Objekt instanziert
- und durch den Server verarbeitet.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Request.php';
- require_once 'Services/Exception.php';
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- // Ein neues Anfrage-Objekt wird erstellt
- $request = new Services_Request();
- echo $server->handle($request);
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case6">
- <title>Nutzen eigener Antwort-Objekte</title>
- <para>
- Das nachstehende Beispiel zeigt, wie man eine eigene Antwort-Klasse
- als zurückgegebene Antwort für den Server setzt.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Request.php';
- require_once 'Services/Response.php';
- require_once 'Services/Exception.php';
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- // Ein neues Anfrage-Objekt wird erstellt
- $request = new Services_Request();
- // Nutzen eigener Antwort-Klasse
- $server->setResponseClass('Services_Response');
- echo $server->handle($request);
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case7">
- <title>Zwischenspeichern von Serverdefinition zwischen den Anfragen</title>
- <para>
- Dieses Beispiel zeigt, wie man Serverdefinitionen zwischen verschiedenen
- Anfragen zwischenspeichern kann.
- </para>
- <programlisting language="php"><![CDATA[
- // Definieren einer Cache-Datei
- $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
- // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Versucht die Serverdefinition aus dem Cache zu laden
- if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- // Speichern des Caches
- Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
- }
- // Ein neues Anfrage-Objekt wird erstellt
- $request = new Services_Request();
- // Nutzen eigener Antwort-Klasse
- $server->setResponseClass('Services_Response');
- echo $server->handle($request);
- ]]></programlisting>
- </sect3>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|