29.3. Zend_XmlRpc_Server
Poprzedni | Rozdział 29. Zend_XmlRpc | Następny

## 29.3. Zend_XmlRpc_Server

### 29.3.1. Wprowadzenie

Klasa Zend_XmlRpc_Server jest przeznaczona do użycia jako pełnofunkcjonalny serwer XML-RPC, zgodny ze specyfikacją przedstawioną na www.xmlrpc.com. Dodatkowo implementuje ona metodę system.multicall(), pozwalającą na wywołanie wielu metod podczas jednego żądania.

### 29.3.2. Podstawowe użycie

Przykład najbardziej podstawowego przypadku użycia:

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'My/Service/Class.php';

    $server = new Zend_XmlRpc_Server();
    $server->setClass('My_Service_Class');
    echo $server->handle();

### 29.3.3. Struktura serwera

Zend_XmlRpc_Server składa się z wielu różnych komponentów, od samego serwera, przez obiekty żądania, obiekty odpowiedzi aż do obiektów błędów.

Aby uruchomić serwer Zend_XmlRpc_Server, programista musi dołączyć jedną lub więcej klas albo funkcji do serwera, za pomocą metod `setClass()` oraz `addFunction()`.

Kiedy jest to już zrobione, możesz przekazać obiekt `Zend_XmlRpc_Request` do metody `Zend_XmlRpc_Server::handle()`, lub zostanie utworzona instancja obiektu `Zend_XmlRpc_Request_Http` w przypadku gdy nie zostanie zapewniony żaden obiekt -- spowoduje to pobieranie żądań z `php://input`.

`Zend_XmlRpc_Server::handle()` próbuje wtedy uruchomić odpowiednią klasę obsługującą, zależnie od użytej metody dostępu. Zwraca wtedy obiekt oparty na `Zend_XmlRpc_Response` lub obiekt `Zend_XmlRpc_Server_Fault`. Oba te obiekty mają dostępne metody `__toString()`, ktore tworzą poprawne odpowiedzi XML-RPC, pozwalając na bezpośrednie ich wyświetlenie.

### 29.3.4. Konwencje

Zend_XmlRpc_Server pozwala programiście dołączać funkcje oraz metody klas jako uruchamialne metody XML-RPC. Poprzez Zend_Server_Reflection, przeprowadzana jest introspekcja dla wszystkich dołączanych metod, używając bloków dokumentacji funkcji i metod do określenia opisów pomocy dla metod oraz sygnatur metod.

XML-RPC types do not necessarily map one-to-one to PHP types. However, the code will do its best to guess the appropriate type based on the values listed in @param and @return lines. Some XML-RPC types have no immediate PHP equivalent, however, and should be hinted using the XML-RPC type in the phpdoc. These include:

- dateTime.iso8601, łańcuch znaków sformatowany jako YYYYMMDDTHH:mm:ss

- base64, dane zakodowane jako base64

- struct, dowolna tablica asocjacyjna

Przykład wywołania przykładowej funkcji:

    <?php
    /**
    * To jest przykładowa funkcja
    *
    * @param base64 $val1 Dane zakodowane jako Base64
    * @param dateTime.iso8601 $val2 Data ISO
    * @param struct $val3 Tablica asocjacyjna
    * @return struct
    */
    function myFunc($val1, $val2, $val3)
    {
    }

PhpDocumentor nie przeprowadza walidacji typów określonych dla parametrów lub zwracanych wartości, więc nie będzie to miało wpływu na twoją dokumentację API Providing the hinting is necessary, however, when the server is validating the parameters provided to the method call.

It is perfectly valid to specify multiple types for both params and return values; the XML-RPC specification even suggests that system.methodSignature should return an array of all possible method signatures (i.e., all possible combinations of param and return values). You may do so just as you normally would with PhpDocumentor, using the '|' operator:

    <?php
    /**
    * To jest przykładowa funkcja
    *
    * @param string|base64 $val1 Łańcuch znaków lub dane zakodowane jako base64
    * @param string|dateTime.iso8601 $val2 Łańcuch znaków lub data ISO
    * @param array|struct $val3 Normalnie indeksowana tablica lub tablica asocjacyjna
    * @return boolean|struct
    */
    function myFunc($val1, $val2, $val3)
    {
    }

One note, however: allowing multiple signatures can lead to confusion for developers using the services; generally speaking, an XML-RPC method should only have a single signature.

### 29.3.5. Używanie przestrzeni nazw

XML-RPC has a concept of namespacing; basically, it allows grouping XML-RPC methods by dot-delimited namespaces. This helps prevent naming collisions between methods served by different classes. As an example, the XML-RPC server is expected to server several methods in the 'system' namespace:

- system.listMethods

- system.methodHelp

- system.methodSignature

Wewnątrz odpowiada to metodom o tych samych w obiekcie Zend_XmlRpc_Server.

Jeśli chcesz dodać przestrzenie nazw do metod, które oferujesz, po prostu podaj przestrzeń nazw do odpowiedniej metody wtedy, gdy dołączasz funkcję lub klasę:

    <?php
    // Wszystkie publiczne metody klasy My_Service_Class będą dostępne jako
    // myservice.METHODNAME
    $server->setClass('My_Service_Class', 'myservice');

    // Funkcja 'somefunc' będzie dostępna jako funcs.somefunc
    $server->addFunction('somefunc', 'funcs');

### 29.3.6. Własny obiekt żądania

Most of the time, you'll simply use the default request type included with Zend_XmlRpc_Server, Zend_XmlRpc_Request_Http. However, there may be times when you need XML-RPC to be available via the CLI, a GUI, or other environment, or want to log incoming requests. To do so, you may create a custom request object that extends Zend_XmlRpc_Request. The most important thing to remember is to ensure that the getMethod() and getParams() methods are implemented so that the XML-RPC server can retrieve that information in order to dispatch the request.

### 29.3.7. Własne odpowiedzi

Podobnie jak obiekty żądania, Zend_XmlRpc_Server może zwracać własne obiekty odpowiedzi; domyślnie zwracany jest obiekt Zend_XmlRpc_Response_Http, który wysyła odpowiedni nagłówek HTPP Content-Type do użycia z XML-RPC. Możliwym powodem użycia własnego obiektu może być potrzeba logowania odpowiedzi, lub wysyłanie odpowiedzi spowrotem do STDOUT.

Aby użyć własnej klasy odpowiedzi, użyj metody Zend_XmlRpc_Server::setResponseClass() przed wywołaniem handle().

### 29.3.8. Handling Exceptions via Faults

Zend_XmlRpc_Server catches Exceptions generated by a dispatched method, and generates an XML-RPC fault response when such an exception is caught. By default, however, the exception messages and codes are not used in a fault response. This is an intentional decision to protect your code; many exceptions expose more information about the code or environment than a developer would necessarily intend (a prime example includes database abstraction or access layer exceptions).

Exception classes can be whitelisted to be used as fault responses, however. To do so, simply utilize Zend_XmlRpc_Server_Fault::attachFaultException() to pass an exception class to whitelist:

    <?php
    Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');

If you utilize an exception class that your other project exceptions inherit, you can then whitelist a whole family of exceptions at a time. Zend_XmlRpc_Server_Exceptions are always whitelisted, to allow reporting specific internal errors (undefined methods, etc.).

Any exception not specifically whitelisted will generate a fault response with a code of '404' and a message of 'Unknown error'.

### 29.3.9. Buforowanie definicji serwera pomiędzy żądaniami

Dołączanie wielu klas do instancji serwera XML-RPC może zajmować wiele zasobów; za pomocą Reflection API (przez Zend_Server_Reflection) musi być dokonana introspekcja każdej klasy co w rezultacie wygeneruje listę wszystkich możliwych sygnatur metod w celu przekazania jej do klasy serwera.

Aby zredukować straty wydajności, możemy użyć obiektu Zend_XmlRpc_Server_Cache do buforowania definicji serwera pomiędzy żądaniami. Gdy połączymy to z funkcją __autoload(), może to mocno zwiększyć wydajność.

Przykładowe użycie:

    <?php
    require_once 'Zend.php';
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Zend/XmlRpc/Server/Cache.php';

    function __autoload($class)
    {
        Zend::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');   // przestrzeń nazwa glue
        $server->setClass('My_Services_Paste', 'paste'); // przestrzeń nazwa paste
        $server->setClass('My_Services_Tape', 'tape');   // przestrzeń nazwa tape

        Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
    }

    echo $server->handle();

Powyższy przykład próbuje pobrać definicję serwera z pliku bufora xmlrpc.cache znajdującego się w tym samym katalogu co skrypt. Jeśli się to nie uda, załaduje on potrzebne klasy serwisu, dołączy do instancji serwera i spróbuje utworzyć nowy plik bufora z definicją sderwera.

### 29.3.10. Przykład użycia

Poniżej znajduje się kilka przykładów użycia, pokazując pełne spektrum opcji dostępnych dla programistów. Każdy z przykładów użycia jest oparty na poprzednich przykładach.

#### 29.3.10.1. Podstawowe użycie

Poniższy przykład dołącza funkcję jaką uruchamialną przez XML-RPC metodę i obsługuje przychodzące wywołania.

    <?php
    require_once 'Zend/XmlRpc/Server.php';

    /**
     * Zwraca sumę MD5 zadanej wartości
     *
     * @param string $value wartość do obliczenia sumy md5
     * @return string MD5 suma wartości
     */
    function md5Value($value)
    {
        return md5($value);
    }

    $server = new Zend_XmlRpc_Server();
    $server->addFunction('md5Value');
    echo $server->handle();

#### 29.3.10.2. Dołączanie klasy

Poniższy przykład pokazuje dołączanie publicznych metod klasy jako uruchamialnych metod XML-RPC.

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Services/Comb.php';

    $server = new Zend_XmlRpc_Server();
    $server->setClass('Services_Comb');
    echo $server->handle();

#### 29.3.10.3. Dołączanie wielu klas używając przestrzeni nazw

Poniższy przykład pokazuje dołączanie kilku klas, każdej z własną przestrzenią nazw.

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Services/Comb.php';
    require_once 'Services/Brush.php';
    require_once 'Services/Pick.php';

    $server = new Zend_XmlRpc_Server();
    $server->setClass('Services_Comb', 'comb');   // metody wywoływane jako comb.*
    $server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
    $server->setClass('Services_Pick', 'pick');   // metody wywoływane jako pick.*
    echo $server->handle();

#### 29.3.10.4. Określenie wyjątków dla odpowiedzi błędów

Poniższy przykład pozwala dowolnej klasie pochodzącej od Services_Exception na przekazywanie informacji o wyjątkach w postaci kodu i wiadomości w odpowiedzi błędu.

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Zend/XmlRpc/Server/Fault.php';
    require_once 'Services/Exception.php';
    require_once 'Services/Comb.php';
    require_once 'Services/Brush.php';
    require_once 'Services/Pick.php';

    // Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
    Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

    $server = new Zend_XmlRpc_Server();
    $server->setClass('Services_Comb', 'comb');   // metody wywoływane jako comb.*
    $server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
    $server->setClass('Services_Pick', 'pick');   // metody wywoływane jako pick.*
    echo $server->handle();

#### 29.3.10.5. Użycie własnego obiektu żądania

Poniższy przykład tworzy instancję własnego obiektu żądania i przekazuje go do obiektu serwera.

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Zend/XmlRpc/Server/Fault.php';
    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';

    // Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
    Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

    $server = new Zend_XmlRpc_Server();
    $server->setClass('Services_Comb', 'comb');   // metody wywoływane jako comb.*
    $server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
    $server->setClass('Services_Pick', 'pick');   // metody wywoływane jako pick.*

    // Tworzenie obiektu żądania
    $request = new Services_Request();

    echo $server->handle($request);

#### 29.3.10.6. Użycie własnego obiektu odpowiedzi

Poniższy przykład pokazuje określanie własnej klasy odpowiedzi dla zwracanej odpowiedzi.

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Zend/XmlRpc/Server/Fault.php';
    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';

    // Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
    Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

    $server = new Zend_XmlRpc_Server();
    $server->setClass('Services_Comb', 'comb');   // metody wywoływane jako comb.*
    $server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
    $server->setClass('Services_Pick', 'pick');   // metody wywoływane jako pick.*

    // Utwórz obiekt żądania
    $request = new Services_Request();

    // Użyj własnego obiektu żądania
    $server->setResponseClass('Services_Response');

    echo $server->handle($request);

#### 29.3.10.7. Buforowanie definicji serwera pomiędzy żądaniami

Poniższy przykład pokazuje buforowanie definicji serwera pomiędzy żądaniami.

    <?php
    require_once 'Zend/XmlRpc/Server.php';
    require_once 'Zend/XmlRpc/Server/Fault.php';
    require_once 'Zend/XmlRpc/Server/Cache.php';
    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';

    // Określ plik cache
    $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';

    // Pozwala na wyrzucanie wyjątku Services_Exceptions dla odpowiedzi błędu
    Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

    $server = new Zend_XmlRpc_Server();

    // Spróbuj pobrać definicje serwera z bufora
    if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
        $server->setClass('Services_Comb', 'comb');   // metody wywoływane jako comb.*
        $server->setClass('Services_Brush', 'brush'); // metody wywoływane jako brush.*
        $server->setClass('Services_Pick', 'pick');   // metody wywoływane jako pick.*

        // Zapisz cache
        Zend_XmlRpc_Server_Cache::save($cacheFile, $server));
    }

    // Utwórz obiekt żądania
    $request = new Services_Request();

    // Użyj własnej klasy odpowiedzi
    $server->setResponseClass('Services_Response');

    echo $server->handle($request);

Poprzedni | Początek rozdziału | Następny
29.2. Zend_XmlRpc_Client | Spis treści | Dodatek A. Zend Framework PHP Coding Standard