Zend_XmlRpc_Server.xml 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 20115 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.xmlrpc.server">
  5. <title>Zend_XmlRpc_Server</title>
  6. <sect2 id="zend.xmlrpc.server.introduction">
  7. <title>Einführung</title>
  8. <para>
  9. <classname>Zend_XmlRpc_Server</classname> ist als vollständiger
  10. <acronym>XML-RPC</acronym> Server geplant, der den <ulink
  11. url="http://www.xmlrpc.com/spec">Spezifikationen auf www.xmlrpc.com</ulink> folgt.
  12. Des Weiteren implementiert er die Methode <command>system.multicall()</command>, welche
  13. dem Entwickler erlaubt, mehrere Anfragen aufzureihen.
  14. </para>
  15. </sect2>
  16. <sect2 id="zend.xmlrpc.server.usage">
  17. <title>Grundlegende Benutzung</title>
  18. <para>
  19. Ein Beispiel der grundlegendsten Benutzung:
  20. </para>
  21. <programlisting language="php"><![CDATA[
  22. $server = new Zend_XmlRpc_Server();
  23. $server->setClass('My_Service_Class');
  24. echo $server->handle();
  25. ]]></programlisting>
  26. </sect2>
  27. <sect2 id="zend.xmlrpc.server.structure">
  28. <title>Server-Struktur</title>
  29. <para>
  30. <classname>Zend_XmlRpc_Server</classname> ist aus einer Vielfalt von Komponenten
  31. zusammengesetzt, die vom Server selbst über Anfrage-, Antwort- und bis hin zu
  32. Fehler-Objekten reicht.
  33. </para>
  34. <para>
  35. Um den <classname>Zend_XmlRpc_Server</classname> zu erstellen, muss der Entwickler dem
  36. Server eine oder mehrere Klassen oder Funktionen durch die Methoden
  37. <methodname>setClass()</methodname> und <methodname>addFunction()</methodname>
  38. hinzufügen.
  39. </para>
  40. <para>
  41. Wenn dieses erstmal erledigt wurde, kann man entweder der Methode
  42. <methodname>Zend_XmlRpc_Server::handle()</methodname> ein
  43. <classname>Zend_XmlRpc_Request</classname>-Objekt übergeben oder es wird ein
  44. <classname>Zend_XmlRpc_Request_Http</classname> instanziert, falls keines angegeben
  45. wurde - die Anfrage wird also aus <filename>php://input</filename> geladen.
  46. </para>
  47. <para>
  48. <methodname>Zend_XmlRpc_Server::handle()</methodname> versucht daraufhin, den
  49. zuständigen Handler, der durch die angeforderte Methode bestimmt wird,
  50. auszuführen. Es wird entweder ein <classname>Zend_XmlRpc_Response</classname>-
  51. oder ein <classname>Zend_XmlRpc_Server_Fault</classname>-Objekt zurückgegeben.
  52. Beide Objekte besitzen eine Methode <methodname>__toString()</methodname>, die eine
  53. gültige <acronym>XML-RPC</acronym> Antwort im <acronym>XML</acronym>-Format zurückgibt,
  54. die direkt ausgegeben werden kann.
  55. </para>
  56. </sect2>
  57. <sect2 id="zend.xmlrpc.server.anatomy">
  58. <title>Anatomie eines Webservices</title>
  59. <sect3 id="zend.xmlrpc.server.anatomy.general">
  60. <title>Generelle Annahmen</title>
  61. <para>
  62. Für eine maximale Performance ist es Notwendig eine einfache Bootstrap Datei für die
  63. Server Komponente zu verwenden. Der Verwendung von
  64. <classname>Zend_XmlRpc_Server</classname> innerhalb von <link
  65. linkend="zend.controller"><classname>Zend_Controller</classname></link> wird
  66. strengstens abgeraten um den Overhead zu vermeiden.
  67. </para>
  68. <para>
  69. Services ändern sich mit der Zeit, und wärend sich Webservices generell weniger
  70. intensiv ändern wie Code-native <acronym>APIs</acronym>, wird empfohlen den eigenen
  71. Service zu versionieren. Das legt den Grundstein für die Kompatibilität zu Clients
  72. welche eine ältere Version des eigenen Services verwenden und managt den
  73. Lebenszyklus des Services. Um das zu tun sollte eine Versionsnummer in die
  74. <acronym>URI</acronym> eingefügt werden. Es wird auch empfohlen den Namen des
  75. Remote Protokolls in der <acronym>URI</acronym> einzufügen um eine einfache
  76. Integration von zukünftigen Remote Technologien zu erlauben.
  77. http://myservice.ws/<emphasis>1.0/XMLRPC/</emphasis>.
  78. </para>
  79. </sect3>
  80. <sect3 id="zend.xmlrpc.server.anatomy.expose">
  81. <title>Was kann man freigeben?</title>
  82. <para>
  83. Meistens ist es nicht sensibel Business Objekte direkt freizugeben. Business
  84. Objekte sind normalerweise klein und werden häufig geändert, da die Änderung in
  85. diesem Layer der Anwendung sehr billig ist. Sobald Webservices bekanntgegeben und
  86. verwendet werden ist eine Änderung sehr hart. Andere Vorbehalte sind
  87. <acronym>I/O</acronym> und Latenz: die besten Aufrufe von Webservices sind jene die
  88. nicht stattfinden. Deswegen müssen Aufrufe zu Services grob körniger sein als die
  89. normale Business Logik selbst. Oft macht ein zusätzlicher Layer vor der Business
  90. Logik sinn. Dieser Layer wird manchmal als <ulink
  91. url="http://martinfowler.com/eaaCatalog/remoteFacade.html">Remote Facade</ulink>
  92. bezeichnet. Solch ein Service Layer fügt ein grob körniges Interface über der
  93. Business Logik hinzu und gruppiert langatmige Operationen zu kleineren.
  94. </para>
  95. </sect3>
  96. </sect2>
  97. <sect2 id="zend.xmlrpc.server.conventions">
  98. <title>Konventionen</title>
  99. <para>
  100. <classname>Zend_XmlRpc_Server</classname> ermöglicht es dem Entwickler, Funktionen und
  101. Methodenaufrufe als ausführbare <acronym>XML-RPC</acronym> Methoden anzufügen. Durch
  102. <classname>Zend_Server_Reflection</classname> wird die Überwachung aller angefügten
  103. Methoden - durch Nutzung der DocBlocks der Methoden und Funktionen
  104. werden deren Hilfstexte und Signaturen ermittelt - ermöglicht.
  105. </para>
  106. <para>
  107. <acronym>XML-RPC</acronym> Typen werden nicht zwingend 1:1 zu <acronym>PHP</acronym>
  108. Typen konvertiert. Dennoch wird versucht, einen passenden Typ, anhand der in
  109. @param- und @return-Zeilen enthaltenen Werte, zu ermitteln. Einige
  110. <acronym>XML-RPC</acronym> Typen besitzen jedoch kein direktes Äquivalent und sollten
  111. deshalb mittels <acronym>PHP</acronym>doc auf einen <acronym>XML-RPC</acronym> Typen
  112. hinweisen. Diese beinhalten:
  113. </para>
  114. <itemizedlist>
  115. <listitem>
  116. <para>
  117. <emphasis><property>dateTime.iso8601</property></emphasis>, ein String, der das
  118. Format YYYYMMDDTHH:mm:ss besitzt
  119. </para>
  120. </listitem>
  121. <listitem><para><emphasis>base64</emphasis>, base64-kodierte Daten</para></listitem>
  122. <listitem><para>struct, jegliches assoziatives Array</para></listitem>
  123. </itemizedlist>
  124. <para>
  125. 'Anbei ein Beispiel für einen solchen Hinweis:
  126. </para>
  127. <programlisting language="php"><![CDATA[
  128. /**
  129. * Dies ist eine Beispielfunktion.
  130. *
  131. * @param base64 $val1 Base64-kodierte Daten
  132. * @param dateTime.iso8601 $val2 Ein ISO-Datum
  133. * @param struct $val3 ein assoziatives Array
  134. * @return struct
  135. */
  136. function myFunc($val1, $val2, $val3)
  137. {
  138. }
  139. ]]></programlisting>
  140. <para>
  141. PhpDocumentor validiert keine Typen, die in Parameter- oder
  142. Rückgabewerten angegeben sind, weshalb dies keinen Einfluss auf
  143. die <acronym>API</acronym> Dokumentation hat. Das Angeben der Hinweise ist notwendig,
  144. da der Server die, dem Methodenaufruf zugewiesenen, Parameter
  145. validiert.
  146. </para>
  147. <para>
  148. Es ist genauso gut möglich, mehrere Werte als Parameter oder für
  149. die Rückgabe anzugeben; die <acronym>XML-RPC</acronym> Spezifikation schlägt sogar
  150. vor, dass system.methodeSignatur ein Array, das alle möglichen
  151. Methodensignaturen (d.h. jegliche Kombination aus Parametern und
  152. Rückgabewerten) enthält, zurückgibt. Um dies zu erreichen, kann
  153. man, wie man es normalerweise auch beim PhpDocumentor auch tun würde,
  154. einfach den '|'-Operator nutzen.
  155. </para>
  156. <programlisting language="php"><![CDATA[
  157. /**
  158. * Dies ist eine Beispiel-Funktion.
  159. *
  160. * @param string|base64 $val1 String oder base64-kodierte Daten
  161. * @param string|dateTime.iso8601 $val2 String oder ein ISO-Datum
  162. * @param array|struct $val3 Normal indiziertes oder assoziatives Array
  163. * @return boolean|struct
  164. */
  165. function myFunc($val1, $val2, $val3)
  166. {
  167. }
  168. ]]></programlisting>
  169. <note>
  170. <para>
  171. Wenn man viele Signaturen erlaubt kann dies zu Verwirrung bei Entwicklern führen,
  172. welche diese Services nutzen; um die Dinge einfach zu halten sollte eine
  173. <acronym>XML-RPC</acronym> Methode deshalb nur eine Signatur haben.
  174. </para>
  175. </note>
  176. </sect2>
  177. <sect2 id="zend.xmlrpc.server.namespaces">
  178. <title>Nutzen von Namensräumen</title>
  179. <para>
  180. <acronym>XML-RPC</acronym> besitzt ein Konzept für Namensräume; Grundlegend erlaubt es
  181. das Gruppieren von <acronym>XML-RPC</acronym> Methoden durch Punkt-separierte
  182. Namensräume. Dies hilft, Namenkollisionen zwischen Methoden, die durch verschiedene
  183. Klassen offeriert werden, zu verhindern. Beispielsweise kann der
  184. <acronym>XML-RPC</acronym> Server mehrere Methoden im 'system'-Namensraum nutzen:
  185. </para>
  186. <itemizedlist>
  187. <listitem><para>system.listMethods</para></listitem>
  188. <listitem><para>system.methodHelp</para></listitem>
  189. <listitem><para>system.methodSignature</para></listitem>
  190. </itemizedlist>
  191. <para>
  192. Intern werden die Methoden zu Methoden desselben Namens in der
  193. Klasse <classname>Zend_XmlRpc_Server</classname> umgeleitet.
  194. </para>
  195. <para>
  196. Um angebotenen Methoden Namensräume hinzuzufügen, muss man lediglich beim
  197. Hinzufügen der gewünschten Klasse oder Funktion einen Namensraum angeben:
  198. </para>
  199. <programlisting language="php"><![CDATA[
  200. // Alle öffentlichten Methoden in My_Service_Class sind als
  201. // myservice.METHODNAME verfügbar
  202. $server->setClass('My_Service_Class', 'myservice');
  203. // Funktion 'somefunc' ist als funcs.somefunc ansprechbar.
  204. $server->addFunction('somefunc', 'funcs');
  205. ]]></programlisting>
  206. </sect2>
  207. <sect2 id="zend.xmlrpc.server.request">
  208. <title>Eigene Request-Objekte</title>
  209. <para>
  210. Die meiste Zeit wird man einfach den Standard-Anfragetyp
  211. <classname>Zend_XmlRpc_Request_Http</classname>, welcher im
  212. <classname>Zend_XmlRpc_Server</classname> enthalten ist, nutzen. Jedoch gibt es
  213. gelegentlich Fälle, in denen <acronym>XML-RPC</acronym> über die Kommandozeile
  214. (<acronym>CLI</acronym>), ein grafisches Benutzerinterface (<acronym>GUI</acronym>),
  215. eine andere Umgebung oder beim Protokollieren von ankommenden Anfragen erreichbar sein
  216. muss. Um dies zu bewerkstelligen, muss man ein eigenes Anfrage-Objekt kreieren, das
  217. <classname>Zend_XmlRpc_Request</classname> erweitert. Die wichtigste Sache, die man
  218. sich merken muss, ist sicherzustellen, dass die Methoden
  219. <methodname>getMethod()</methodname> und <methodname>getParams()</methodname>
  220. implementiert sind, so dass der <acronym>XML-RPC</acronym> Server Informationen erhält,
  221. die er für das Abfertigen einer Anfrage benötigt.
  222. </para>
  223. </sect2>
  224. <sect2 id="zend.xmlrpc.server.response">
  225. <title>Eigene Antwort-Objekte</title>
  226. <para>
  227. Ähnlich wie bei den Anfrage-Objekten, kann der <classname>Zend_XmlRpc_Server</classname>
  228. auch eigene Antwortobjekte ausliefern; standardmäßig ist dies ein
  229. <classname>Zend_XmlRpc_Response_Http-Objekt</classname>, das einen passenden
  230. Content-Type <acronym>HTTP</acronym>-Header sendet, der für <acronym>XML-RPC</acronym>
  231. genutzt wird. Mögliche Nutzungen eines eigenen Objekts sind z.B. das Protokollieren von
  232. Antworten oder das Senden der Antworten zu <constant>STDOUT</constant>.
  233. </para>
  234. <para>
  235. Um eine eigene Antwortklasse zu nutzen, muss
  236. <methodname>Zend_XmlRpc_Server::setResponseClass()</methodname> vor dem Aufruf von
  237. <methodname>handle()</methodname> aufgerufen werden.
  238. </para>
  239. </sect2>
  240. <sect2 id="zend.xmlrpc.server.fault">
  241. <title>Verarbeiten von Exceptions durch Fehler</title>
  242. <para>
  243. <classname>Zend_XmlRpc_Server</classname> fängt die, durch eine ausgeführte Methode
  244. erzeugten, Exceptions and generiert daraus einen <acronym>XML-RPC</acronym> Fehler als
  245. Antwort, wenn eine Exception gefangen wurde. Normalerweise werden die
  246. Exceptionnachrichten und -codes nicht in der Fehler-Antwort genutzt. Dies ist eine
  247. gewollte Entscheidung um den Code zu schützen; viele Exceptions entblößen mehr
  248. Informationen über den Code oder die Umgebung als der Entwickler
  249. wünscht (ein Paradebeispiel beinhaltet Datenbankabstraktion- oder
  250. die Zugriffsschichten-Exceptions).
  251. </para>
  252. <para>
  253. Exception-Klassen können jedoch anhand einer Weißliste (Whitelist) als
  254. Fehler-Antworten zurückgegeben werden. Dazu muss man lediglich die gewünschte
  255. Exception mittels
  256. <methodname>Zend_XmlRpc_Server_Fault::attachFaultException()</methodname> zur
  257. Weißliste hinzufügen:
  258. </para>
  259. <programlisting language="php"><![CDATA[
  260. Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');
  261. ]]></programlisting>
  262. <para>
  263. Abgeleitete Exceptions lassen sich als ganze Familie von Exceptions
  264. hinzufügen, indem man deren Basisklasse angibt.
  265. <classname>Zend_XmlRpc_Server_Exception</classname>'s sind immer auf der Weißliste zu
  266. finden, da sie spezielle Serverfehler berichten (undefinierte Methoden, etc.).
  267. </para>
  268. <para>
  269. Jede Exception, die nicht auf der Weißliste zu finden ist, generiert
  270. eine Antwort mit dem '404' Code und der Nachricht 'Unknown error'.
  271. </para>
  272. </sect2>
  273. <sect2 id="zend.xmlrpc.server.caching">
  274. <title>Zwischenspeichern von Serverdefinitionen zwischen den Anfragen</title>
  275. <para>
  276. Das Hinzufügen einer Vielzahl von Klassen zu einer <acronym>XML-RPC</acronym> Server
  277. Instanz kann zu einem großen Ressourcenverbrauch führen; jede Klasse muss via Reflection
  278. <acronym>API</acronym> (<classname>Zend_Server_Reflection</classname>) inspiziert
  279. werden, welche eine Liste von allen möglichen Signaturen, die der Server verwenden kann,
  280. zurückgibt.
  281. </para>
  282. <para>
  283. Um die Einbußen zu reduzieren, kann <classname>Zend_XmlRpc_Server_Cache</classname>
  284. genutzt werden, welche die Serverdefinitionen zwischen den Anfragen zwischenspeichert.
  285. Wenn dies mit <methodname>__autoload()</methodname> kombiniert wird, kann es zu einem
  286. großen Geschwindigkeitsschub kommen.
  287. </para>
  288. <para>
  289. Ein Beispiel folgt:
  290. </para>
  291. <programlisting language="php"><![CDATA[
  292. function __autoload($class)
  293. {
  294. Zend_Loader::loadClass($class);
  295. }
  296. $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
  297. $server = new Zend_XmlRpc_Server();
  298. if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
  299. require_once 'My/Services/Glue.php';
  300. require_once 'My/Services/Paste.php';
  301. require_once 'My/Services/Tape.php';
  302. $server->setClass('My_Services_Glue', 'glue'); // glue. Namensraum
  303. $server->setClass('My_Services_Paste', 'paste'); // paste. Namensraum
  304. $server->setClass('My_Services_Tape', 'tape'); // tape. Namensraum
  305. Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
  306. }
  307. echo $server->handle();
  308. ]]></programlisting>
  309. <para>
  310. Obiges Beispiel zeigt, wie der Server versucht, eine Definition
  311. aus der Datei <property>xmlrpc.cache</property>, welches sich im selben Ordner wie das
  312. Skript befindet, zu laden. Wenn dies nicht erfolgreich ist,
  313. lädt es die Server-Klassen, die es benötigt, und fügt sie zum
  314. Server hinzu. Danach wird versucht, die Cache-Datei mit der
  315. Serverdefinition zu erstellen.
  316. </para>
  317. </sect2>
  318. <sect2 id="zend.xmlrpc.server.use">
  319. <title>Nutzungsbeispiele</title>
  320. <para>
  321. Unten finden sich etliche Beispiele für eine Nutzung, die das
  322. gesamte Spektrum der verfügbaren Optionen für den Entwickler darstellen.
  323. These Beispiele bauen immer auf den vorangegangenen Beispielen auf.
  324. </para>
  325. <example id="zend.xmlrpc.server.use.attach-function">
  326. <title>Grundlegende Benutzung</title>
  327. <para>
  328. Folgendes Beispiel fügt eine Funktion als ausführbare
  329. <acronym>XML-RPC</acronym> Methode hinzu und verarbeitet eingehende Aufrufe.
  330. </para>
  331. <programlisting language="php"><![CDATA[
  332. /**
  333. * Gibt die MD5-Summe eines Strings zurück.
  334. *
  335. * @param string $value Wert aus dem die MD5-Summe errechnet wird
  336. * @return string MD5-Summe des Werts
  337. */
  338. function md5Value($value)
  339. {
  340. return md5($value);
  341. }
  342. $server = new Zend_XmlRpc_Server();
  343. $server->addFunction('md5Value');
  344. echo $server->handle();
  345. ]]></programlisting>
  346. </example>
  347. <example id="zend.xmlrpc.server.use.attach-class">
  348. <title>Hinzufügen einer Klasse</title>
  349. <para>
  350. Das nächste Beispiel illustriert, wie man die öffentlichen Methoden
  351. eienr Klasse als ausführbare <acronym>XML-RPC</acronym> Methoden hinzufügt.
  352. </para>
  353. <programlisting language="php"><![CDATA[
  354. $server = new Zend_XmlRpc_Server();
  355. $server->setClass('Services_Comb');
  356. echo $server->handle();
  357. ]]></programlisting>
  358. </example>
  359. <example id="zend.xmlrpc.server.use.attach-class-with-arguments">
  360. <title>Hinzufügen einer Klasse mit Argumenten</title>
  361. <para>
  362. Das folgende Beispiel zeigt wie öffentliche Methoden einer Klasse hinzugefügt werden
  363. und an deren Methoden Argumente übergeben werden können. Das kann verwendet werden
  364. um spezielle Standardwerte zu spezifizieren wenn Serviceklassen registriert werden.
  365. </para>
  366. <programlisting language="php"><![CDATA[
  367. class Services_PricingService
  368. {
  369. /**
  370. * Calculate current price of product with $productId
  371. *
  372. * @param ProductRepository $productRepository
  373. * @param PurchaseRepository $purchaseRepository
  374. * @param integer $productId
  375. */
  376. public function calculate(ProductRepository $productRepository,
  377. PurchaseRepository $purchaseRepository,
  378. $productId)
  379. {
  380. ...
  381. }
  382. }
  383. $server = new Zend_XmlRpc_Server();
  384. $server->setClass('Services_PricingService',
  385. 'pricing',
  386. new ProductRepository(),
  387. new PurchaseRepository());
  388. ]]></programlisting>
  389. <para>
  390. Die Argumente welche an <methodname>setClass()</methodname> wärend der
  391. Erstellungszeit des Servers übergeben werden, werden dem Methodenaufruf
  392. <command>pricing.calculate()</command> injiziert, wenn er aufgerufen wird. Im obigen
  393. Beispiel wird vom Client nur das Argument <code>$purchaseId</code> erwartet.
  394. </para>
  395. </example>
  396. <example id="zend.xmlrpc.server.use.attach-class-with-arguments-constructor">
  397. <title>Argumente nur dem Constructor übergeben</title>
  398. <para>
  399. <classname>Zend_XmlRpc_Server</classname> erlaubt es die Übergabe von Argumenten nur
  400. für den Constructor zu limitieren. Das kann für Dependency Injection beim
  401. Constructor verwendet werden. Um die Injektion auf Constructoren zu begrenzen muss
  402. <methodname>sendArgumentsToAllMethods</methodname> aufgerufen und
  403. <constant>FALSE</constant> als Argument übergeben werden. Dies deaktiviert das
  404. Standardverhalten mit dem alle Argumente in die entfernte Methode injiziert werden.
  405. Im nächsten Beispiel werden die Instanzen von
  406. <classname>ProductRepository</classname> und
  407. <classname>PurchaseRepository</classname> nur in dem Constructor von
  408. <classname>Services_PricingService2</classname> injiziert.
  409. </para>
  410. <programlisting language="php"><![CDATA[
  411. class Services_PricingService2
  412. {
  413. /**
  414. * @param ProductRepository $productRepository
  415. * @param PurchaseRepository $purchaseRepository
  416. */
  417. public function __construct(ProductRepository $productRepository,
  418. PurchaseRepository $purchaseRepository)
  419. {
  420. ...
  421. }
  422. /**
  423. * Calculate current price of product with $productId
  424. *
  425. * @param integer $productId
  426. * @return double
  427. */
  428. public function calculate($productId)
  429. {
  430. ...
  431. }
  432. }
  433. $server = new Zend_XmlRpc_Server();
  434. $server->sendArgumentsToAllMethods(false);
  435. $server->setClass('Services_PricingService2',
  436. 'pricing',
  437. new ProductRepository(),
  438. new PurchaseRepository());
  439. ]]></programlisting>
  440. </example>
  441. <example id="zend.xmlrpc.server.use.attach-instance">
  442. <title>Die Instanz einer Klasse anhängen</title>
  443. <para>
  444. <methodname>setClass()</methodname> erlaubt es ein vorher instanziertes Objekt beim
  445. Server zu registrieren. Man muss nur die Instanz statt dem Namen der Klasse
  446. übergeben. Natürlich ist die Übergabe von Argumenten an den Constructor bei vorher
  447. instanzierten Objekten nicht möglich.
  448. </para>
  449. </example>
  450. <example id="zend.xmlrpc.server.use.attach-several-classes-namespaces">
  451. <title>Mehrere Klassen unter der Nutzung von Namensräumen hinzufügen</title>
  452. <para>
  453. Das nächste Beispiel zeigt, wie man mehrer Klassen mit ihren eigenen
  454. Namensräumen hinzufügt.
  455. </para>
  456. <programlisting language="php"><![CDATA[
  457. require_once 'Services/Comb.php';
  458. require_once 'Services/Brush.php';
  459. require_once 'Services/Pick.php';
  460. $server = new Zend_XmlRpc_Server();
  461. // Methoden werden als comb.* aufgerufen
  462. $server->setClass('Services_Comb', 'comb');
  463. // Methoden werden als brush.* aufgerufen
  464. $server->setClass('Services_Brush', 'brush');
  465. // Methoden werden als pick.* aufgerufen
  466. $server->setClass('Services_Pick', 'pick');
  467. echo $server->handle();
  468. ]]></programlisting>
  469. </example>
  470. <example id="zend.xmlrpc.server.use.example-faults">
  471. <title>Bestimmen von Exceptions als valide Fehler-Antwort</title>
  472. <para>
  473. Im nächsten Beispiel wird gezeigt, wie man jede Exception, die von
  474. <classname>Services_Exception</classname> abgeleitet wurde, als Fehler-Antwort
  475. nutzen kann, dessen Nachricht und Code erhalten bleibt.
  476. </para>
  477. <programlisting language="php"><![CDATA[
  478. require_once 'Services/Exception.php';
  479. require_once 'Services/Comb.php';
  480. require_once 'Services/Brush.php';
  481. require_once 'Services/Pick.php';
  482. // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
  483. Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
  484. $server = new Zend_XmlRpc_Server();
  485. // Methoden werden als comb.* aufgerufen
  486. $server->setClass('Services_Comb', 'comb');
  487. // Methoden werden als brush.* aufgerufen
  488. $server->setClass('Services_Brush', 'brush');
  489. // Methoden werden als pick.* aufgerufen
  490. $server->setClass('Services_Pick', 'pick');
  491. echo $server->handle();
  492. ]]></programlisting>
  493. </example>
  494. <example id="zend.xmlrpc.server.use.custom-request-object">
  495. <title>Anpassen eigener Anfrage und Antwort Objekte</title>
  496. <para>
  497. Einige Anwendungsfälle verlangen die Verwendung eines eigenen Request Objektes.
  498. Zum Beispiel ist <acronym>XML/RPC</acronym> nicht an <acronym>HTTP</acronym> als
  499. Übertragungsprotokoll gebunden. Es ist möglich auch andere Übertragungsprotokolle
  500. wie <acronym>SSH</acronym> oder Telnet zu verwenden um Anfrage und Antwort Daten
  501. über den Draht zu senden. Ein anderer Anwendungsfall ist die Authentifizierung
  502. und Authorisierung. Im Falle eines anderen Übertragungsprotokolls muss die
  503. Implementation geändert werden damit Anfrage Daten gelesen werden können.
  504. </para>
  505. <para>
  506. Im folgenden Beispiel wird ein eigenes Anfrage-Objekt instanziert
  507. und durch den Server verarbeitet.
  508. </para>
  509. <programlisting language="php"><![CDATA[
  510. require_once 'Services/Request.php';
  511. require_once 'Services/Exception.php';
  512. require_once 'Services/Comb.php';
  513. require_once 'Services/Brush.php';
  514. require_once 'Services/Pick.php';
  515. // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
  516. Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
  517. $server = new Zend_XmlRpc_Server();
  518. // Methoden werden als comb.* aufgerufen
  519. $server->setClass('Services_Comb', 'comb');
  520. // Methoden werden als brush.* aufgerufen
  521. $server->setClass('Services_Brush', 'brush');
  522. // Methoden werden als pick.* aufgerufen
  523. $server->setClass('Services_Pick', 'pick');
  524. // Ein neues Anfrage-Objekt wird erstellt
  525. $request = new Services_Request();
  526. echo $server->handle($request);
  527. ]]></programlisting>
  528. </example>
  529. <example id="zend.xmlrpc.server.use.custom-response-object">
  530. <title>Eine eigene Antwort Klasse spezifizieren</title>
  531. <para>
  532. Das nachstehende Beispiel zeigt, wie man eine eigene Antwort-Klasse
  533. als zurückgegebene Antwort für den Server setzt.
  534. </para>
  535. <programlisting language="php"><![CDATA[
  536. require_once 'Services/Request.php';
  537. require_once 'Services/Response.php';
  538. require_once 'Services/Exception.php';
  539. require_once 'Services/Comb.php';
  540. require_once 'Services/Brush.php';
  541. require_once 'Services/Pick.php';
  542. // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
  543. Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
  544. $server = new Zend_XmlRpc_Server();
  545. // Methoden werden als comb.* aufgerufen
  546. $server->setClass('Services_Comb', 'comb');
  547. // Methoden werden als brush.* aufgerufen
  548. $server->setClass('Services_Brush', 'brush');
  549. // Methoden werden als pick.* aufgerufen
  550. $server->setClass('Services_Pick', 'pick');
  551. // Ein neues Anfrage-Objekt wird erstellt
  552. $request = new Services_Request();
  553. // Nutzen eigener Antwort-Klasse
  554. $server->setResponseClass('Services_Response');
  555. echo $server->handle($request);
  556. ]]></programlisting>
  557. </example>
  558. </sect2>
  559. <sect2 id="zend.xmlrpc.server.performance">
  560. <title>Performance Optimierung</title>
  561. <example id="zend.xmlrpc.server.performance.caching">
  562. <title>Zwischenspeichern von Serverdefinition zwischen den Anfragen</title>
  563. <para>
  564. Dieses Beispiel zeigt, wie man Serverdefinitionen zwischen verschiedenen
  565. Anfragen zwischenspeichern kann.
  566. </para>
  567. <programlisting language="php"><![CDATA[
  568. // Definieren einer Cache-Datei
  569. $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
  570. // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
  571. Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
  572. $server = new Zend_XmlRpc_Server();
  573. // Versucht die Serverdefinition aus dem Cache zu laden
  574. if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
  575. // Methoden werden als comb.* aufgerufen
  576. $server->setClass('Services_Comb', 'comb');
  577. // Methoden werden als brush.* aufgerufen
  578. $server->setClass('Services_Brush', 'brush');
  579. // Methoden werden als pick.* aufgerufen
  580. $server->setClass('Services_Pick', 'pick');
  581. // Speichern des Caches
  582. Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
  583. }
  584. // Ein neues Anfrage-Objekt wird erstellt
  585. $request = new Services_Request();
  586. // Nutzen eigener Antwort-Klasse
  587. $server->setResponseClass('Services_Response');
  588. echo $server->handle($request);
  589. ]]></programlisting>
  590. <note>
  591. <para>
  592. Die Datei des Server Caches sollte ausserhalb des Document Roots platziert
  593. werden.
  594. </para>
  595. </note>
  596. </example>
  597. <example id="zend.xmlrpc.server.performance.xmlgen">
  598. <title>Optimizing XML generation</title>
  599. <para>
  600. <classname>Zend_XmlRpc_Server</classname> verwendet
  601. <classname>DOMDocument</classname> der <acronym>PHP</acronym> Erweiterung
  602. <code>ext/dom</code> um seine <acronym>XML</acronym> Ausgaben zu erstellen. Wärend
  603. <code>ext/dom</code> auf vielen Hosts vorhanden ist, ist es nicht wirklich das
  604. schnellste. Benchmarks haben gezeigt das <classname>XMLWriter</classname> von
  605. <code>ext/xmlwriter</code> schneller ist.
  606. </para>
  607. <para>
  608. Wenn <code>ext/xmlwriter</code> auf dem eigenen Host vorhanden ist, kann ein
  609. <classname>XMLWriter</classname>-basierter Generator ausgewählt werden um die
  610. Performance Unterschiede auszunutzen.
  611. </para>
  612. <programlisting language="php"><![CDATA[
  613. require_once 'Zend/XmlRpc/Server.php';
  614. require_once 'Zend/XmlRpc/Generator/XMLWriter.php';
  615. Zend_XmlRpc_Value::setGenerator(new Zend_XmlRpc_Generator_XMLWriter());
  616. $server = new Zend_XmlRpc_Server();
  617. ...
  618. ]]></programlisting>
  619. </example>
  620. <note>
  621. <title>Die eigene Anwendung benchmarken</title>
  622. <para>
  623. Performance wird durch eine Vielzahl an Parametern und Benchmarks ermittelt
  624. welche nur für den speziellen Testfall angewendet werden. Unterschiede basieren
  625. auf der PHP Version, installierten Erweiterungen, dem Webserver und dem
  626. Betriebssystem um nur einige zu nennen. Man sollte darauf achten das man die
  627. eigene Anwendung selbst benchmarkt und anschließend auswählt welchen Generator
  628. man verwendet, aber basierend auf <emphasis>eigenen</emphasis> Zahlen.
  629. </para>
  630. </note>
  631. <note>
  632. <title>Den eigenen Client benchmarken</title>
  633. <para>
  634. Diese Optimierung macht auch für die Client Seite Sinn. Man muss den
  635. alternativen <acronym>XML</acronym> Generator nur auswählen bevor man irgendeine
  636. Arbeit mit <classname>Zend_XmlRpc_Client</classname> durchführt.
  637. </para>
  638. </note>
  639. </sect2>
  640. </sect1>
  641. <!--
  642. vim:se ts=4 sw=4 et:
  643. -->