24.2. Zend_XmlRpc_Client

24.2.1. Wprowadzenie

The Zend Framework zapewnia obsługę wywoływania zdalnych serwisów XML-RPC jako klient w pakiecie Zend_XmlRpc_Client. Do głównych funkcjonalności należą: automatyczna konwersja typów pomiędzy PHP a XML-RPC, obiekt serwera proxy oraz dostęp do możliwości introspekcji serwerów.

24.2.2. Wywołania metod

Konstruktor klasy Zend_XmlRpc_Client odbiera w pierwszym parametrze adres URL zdalnego serwera XML-RPC. Nowa zwrócona instancja może być użyta do wywołania dowolnej ilości zdalnych metod tego serwera.

To call a remote method with the XML-RPC client, instantiate it and use the call() instance method. The code sample below uses a demonstration XML-RPC server on the Zend Framework website. You can use it for testing or exploring the Zend_XmlRpc components.

Przykład 24.1. Wywołanie metody XML-RPC

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

echo $client->call('test.sayHello'); 

// hello

?>

The XML-RPC value returned from the remote method call will be automatically unmarshaled and cast to the equivalent PHP native type. In the example above, a PHP string is returned and is immediately ready to be used.

The first parameter of the call() method receives the name of the remote method to call. If the remote method requires any parameters, these can be sent by supplying a second, optional parameter to call() with an array of values to pass to the remote method:

Przykład 24.2. Wywołanie metody XML-RPC z parametrem

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$arg1 = 1.1;
$arg2 = 'foo';

$result = $client->call('test.sayHello', array($arg1, $arg2)); 

// zmienna $result jest natywnego typu PHP

?>

If the remote method doesn't require parameters, this optional parameter may either be left out or an empty array() passed to it. The array of parameters for the remote method can contain native PHP types, Zend_XmlRpc_Value objects, or a mix of each.

The call() method will automatically convert the XML-RPC response and return its equivalent PHP native type. A Zend_XmlRpc_Response object for the return value will also be available by calling the getLastResponse() method after the call.

24.2.3. Typy i konwersje

Some remote method calls require parameters. These are given to the call() method of Zend_XmlRpc_Client as an array in the second parameter. Each parameter may be given as either a native PHP type which will be automatically converted, or as an object representing a specific XML-RPC type (one of the Zend_XmlRpc_Value objects).

24.2.3.1. Natywne typy PHP jako parametry

Parameters may be passed to call() as native PHP variables, meaning as a string, integer, float, boolean, array, or an object. In this case, each PHP native type will be auto-detected and converted into one of the XML-RPC types according to this table:

Tabela 24.1. Konwersje między typami PHP oraz XML-RPC

Natywny typ PHP Typ XML-RPC
integer int
double double
boolean boolean
string string
array array
associative array struct
object array

24.2.3.2. Obiekty Zend_XmlRpc_Value jako parametry

Parameters may also be created as Zend_XmlRpc_Value instances to specify an exact XML-RPC type. The primary reasons for doing this are:

  • When you want to make sure the correct parameter type is passed to the procedure (i.e. the procedure requires an integer and you may get it from a database as a string)

  • When the procedure requires base64 or dateTime.iso8601 type (which doesn't exists as a PHP native type)

  • When auto-conversion may fail (i.e. you want to pass an empty XML-RPC struct as a parameter. Empty structs are represented as empty arrays in PHP but, if you give an empty array as a parameter it will be auto-converted to an XML-RPC array since it's not an associative array)

There are two ways to create a Zend_XmlRpc_Value object: instantiate one of the Zend_XmlRpc_Value subclasses directly, or use the static factory method Zend_XmlRpc_Value::getXmlRpcValue().

Tabela 24.2. Obiekty Zend_XmlRpc_Value dla typów XML-RPC

Typ XML-RPC Stała Zend_XmlRpc_Value Obiekt Zend_XmlRpc_Value Object
int Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER Zend_XmlRpc_Value_Integer
double Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE Zend_XmlRpc_Value_Double
boolean Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN Zend_XmlRpc_Value_Boolean
string Zend_XmlRpc_Value::XMLRPC_TYPE_STRING Zend_XmlRpc_Value_String
base64 Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64 Zend_XmlRpc_Value_Base64
dateTime.iso8601 Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME Zend_XmlRpc_Value_DateTime
array Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY Zend_XmlRpc_Value_Array
struct Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT Zend_XmlRpc_Value_Struct

[Notatka] Automatyczna konwersja

When building a new Zend_XmlRpc_Value object, its value is set by a PHP type. The PHP type will be will be converted to the specified type using PHP casting. For example, if a string is given as a value to the Zend_XmlRpc_Value_Integer object, it will be converted using (int)$value.

24.2.4. Server Proxy Object

Another way to call remote methods with the XML-RPC client is to use the server proxy. This is a PHP object that proxies a remote XML-RPC namespace, making it work as close to a native PHP object as possible.

To instantiate a server proxy, call the getProxy() instance method of Zend_XmlRpc_Client. This will return an instance of Zend_XmlRpc_Client_ServerProxy. Any method call on the server proxy object will be forwarded to the remote, and parameters may be passed like any other PHP method.

Przykład 24.3. Proxy the Default Namespace

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$server = $client->getProxy();           // Proxy the default namespace

$hello = $server->test->sayHello(1, 2);  // test.Hello(1, 2) zwraca "hello"

?>
            

The getProxy() method receives an optional argument specifying which namespace of the remote server to proxy. If it does not receive a namespace, the default namespace will be proxied. In the next example, the test namespace will be proxied:

Przykład 24.4. Proxy Any Namespace

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$test  = $client->getProxy('test');     // Proxy the "test" namespace

$hello = $test->sayHello(1, 2);         // test.Hello(1,2) zwraca "hello"

?>

If the remote server supports nested namespaces of any depth, these can also be used through the server proxy. For example, if the server in the example above had a method test.foo.bar(), it could be called as $test->foo->bar().

24.2.5. Obsługa błędów

Two kinds of errors can occur during an XML-RPC method call: HTTP errors and XML-RPC faults. The Zend_XmlRpc_Client recognizes each and provides the ability to detect and trap them independently.

24.2.5.1. Błędy HTTP

Jeśli wystąpi jakiś błąd HTTP, na przykład gdy zdalny serwer HTTP zwróci błąd 404 Not Found, wyrzucony zostanie wyjątek Zend_XmlRpc_Client_HttpException.

Przykład 24.5. Obsługa błędów HTTP

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://foo/404');

try {

    $client->call('bar', array($arg1, $arg2));

} catch (Zend_XmlRpc_HttpException $e) {
    
    // $e->getCode() zwraca 404
    // $e->getMessage() zwraca "Not found"
    
}

?>

Regardless of how the XML-RPC client is used, the Zend_XmlRpc_Client_HttpException will be thrown whenever an HTTP error occurs.

24.2.5.2. XML-RPC Faults

An XML-RPC fault is analogous to a PHP exception. It is a special type returned from an XML-RPC method call that has both an error code and an error message. XML-RPC faults are handled differently depending on the context of how the Zend_XmlRpc_Client is used.

When the call() method or the server proxy object is used, an XML-RPC fault will result in a Zend_XmlRpc_Client_FaultException being thrown. The code and message of the exception will map directly to their respective values in the original XML-RPC fault response.

Przykład 24.6. Handling XML-RPC Faults

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

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

try {

    $client->call('badMethod');

} catch (Zend_XmlRpc_FaultException $e) {
    
    // $e->getCode() zwraca 1
    // $e->getMessage() zwraca "Unknown method"
    
}

?>

When the call() method is used to make the request, the Zend_XmlRpc_FaultException will be thrown on fault. A Zend_XmlRpc_Response object containing the fault will also be available by calling getLastResponse().

When the doRequest() method is used to make the request, it will not throw the exception. Instead, it will return a Zend_XmlRpc_Response object returned will containing the fault. This can be checked with isFault() instance method of Zend_XmlRpc_Response.

24.2.6. Introspekcja serwerów

Some XML-RPC servers support the de facto introspection methods under the XML-RPC system. namespace. Zend_XmlRpc_Client provides special support for servers with these capabilities.

A Zend_XmlRpc_Client_ServerIntrospection instance may be retrieved by calling the getIntrospector() method of Zend_XmlRpcClient. It can then be used to perform introspection operations on the server.

24.2.7. Od żądania do odpowiedzi

Under the hood, the call() instance method of Zend_XmlRpc_Client builds a request object (Zend_XmlRpc_Request) and sends it to another method, doRequest(), that returns a response object (Zend_XmlRpc_Response).

Metoda doRequest() jest także dostępna dla bezpośredniego użycia:

Przykład 24.7. Przetwarzanie żądania do odpowiedzi

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

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$request = new Zend_XmlRpc_Request();
$request->setMethod('test.sayHello');
$request->setParams(array('foo', 'bar'));

$client->doRequest($request);

// $server->getLastRequest() zwraca instancję Zend_XmlRpc_Request
// $server->getLastResponse() zwraca instancję Zend_XmlRpc_Response

?>

Whenever an XML-RPC method call is made by the client through any means, either the call() method, doRequest() method, or server proxy, the last request object and its resultant response object will always be available through the methods getLastRequest() and getLastResponse() respectively.

24.2.8. Klient HTTP i testowanie

In all of the prior examples, an HTTP client was never specified. When this is the case, a new instance of Zend_Http_Client will be created with its default options and used by Zend_XmlRpc_Client automatically.

The HTTP client can be retrieved at any time with the getHttpClient() method. For most cases, the default HTTP client will be sufficient. However, the setHttpClient() method allows for a different HTTP client instance to be injected.

The setHttpClient() is particularly useful for unit testing. When combined with the Zend_Http_Client_Adapter_Test, remote services can be mocked out for testing. See the unit tests for Zend_XmlRpc_Client for examples of how to do this.