lunes, 14 de junio de 2010

Como devolver arreglos y estructuras de datos en SOAP transparentemente, utilizando PHP y NuSOAP


¡Saludos nuevamente blogueros!

En este artículo veremos como resolver una duda que apareció hace un tiempo, acerca del envío de datos por servicios web utilizando la biblioteca NuSOAP de PHP. En un artículo pasado, hablamos de como implementar un servicio web desde PHP utilizando esta biblioteca; este servicio contaba con dos métodos, uno de ellos devolvía una cadena y el otro un arreglo asociativo de PHP, se pudo consumir el servicio desde un cliente AJAX sin problema procesando el código XML directamente, sin embargo, al trabajar de esta manera se pierde uno de los puntos importantes para utilizar protocolos de comunicación entre aplicaciones: la transparencia. Es decir, al consumir el servicio el cliente no pudo extraer la estructura de datos recibida, sin necesidad de darle un tratamiento al XML de la respuesta y teniendo que saber de antemano cuál era la estructura XML que recibiría.

Ahora, la idea es corregir este problema de transparencia, al mismo tiempo que mostramos como mandar diferentes tipos de datos complejos, como son: estructuras, arreglos y arreglos de estructuras.

Manos a la obra

Para poder llegar a este nivel de transparencia entre aplicaciones es que el protocolo SOAP utiliza el WSDL, el cual además de contener la definición de cada uno de los métodos que posee un servicio web, puede tener también la definición de tipos de datos complejos. Un tipo de dato complejo consiste una colección de valores agrupados dentro de una estructura, y dentro de este tipo de datos es que encontramos los objetos y arreglos.

Podemos definir estos datos complejos utilizando la clase soap_server de la biblioteca NuSOAP. Como recordarán -y si no es así lo menciono- esta clase nos permite crear servicios web en nuestro servidor para que lo consuman los clientes. Dentro de esta clase se encuentra un objeto llamado wsdl, definido como una propiedad de la misma clase, el cual posee una serie de métodos para definir las características del WSDL del servicio web. El método que emplearemos concretamente para definir los nuevos tipos de datos será el addComplexType. El primer paso consistirá en instanciar la clase soap_server de la siguiente forma:

require_once('nusoap.php');
$servidor = new soap_server;


Una vez hecho esto contamos con un objeto de esta clase, para el cual podemos definir sus características:

$ns = "http://nuestroespaciodenombres";
$servidor->configureWSDL('NombreDelServicio',$ns);
$servidor->wsdl->schematargetnamespace = $ns;


Ahora viene lo bueno, definir tipos de datos complejos para que sean devueltos por los métodos de nuestro servicio. Para este ejemplo definiremos 3 estructuras diferentes para probar las posibilidades que nos ofrece esta clase:

  • Primero un arreglo de cadenas sencillo:

$servidor->wsdl->addComplexType(
        'ArregloDeCadenas',
        'complexType',
        'array',
        'sequence',
        'http://schemas.xmlsoap.org/soap/encoding/:Array',
        array(),
        array(array('ref' => 'http://schemas.xmlsoap.org/soap/encoding/:arrayType',
         'wsdl:arrayType' => 'xsd:string[]')
        ),
        'xsd:string'  
);


Como vemos, se incluye una referencia(http://schemas.xmlsoap.org/soap/encoding/:Array) a la definición del formato que debe tener un dato de tipo complejo Array.

  • Después una estructura de datos, similar a los arreglos asociativos, que contendrá una serie de valores distinguidos por un nombre:


  • $servidor->wsdl->addComplexType(
            'Estructura',
            'complexType',
            'struct',
            'all',
            '',
            array(
            'Nombre' => array('name' => 'Nombre', 'type' => 'xsd:string'),
            'Apellidos'=>array('name' => 'Apellidos', 'type' => 'xsd:string'),
            'Edad'=>array('name' => 'Edad', 'type' => 'xsd:integer')
            )
    );


  • Finalmente -y lo más interesante-, un arreglo de estructuras de datos:

$servidor->wsdl->addComplexType(
        'ArregloDeEstructuras',
        'complexType',
        'array',
        'sequence',
        'http://schemas.xmlsoap.org/soap/encoding/:Array',
        array(),
        array(array('ref' => 'http://schemas.xmlsoap.org/soap/encoding/:arrayType',
         'wsdl:arrayType' => 'tns:Estructura[]')
        ),
        'tns:Estructura'  
);


Digo que el último ejemplo me parece el más interesante porque con este podemos definir datos de entrada y de salida para los métodos que consistirán en listas de estructuras de datos, similares a las que encontramos en muchos lenguajes de programación de alto nivel y sobre todo muy útiles para representar registros de bases de datos y archivos estructurados.

Para incluir estos datos de entrada y de salida de los métodos, basta con declararlo en el método registrer donde se declaran los métodos, y asegurarnos por supuesto de que la estructura de los parámetros de estos métodos que hagan referencia los tipos de datos complejos, corresponda con la estructura declarada, es decir:

function consultaPersonas($param) {
    $arreglo = array();
    $arreglo[] = array('Nombre'=>"Juan", 'Apellidos'=>"Torres", 'Edad'=>18);
    $arreglo[] = array('Nombre'=>"Teresa", 'Apellidos'=>"Jiménez Sánchez", 'Edad'=>19);
    $arreglo[] = array('Nombre'=>"Efraín", 'Apellidos'=>"Ovalles López", 'Edad'=>22);
    return $arreglo;
}

$servidor->register('consultaPersonas',
    array('param'=>'xsd:string'),
    array('return'=>'tns:ArregloDeEstructuras'),
    $ns
);



Si por ejemplo creamos un método que devuelva el tipo de dato complejo ArregloDeEstructuras, en el código de nuestro método deberemos incluir una estructura de datos equivalente, en este caso un arreglo asociativo, donde cada llave del arreglo corresponde al identificador de los datos de nuestra estructura previamente definida -llamada Estructura en este ejemplo-; así en el método, cada entrada del arreglo contendrá a la vez un arreglo asociativo, que corresponderá a esta estructura de datos.

De esta forma es posible crear servicios web que devuelvan a nuestras aplicaciones arreglos de estructuras de datos, e incluso arreglos de arreglos, lo cual ayudará a que nuestros servicios puedan generar mayor variedad de datos de salida, y de esta forma aumentaremos el poder las capacidades nuestras aplicaciones. Además de esto, se logra mucha mayor transparencia, ya que cualquier aplicación de terceros o que nosotros mismos desarrollemos, solo tendrá que seguir el formato definido en el WSDL de nuestros servicios web, para poder desentrañar estos tipos de datos complejos. Algunos entornos de desarrollo -como el de .Net- incluso permiten implementar el consumo de estos servicios web interpretando los tipos de datos complejos como objetos nativos del lenguaje, lo que nos permite manipularlos con mucha mayor facilidad, así que las posibilidades son muchas.

Hasta la próxima.

3 comentarios:

Wilfo dijo...

Me dejaste con la duda amigo justo al final.Tengo un problema que deseo resolver.Deseo sacar de mi base de datos 3 datos y mediante el servicio devolver esos 3 registros.
Pero en tu ejemplo solo realizas para uno pero podrias ser mas claro aqui:
$servidor->wsdl->addComplexType(
'ArregloDeEstructuras',
'complexType',
'array',
'sequence',
'http://schemas.xmlsoap.org/soap/encoding/:Array',
array(),
array(array('ref' => 'http://schemas.xmlsoap.org/soap/encoding/:arrayType',
'wsdl:arrayType' => 'tns:Estructura[]')
),
'tns:Estructura'
);

Beto dijo...

Hola, es en esa parte donde se define el tipo de dato "ArregloDeEstructuras", con ese tipo podrás mandar arreglos de arreglos, es decir, esos 3 registros que deseas mandar los puedes guardar en un arreglo y devolverlo por medio del servicio, por ejemplo, digamos que tienes tus tres registros en tres arreglos asociativos diferentes (llamados $registro1, $registro2 y $registro3), tendrías que declarar una función en la cual se regresen así:

Para luego hacer referencia a esa función en el método $servidor->register()
$arreglo = array($registro1, $registro2, $registro3);
return $arreglo;
}

Para esa función declararla

Administrador dijo...

Hola buenas noches.. he probado el ejemplo en la web.. y funciona de maravillas... pero cuando intento consumirlo desde c# winform y meter ese arreglo de arrays en un DataGridView no logro mostrarlo... cuenta perfectamente cuantos Rows tiene la consulta.. pero las columnas se muestran vacías crees poder ayudarme en esta Trabesia gracias

Publicar un comentario