2
0

Zend_XmlRpc_Server.xml 31 KB

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