TigerZF
🌐Español

80.2. Zend_XmlRpc_Client

80.2.1. Introducción

Zend Framework proporciona soporte para consumir servicios remotos XML-RPC como cliente en el paquete Zend_XmlRpc_Client. Sus características principales incluyen la conversión automática de tipos entre PHP y XML-RPC, un objeto proxy de servidor, y acceso a las capacidades de introspección del servidor.

80.2.2. Llamadas a métodos

El constructor de Zend_XmlRpc_Client recibe la URL del endpoint del servidor XML-RPC remoto como su primer parámetro. La nueva instancia devuelta puede usarse para llamar a cualquier cantidad de métodos remotos en ese endpoint.

Para llamar a un método remoto con el cliente XML-RPC, instáncielo y use el método de instancia call(). El ejemplo de código que sigue utiliza un servidor XML-RPC de demostración en el sitio web de Zend Framework. Puede usarlo para pruebas o para explorar los componentes de Zend_XmlRpc.

Ejemplo 80.1. Llamada a un método XML-RPC

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

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

// hello

El valor XML-RPC devuelto por la llamada al método remoto será automáticamente desmarshalado y convertido al tipo nativo equivalente de PHP. En el ejemplo anterior, se devuelve un String de PHP y está listo para usarse de inmediato.

El primer parámetro del método call() recibe el nombre del método remoto a llamar. Si el método remoto requiere algún parámetro, este puede enviarse proporcionando un segundo parámetro opcional a call() con un Array de valores a pasar al método remoto:

Ejemplo 80.2. Llamada a un método XML-RPC con parámetros

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

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

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

// $result is a native PHP type

Si el método remoto no requiere parámetros, este parámetro opcional puede omitirse o puede pasarse un array() vacío. El array de parámetros para el método remoto puede contener tipos nativos de PHP, objetos Zend_XmlRpc_Value, o una mezcla de ambos.

El método call() convertirá automáticamente la respuesta XML-RPC y devolverá su tipo nativo equivalente de PHP. Un objeto Zend_XmlRpc_Response para el valor de retorno también estará disponible llamando al método getLastResponse() después de la llamada.

80.2.3. Tipos y conversiones

Algunas llamadas a métodos remotos requieren parámetros. Estos se pasan al método call() de Zend_XmlRpc_Client como un array en el segundo parámetro. Cada parámetro puede darse como un tipo nativo de PHP que se convertirá automáticamente, o como un objeto que representa un tipo XML-RPC específico (uno de los objetos Zend_XmlRpc_Value).

80.2.3.1. Tipos nativos de PHP como parámetros

Los parámetros pueden pasarse a call() como variables nativas de PHP, es decir, como String, Integer, Float, Boolean, Array, u Object. En este caso, cada tipo nativo de PHP será detectado automáticamente y convertido a uno de los tipos XML-RPC según esta tabla:

Tabla 80.1. Conversiones de tipos PHP y XML-RPC

Tipo nativo de PHP Tipo XML-RPC
integer int
Zend_Crypt_Math_BigInteger i8
double double
boolean boolean
string string
null nil
array array
associative array struct
object array
Zend_Date dateTime.iso8601
DateTime dateTime.iso8601

[Note] ¿A qué tipo se convierten los arrays vacíos?

Pasar un array vacío a un método XML-RPC es problemático, ya que podría representar tanto un array como un struct. Zend_XmlRpc_Client detecta estas condiciones y realiza una petición al método system.methodSignature del servidor para determinar el tipo XML-RPC apropiado al que convertir.

Sin embargo, esto puede llevar a problemas en sí mismo. En primer lugar, los servidores que no admiten system.methodSignature registrarán peticiones fallidas en el log, y Zend_XmlRpc_Client recurrirá a convertir el valor a un tipo array de XML-RPC. Además, esto significa que cualquier llamada con argumentos de tipo array resultará en una llamada adicional al servidor remoto.

Para deshabilitar la búsqueda por completo, puede llamar al método setSkipSystemLookup() antes de realizar su llamada XML-RPC:

$client->setSkipSystemLookup(true);
$result = $client->call('foo.bar', array(array()));

80.2.3.2. Objetos Zend_XmlRpc_Value como parámetros

Los parámetros también pueden crearse como instancias de Zend_XmlRpc_Value para especificar un tipo XML-RPC exacto. Las razones principales para hacer esto son:

  • Cuando desea asegurarse de que se pasa el tipo de parámetro correcto al procedimiento (por ejemplo, el procedimiento requiere un entero y usted podría obtenerlo de una base de datos como cadena de texto)

  • Cuando el procedimiento requiere el tipo base64 o dateTime.iso8601 (que no existe como tipo nativo de PHP)

  • Cuando la conversión automática puede fallar (por ejemplo, si desea pasar un struct XML-RPC vacío como parámetro. Los structs vacíos se representan como arrays vacíos en PHP pero, si proporciona un array vacío como parámetro, se convertirá automáticamente a un array XML-RPC ya que no es un array asociativo)

Hay dos formas de crear un objeto Zend_XmlRpc_Value: instanciar directamente una de las subclases de Zend_XmlRpc_Value, o usar el método de fábrica estático Zend_XmlRpc_Value::getXmlRpcValue().

Tabla 80.2. Objetos Zend_XmlRpc_Value para tipos XML-RPC

Tipo XML-RPC Constante de Zend_XmlRpc_Value Objeto Zend_XmlRpc_Value
int Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER Zend_XmlRpc_Value_Integer
i8 Zend_XmlRpc_Value::XMLRPC_TYPE_I8 Zend_XmlRpc_Value_BigInteger
ex:i8 Zend_XmlRpc_Value::XMLRPC_TYPE_APACHEI8 Zend_XmlRpc_Value_BigInteger
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
nil Zend_XmlRpc_Value::XMLRPC_TYPE_NIL Zend_XmlRpc_Value_Nil
ex:nil Zend_XmlRpc_Value::XMLRPC_TYPE_APACHENIL Zend_XmlRpc_Value_Nil
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

[Note] Conversión automática

Al construir un nuevo objeto Zend_XmlRpc_Value, su valor se establece mediante un tipo de PHP. El tipo de PHP se convertirá al tipo especificado usando el casting de PHP. Por ejemplo, si se proporciona una cadena como valor al objeto Zend_XmlRpc_Value_Integer, se convertirá usando (int)$value.

80.2.4. Objeto proxy de servidor

Otra forma de llamar a métodos remotos con el cliente XML-RPC es usar el proxy de servidor. Este es un objeto PHP que actúa como proxy de un namespace XML-RPC remoto, haciendo que funcione lo más parecido posible a un objeto nativo de PHP.

Para instanciar un proxy de servidor, llame al método de instancia getProxy() de Zend_XmlRpc_Client. Esto devolverá una instancia de Zend_XmlRpc_Client_ServerProxy. Cualquier llamada a método en el objeto proxy de servidor se reenviará al remoto, y los parámetros pueden pasarse como en cualquier otro método de PHP.

Ejemplo 80.3. Proxy del namespace por defecto

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

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

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

El método getProxy() recibe un argumento opcional que especifica qué namespace del servidor remoto se debe usar como proxy. Si no recibe un namespace, se usará como proxy el namespace por defecto. En el siguiente ejemplo, se usará como proxy el namespace 'test':

Ejemplo 80.4. Proxy de cualquier namespace

$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) returns "hello"

Si el servidor remoto admite namespaces anidados de cualquier profundidad, estos también pueden usarse a través del proxy de servidor. Por ejemplo, si el servidor del ejemplo anterior tuviera un método test.foo.bar(), podría llamarse como $test->foo->bar().

80.2.5. Manejo de errores

Pueden producirse dos tipos de errores durante una llamada a un método XML-RPC: errores de HTTP y fallos de XML-RPC. El Zend_XmlRpc_Client reconoce cada uno y proporciona la capacidad de detectarlos y capturarlos de forma independiente.

80.2.5.1. Errores HTTP

Si se produce algún error HTTP, como que el servidor HTTP remoto devuelva un 404 Not Found, se lanzará una Zend_XmlRpc_Client_HttpException.

Ejemplo 80.5. Manejo de errores HTTP

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

try {

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

} catch (Zend_XmlRpc_Client_HttpException $e) {

    // $e->getCode() returns 404
    // $e->getMessage() returns "Not Found"

}

Independientemente de cómo se use el cliente XML-RPC, la Zend_XmlRpc_Client_HttpException se lanzará siempre que ocurra un error HTTP.

80.2.5.2. Fallos de XML-RPC

Un fallo XML-RPC es análogo a una excepción de PHP. Es un tipo especial devuelto por una llamada a un método XML-RPC que tiene tanto un código de error como un mensaje de error. Los fallos XML-RPC se manejan de forma diferente según el contexto en que se use el Zend_XmlRpc_Client.

Cuando se usa el método call() o el objeto proxy de servidor, un fallo XML-RPC resultará en el lanzamiento de una Zend_XmlRpc_Client_FaultException. El código y el mensaje de la excepción se corresponderán directamente con sus respectivos valores en la respuesta de fallo XML-RPC original.

Ejemplo 80.6. Manejo de fallos XML-RPC

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

try {

    $client->call('badMethod');

} catch (Zend_XmlRpc_Client_FaultException $e) {

    // $e->getCode() returns 1
    // $e->getMessage() returns "Unknown method"

}

Cuando se usa el método call() para realizar la petición, la Zend_XmlRpc_Client_FaultException se lanzará en caso de fallo. Un objeto Zend_XmlRpc_Response que contiene el fallo también estará disponible llamando a getLastResponse().

Cuando se usa el método doRequest() para realizar la petición, no se lanzará la excepción. En su lugar, se devolverá un objeto Zend_XmlRpc_Response que contendrá el fallo. Esto puede comprobarse con el método de instancia isFault() de Zend_XmlRpc_Response.

80.2.6. Introspección del servidor

Algunos servidores XML-RPC admiten los métodos de introspección de facto bajo el namespace XML-RPC system.. Zend_XmlRpc_Client proporciona soporte especial para servidores con estas capacidades.

Se puede obtener una instancia de Zend_XmlRpc_Client_ServerIntrospection llamando al método getIntrospector() de Zend_XmlRpcClient. Luego puede usarse para realizar operaciones de introspección en el servidor.

80.2.7. De la petición a la respuesta

Internamente, el método de instancia call() de Zend_XmlRpc_Client construye un objeto de petición (Zend_XmlRpc_Request) y lo envía a otro método, doRequest(), que devuelve un objeto de respuesta (Zend_XmlRpc_Response).

El método doRequest() también está disponible para su uso directo:

Ejemplo 80.7. Procesamiento de la petición a la respuesta

$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);

// $client->getLastRequest() returns instanceof Zend_XmlRpc_Request
// $client->getLastResponse() returns instanceof Zend_XmlRpc_Response

Siempre que el cliente realiza una llamada a un método XML-RPC, ya sea por medio del método call(), el método doRequest(), o el proxy de servidor, el último objeto de petición y su objeto de respuesta resultante siempre estarán disponibles a través de los métodos getLastRequest() y getLastResponse() respectivamente.

80.2.8. Cliente HTTP y pruebas

En todos los ejemplos anteriores, nunca se especificó un cliente HTTP. Cuando este es el caso, se creará una nueva instancia de Zend_Http_Client con sus opciones por defecto y será utilizada automáticamente por Zend_XmlRpc_Client.

El cliente HTTP puede obtenerse en cualquier momento con el método getHttpClient(). Para la mayoría de los casos, el cliente HTTP por defecto será suficiente. Sin embargo, el método setHttpClient() permite inyectar una instancia de cliente HTTP diferente.

El método setHttpClient() es particularmente útil para pruebas unitarias. Combinado con Zend_Http_Client_Adapter_Test, los servicios remotos pueden simularse para las pruebas. Consulte las pruebas unitarias de Zend_XmlRpc_Client para ver ejemplos de cómo hacerlo.