fix php 5.6 in docker dev env (#1740)
[openemr.git] / vendor / zendframework / zend-xmlrpc / doc / book / server.md
blob97ac1be22c0be91fe9e3b2392f654eb1c66a7db2
1 # Zend\\XmlRpc\\Server
3 `Zend\XmlRpc\Server` is a fully-featured XML-RPC server, following
4 [the specifications outlined at www.xmlrpc.com](http://www.xmlrpc.com/spec).
5 Additionally, it implements the `system.multicall()` method, allowing boxcarring
6 of requests.
8 ## Basic Usage
10 ```php
11 $server = new Zend\XmlRpc\Server();
12 $server->setClass('My\Service\Class');
13 echo $server->handle();
14 ```
16 ## Server Structure
18 `Zend\XmlRpc\Server` is composed of a variety of components, ranging from the
19 server itself to request, response, and fault objects.
21 To bootstrap `Zend\XmlRpc\Server`, the developer must attach one or more classes
22 or functions to the server, via the `setClass()` and `addFunction()` methods.
24 Once done, you may either pass a `Zend\XmlRpc\Request` object to
25 `Zend\XmlRpc\Server::handle()`, or it will instantiate a
26 `Zend\XmlRpc\Request\Http` object if none is provided, thus grabbing the request
27 from `php://input`.
29 `Zend\XmlRpc\Server::handle()` then attempts to dispatch to the appropriate
30 handler based on the method requested. It then returns either a
31 `Zend\XmlRpc\Response`-based object or a `Zend\XmlRpc\Server\Fault` object.
32 These objects both have `__toString()` methods that create valid XML-RPC XML
33 responses, allowing them to be directly echoed.
35 ## Anatomy of a webservice
37 ### General considerations
39 For maximum performance it is recommended to use a simple bootstrap file for the
40 server component.  Using `Zend\XmlRpc\Server` inside a
41 [Zend\\Mvc\\Controller](https://zendframework.github.io/zend-mvc/) is strongly
42 discouraged to avoid the overhead.
44 Services change over time and while webservices are generally less change
45 intense as code-native APIs, it is recommended to version your service. Do so to
46 lay grounds to provide compatibility for clients using older versions of your
47 service and manage your service lifecycle including deprecation timeframes. To
48 do so just include a version number into your URI. It is also recommended to
49 include the remote protocol name in the URI to allow easy integration of
50 upcoming remoting technologies. `http://myservice.ws/1.0/XMLRPC/`.
52 ### What to expose?
54 Most of the time it is not sensible to expose business objects directly.
55 Business objects are usually small and under heavy change, because change is
56 cheap in this layer of your application.  Once deployed and adopted, web
57 services are hard to change. Another concern is I/O and latency: the best
58 webservice calls are those not happening. Therefore service calls need to be
59 more coarse-grained than usual business logic is. Often an additional layer in
60 front of your business objects makes sense. This layer is sometimes referred to
61 as [Remote Facade](http://martinfowler.com/eaaCatalog/remoteFacade.html). Such a
62 service layer adds a coarse grained interface on top of your business logic and
63 groups verbose operations into smaller ones.
65 ## Conventions
67 `Zend\XmlRpc\Server` allows the developer to attach functions and class method
68 calls as dispatchable XML-RPC methods. Via `Zend\Server\Reflection`, it does
69 introspection on all attached methods, using the function and method docblocks
70 to determine the method help text and method signatures.
72 XML-RPC types do not necessarily map one-to-one to PHP types. However, the code
73 will do its best to guess the appropriate type based on the values listed in
74 `@param` and `@return` annotations. Some XML-RPC types have no immediate PHP
75 equivalent, however, and should be hinted using the XML-RPC type in the PHPDoc.
76 These include:
78 * `dateTime.iso8601`, a string formatted as '`YYYYMMDDTHH:mm:ss`'
79 * `base64`, base64 encoded data
80 * `struct`, any associative array
82 An example of how to hint follows:
84 ```php
85 /**
86  * This is a sample function
87  *
88  * @param base64 $val1 Base64-encoded data
89  * @param dateTime.iso8601 $val2 An ISO date
90  * @param struct $val3 An associative array
91  * @return struct
92  */
93 function myFunc($val1, $val2, $val3)
96 ```
98 PhpDocumentor does not validate types specified for params or return values, so
99 this will have no impact on your API documentation. Providing the hinting is
100 necessary, however, when the server is validating the parameters provided to the
101 method call.
103 It is perfectly valid to specify multiple types for both params and return
104 values; the XML-RPC specification even suggests that `system.methodSignature`
105 should return an array of all possible method signatures (i.e., all possible
106 combinations of param and return values). You may do so just as you normally
107 would with PhpDocumentor, using the `|` operator:
109 ```php
111  * This is a sample function
113  * @param string|base64 $val1 String or base64-encoded data
114  * @param string|dateTime.iso8601 $val2 String or an ISO date
115  * @param array|struct $val3 Normal indexed array or an associative array
116  * @return boolean|struct
117  */
118 function myFunc($val1, $val2, $val3)
123 > ### Use multiple values sparingly
125 > Allowing multiple signatures can lead to confusion for developers using the
126 > services; to keep things simple, a XML-RPC service method should typically
127 > only present a single signature.
129 ## Utilizing Namespaces
131 XML-RPC allows grouping related methods under dot-delimited *namespaces*. This
132 helps prevent naming collisions between methods served by different classes. As
133 an example, the XML-RPC server is expected to server several methods in the
134 `system` namespace:
136 - `system.listMethods`
137 - `system.methodHelp`
138 - `system.methodSignature`
140 Internally, these map to the methods of the same name in `Zend\XmlRpc\Server`.
142 If you want to add namespaces to the methods you serve, simply provide a
143 namespace to the appropriate method when attaching a function or class:
145 ```php
146 // All public methods in My\Service\Class will be accessible as
147 // myservice.METHODNAME
148 $server->setClass('My\Service\Class', 'myservice');
150 // Function 'somefunc' will be accessible as funcs.somefunc
151 $server->addFunction('somefunc', 'funcs');
154 ## Custom Request Objects
156 Most of the time, you'll simply use the default request type included with
157 `Zend\XmlRpc\Server`, `Zend\XmlRpc\Request\Http`. However, there may be times
158 when you need XML-RPC to be available via the CLI, a GUI, or other environment,
159 or want to log incoming requests. To do so, you may create a custom request
160 object that extends `Zend\XmlRpc\Request`. The most important thing to remember
161 is to ensure that the `getMethod()` and `getParams()` methods are implemented so
162 that the XML-RPC server can retrieve that information in order to dispatch the
163 request.
165 ## Custom Responses
167 Similar to request objects, `Zend\XmlRpc\Server` can return custom response
168 objects; by default, a `Zend\XmlRpc\Response\Http` object is returned, which
169 sends an appropriate `Content-Type` HTTP header for use with XML-RPC. Possible
170 uses of a custom object would be to log responses, or to send responses back to
171 `STDOUT`.
173 To use a custom response class, use `Zend\XmlRpc\Server::setResponseClass()`
174 prior to calling `handle()`.
176 ## Handling Exceptions via Faults
178 `Zend\XmlRpc\Server` catches Exceptions generated by a dispatched method, and
179 generates an XML-RPC fault response when such an exception is caught. By
180 default, however, the exception messages and codes are not used in a fault
181 response. This is an intentional decision to protect your code; many exceptions
182 expose more information about the code or environment than a developer would
183 necessarily intend (a prime example includes database exceptions).
185 Exception classes can be whitelisted to be used as fault responses, however. To
186 do so, call `Zend\XmlRpc\Server\Fault::attachFaultException()` and pass an
187 exception class to whitelist:
189 ```php
190 Zend\XmlRpc\Server\Fault::attachFaultException('My\Project\Exception');
193 If you utilize an exception class that your other project exceptions inherit,
194 you can then whitelist a whole family of exceptions at a time.
195 `Zend\XmlRpc\Server\Exception`s are always whitelisted, to allow reporting
196 specific internal errors (undefined methods, etc.).
198 Any exception not specifically whitelisted will generate a fault response with a
199 code of '404' and a message of 'Unknown error'.
201 ## Caching Server Definitions Between Requests
203 Attaching many classes to an XML-RPC server instance can utilize a lot of
204 resources; each class must introspect using the Reflection API (via
205 `Zend\Server\Reflection`), which in turn generates a list of all possible method
206 signatures to provide to the server class.
208 To reduce this performance hit somewhat, `Zend\XmlRpc\Server\Cache` can be used
209 to cache the server definition between requests.
211 An sample usage follows:
213 ```php
214 use My\Service as s;
215 use Zend\XmlRpc\Server as XmlRpcServer;
217 $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
218 $server = new XmlRpcServer();
220 if (! XmlRpcServer\Cache::get($cacheFile, $server)) {
222     $server->setClass(s\Glue::class, 'glue');   // glue. namespace
223     $server->setClass(s\Paste::class, 'paste'); // paste. namespace
224     $server->setClass(s\Tape::class, 'tape');   // tape. namespace
226     XmlRpcServer\Cache::save($cacheFile, $server);
229 echo $server->handle();
232 The above example attempts to retrieve a server definition from `xmlrpc.cache`
233 in the same directory as the script. If unsuccessful, it loads the service
234 classes it needs, attaches them to the server instance, and then attempts to
235 create a new cache file with the server definition.
237 ## Usage Examples
239 Below are several usage examples, showing the full spectrum of options available
240 to developers.  Usage examples will each build on the previous example provided.
242 ### Basic Usage
244 The example below attaches a function as a dispatchable XML-RPC method and
245 handles incoming calls.
247 ```php
249  * Return the MD5 sum of a value
251  * @param string $value Value to md5sum
252  * @return string MD5 sum of value
253  */
254 function md5Value($value)
256     return md5($value);
259 $server = new Zend\XmlRpc\Server();
260 $server->addFunction('md5Value');
261 echo $server->handle();
264 ### Attaching a class
266 The example below illustrates attaching a class' public methods as dispatchable
267 XML-RPC methods.
269 ```php
270 require_once 'Services/Comb.php';
272 $server = new Zend\XmlRpc\Server();
273 $server->setClass('Services\Comb');
274 echo $server->handle();
277 ### Attaching a class with arguments
279 The following example illustrates how to attach a class' public methods and
280 passing arguments to its methods. This can be used to specify certain defaults
281 when registering service classes.
283 ```php
284 namespace Services;
286 class PricingService
288     /**
289      * Calculate current price of product with $productId
290      *
291      * @param ProductRepository $productRepository
292      * @param PurchaseRepository $purchaseRepository
293      * @param integer $productId
294      */
295     public function calculate(
296         ProductRepository $productRepository,
297         PurchaseRepository $purchaseRepository,
298         $productId
299     ) {
300         /* ... */
301     }
304 $server = new Zend\XmlRpc\Server();
305 $server->setClass(
306     'Services\PricingService',
307     'pricing',
308     new ProductRepository(),
309     new PurchaseRepository()
313 The arguments passed to `setClass()` are injected into the method call
314 `pricing.calculate()` on remote invocation. In the example above, only the
315 argument `$productId` is expected from the client.
317 ### Passing arguments only to constructor
319 `Zend\XmlRpc\Server` allows providing constructor arguments when specifying
320 classes, instead of when invoking methods.
322 To limit injection to constructors, call `sendArgumentsToAllMethods` and pass
323 `FALSE` as an argument. This disables the default behavior of all arguments
324 being injected into the remote method. In the example below, the instance of
325 `ProductRepository` and `PurchaseRepository` is only injected into the
326 constructor of `Services\PricingService2`.
328 ```php
329 class Services\PricingService2
331     /**
332      * @param ProductRepository $productRepository
333      * @param PurchaseRepository $purchaseRepository
334      */
335     public function __construct(
336         ProductRepository $productRepository,
337         PurchaseRepository $purchaseRepository
338     ) {
339         /* ... */
340     }
342     /**
343      * Calculate current price of product with $productId
344      *
345      * @param integer $productId
346      * @return double
347      */
348     public function calculate($productId)
349     {
350         ...
351     }
354 $server = new Zend\XmlRpc\Server();
356 // Tell the server to pass arguments to constructors instead of at invocation:
357 $server->sendArgumentsToAllMethods(false);
359 // Map the class:
360 $server->setClass(
361     'Services\PricingService2',
362     'pricing',
363     new ProductRepository(),
364     new PurchaseRepository()
368 ### Attaching a class instance
370 `setClass()` allows registering a previously instantiated class with the server,
371 instead of specifying the class name. Obviously, passing arguments to the
372 constructor is not possible with pre-instantiated classes.
374 ### Attaching several classes using namespaces
376 The example below illustrates attaching several classes, each with their own
377 namespace.
379 ```php
380 use Services as s;
381 use Zend\XmlRpc\Server as XmlRpcServer;
383 $server = new XmlRpcServer();
384 $server->setClass(s\Comb::class, 'comb');   // methods called as comb.*
385 $server->setClass(s\Brush::class, 'brush'); // methods called as brush.*
386 $server->setClass(s\Pick::class, 'pick');   // methods called as pick.*
387 echo $server->handle();
390 ### Specifying exceptions to use as valid fault responses
392 The example below allows any `Services\Exception`-derived class to report its
393 code and message in the fault response.
395 ```php
396 use Services as s;
397 use Zend\XmlRpc\Server as XmlRpcServer;
398 use Zend\XmlRpc\Server\Fault as XmlRpcFault;
400 // Allow Services_Exceptions to report as fault responses
401 XmlRpcFault::attachFaultException(s\Exception::class);
403 $server = new XmlRpcServer();
404 $server->setClass(s\Comb::class, 'comb');   // methods called as comb.*
405 $server->setClass(s\Brush::class, 'brush'); // methods called as brush.*
406 $server->setClass(s\Pick::class, 'pick');   // methods called as pick.*
407 echo $server->handle();
410 ### Utilizing custom request and response objects
412 Some use cases require custom request objects; XML-RPC is not bound to HTTP as a
413 transfer protocol. It is possible to use other transfer protocols like SSH or
414 telnet to send the request and response data over the wire. Another use case is
415 authentication and authorization. When a different transfer protocol is
416 required, you will need to change the implementation to read request data.
418 The example below instantiates a custom request class and passes it to the
419 server to handle.
421 ```php
422 use Services as s;
423 use Zend\XmlRpc\Server as XmlRpcServer;
424 use Zend\XmlRpc\Server\Fault as XmlRpcFault;
426 // Allow Services_Exceptions to report as fault responses
427 XmlRpcFault::attachFaultException(s\Exception::class);
429 $server = new XmlRpcServer();
430 $server->setClass(s\Comb::class, 'comb');   // methods called as comb.*
431 $server->setClass(s\Brush::class, 'brush'); // methods called as brush.*
432 $server->setClass(s\Pick::class, 'pick');   // methods called as pick.*
434 // Create a request object
435 $request = new s\Request();
437 echo $server->handle($request);
440 ### Specifying a custom response class
442 The example below illustrates specifying a custom response class for the returned response.
444 ```php
445 use Services as s;
446 use Zend\XmlRpc\Server as XmlRpcServer;
447 use Zend\XmlRpc\Server\Fault as XmlRpcFault;
449 // Allow Services_Exceptions to report as fault responses
450 XmlRpcFault::attachFaultException(s\Exception::class);
452 $server = new XmlRpcServer();
453 $server->setClass(s\Comb::class, 'comb');   // methods called as comb.*
454 $server->setClass(s\Brush::class, 'brush'); // methods called as brush.*
455 $server->setClass(s\Pick::class, 'pick');   // methods called as pick.*
457 // Create a request object
458 $request = new s\Request();
460 // Utilize a custom response
461 $server->setResponseClass(s\Response::class);
463 echo $server->handle($request);
466 ## Performance optimization
468 ### Cache server definitions between requests
470 The example below illustrates caching server definitions between requests.
472 ```php
473 use Services as s;
474 use Zend\XmlRpc\Server as XmlRpcServer;
475 use Zend\XmlRpc\Server\Fault as XmlRpcFault;
477 // Specify a cache file
478 $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
480 // Allow Services\Exceptions to report as fault responses
481 XmlRpcFault::attachFaultException(s\Exception::class);
483 $server = new XmlRpcServer();
485 // Attempt to retrieve server definition from cache
486 if (! XmlRpcServer\Cache::get($cacheFile, $server)) {
487     $server->setClass(s\Comb::class, 'comb');   // methods called as comb.*
488     $server->setClass(s\Brush::class, 'brush'); // methods called as brush.*
489     $server->setClass(s\Pick::class, 'pick');   // methods called as pick.*
491     // Save cache
492     XmlRpcServer\Cache::save($cacheFile, $server);
495 // Create a request object
496 $request = new s\Request();
498 // Utilize a custom response
499 $server->setResponseClass(s\Response::class);
501 echo $server->handle($request);
504 > ### Cache file location
506 > The server cache file should be located outside the document root.
508 ### Optimizing XML generation
510 `Zend\XmlRpc\Server` uses `DOMDocument` to generate it's XML output. While this
511 functionality is available on most hosts, it's not always the most performant
512 solution; benchmarks have shown that `XmlWriter` performs better.
514 If `ext/xmlwriter` is available on your host, you can select the
515 `XmlWriter`-based generator to leverage the performance differences.
517 ```php
518 use Zend\XmlRpc;
520 XmlRpc\AbstractValue::setGenerator(new XmlRpc\Generator\XmlWriter());
522 $server = new XmlRpc\Server();
525 > #### Benchmark your application
527 > Performance is determined by many parameters, and benchmarks only apply for
528 > the specific test case. Differences come from PHP version, installed
529 > extensions, webserver, and operating system just to name a few. Please make
530 > sure to benchmark your application on your own and decide which generator to
531 > use based on **your** numbers.
533 > #### Benchmark your client
535 > Optimization makes sense for the client side too. Just select the alternate
536 > XML generator before doing any work with `Zend\XmlRpc\Client`.