Este el tercer ejemplo que voy
a publicar de la comunicación
entre el cliente y servidor de WebServices utilizando NuSOAP con un
servidor PHP. Para aquellos que llegarón directamente a esta
página, les recomiendo que primero lean el
primer
ejemplo de NuSOAP con PHP, y
luego el
segundo
ejemplo de NuSOAP con PHP, antes
de continuar con este. En este
ejemplo en particular voy a modificar el
ejemplo
2, para en vez de retornar un
objeto, retornar una lista de
objetos. En el ejemplo anterior, trate un caso muy particular, que es
cuando necesitamos obtener un objeto desde el servidor, en este nuevo
ejemplo, voy a obtener un listado de objetos. Muchas veces necesitamos
un listado de algún tipo de objeto, por ejemplo, un listado
de
clientes, con este nuevo Servicio Web planteo este caso, en el cual el
servidor nos devuelve un listado con todos los clientes que existen en
el sistema.
Como veremos existen algunas
modificaciones extras que debemos
realizar para retornar un listado con los clientes. Primero debemos
definir una estructura que contenga a la definición
planteada en
el ejemplo anterior, y luego realizar una conversión un poco
más compleja (de un vector de objetos, a un vector de
vector).
También voy a incluír una clase de soporte, que
nos
ayudará a realizar las conversiones.
Módulo Servidor
Para simplificar la estructura
del servidor, intente extraer toda la lógica de
conversión en una clase extra (smart_soporte.php),
así la lectura del código del servidor se
mantiene lo suficientemente limpia como para que sea más
fácil su entendimiento. En el
ejemplo
anterior el servicio web
retornaba un cliente al consumidor/cliente de dicho servicio web, en
este caso, retornaremos un listado de clientes. Debemos tener en cuenta
que las respuestas deben ser convertidas a los tipos de datos
básicos, por lo tanto para devolver una lista de clientes,
debemos convertir dicha lista en un lista de listas que contengan como
indices/keys/claves los atributos de la clase Cliente.
A continuación
expongo el código del servidor:
<?php
// Pull in the NuSOAP code
require_once('nusoap/lib/nusoap.php');
require_once('soporte_obrea.php'); // Incluyo este archivo que tiene archivos para soporte de WS
$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;
/*
* Ejemplo 3: listarClientes es la funcion mas compleja que voy realizar, no recibe parametros
* y retorna un listado de clientes. Utiliza varios metodos del ejemplo 2.
*/
class Cliente {
var $id;
var $nombre;
var $apellido;
var $cuit;
}
class ClienteDAO {
/**
* getCliente($id) : Cliente
* Esta funcion deberia implementarse con una conexion a una base de datos
* y obtener la informacion de la base directamente
*/
function getCliente($id) {
$obj = new Cliente();
if ($id==1) {
$obj->id = 1;
$obj->nombre = 'Blas';
$obj->apellido = 'Pascal';
$obj->cuit = '11-11111111-1';
}
if ($id==2) {
$obj->id = 2;
$obj->nombre = 'Isaac';
$obj->apellido = 'Newton';
$obj->cuit = '22-22222222-2';
}
return $obj;
}
/**
* getList : Array
* Esta funcion retorna un listado de todos los clientes que estan en el sistema.
* @return
*/
function getList() {
$rta = array();
$rta[0] = $this->getCliente(1);
$rta[1] = $this->getCliente(2);
return $rta;
}
}
$server->wsdl->addComplexType('Cliente',
'complexType',
'struct',
'all',
'',
array(
'id' => array('name' => 'id', 'type' => 'xsd:int'),
'nombre' => array('name' => 'nombre', 'type' => 'xsd:string'),
'apellido' => array('name' => 'apellido', 'type' => 'xsd:string'),
'cuit' => array('name' => 'CUIT', 'type' => 'xsd:string')
)
);
$server->wsdl->addComplexType('listadoClientes',
'complexType',
'array',
'',
'',
array (array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:Cliente[]'))
);
$server->register('listarClientes', // Nombre de la funcion
array(), // Parametros de entrada
array('return' => 'tns:listadoClientes'), // Parametros de salida
$miURL
);
function listarClientes() {
$dao = new ClienteDAO();
$listado = $dao->getList();
$objSoporte = new SoporteWS();
$respuesta = $objSoporte->convertirAVectorParaWS($listado);
return new soapval('return', 'tns:listadoClientes', $respuesta);
}
$server->service($HTTP_RAW_POST_DATA);
?>
Existen una lista de
modificaciones que voy a ir detallando en los siguientes puntos.
Agregar una función
en el DAO para que retorne una lista
Como mencione anteriormente en esta oportunidad debemos retornar un
listado de clientes, por eso debemos modificar la clase ClienteDAO
agregando un nuevo método getList, el cual retorna una lista
con todos los clientes.
function getList() {
$rta = array();
$rta[0] = $this->getCliente(1);
$rta[1] = $this->getCliente(2);
return $rta;
}
La clase ObjetoDAO agrega un
nuevo método llamado getList(), el cual retorna una lista de
todos los clientes que tenemos en el sistema. Al igual que en el
ejemplo
2, cuando implementemos este
método en un servidor productivo, tendrá una
lógica de acceso a datos para obtener la
información de alguna fuente de datos. Por ejemplo, si la
fuente de datos fuera una base de datos, deberiamos ejecutar una
sentencia SQL similar a "select * from Cliente" y luego convertir los
resultados en un listado de Clientes.
Definimos la estructura
retornada
Debemos definir el nuevo tipo
de datos que vamos a retornar, en este caso debemos retornar una lista
de clientes, la cual esta definida por la siguiente estructura:
$server->wsdl->addComplexType('listadoClientes',
'complexType',
'array',
'',
'',
array (array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:Cliente[]'))
);
Como podemos ver en el
código anterior, definimos un tipo de datos
"listadoClientes" el cual es un array de "Cliente" (el tipo de datos
que habíamos definido en el
ejemplo
2). Con estas simples lineas
estamos indicando que vamos a retornar un listado (vector) y que cada
elemento de dicho vector contendrá un Cliente.
Registramos el servicio web a
publicar
$server->register('listarClientes', // Nombre de la funcion
array(), // Parametros de entrada
array('return' => 'tns:listadoClientes'), // Parametros de salida
$miURL
);
Al igual que en los ejemplos
anteriores debemos registrar/publiar el servicio web, para ello
llamamos a el método register del server. Definimos que el
servicio web expuesto llamará a la función
"listarClientes" y que la misma retornará un tipo de datos
tns:listadoClientes (el tipo de datos definido en el punto anterior).
Implementación de
la función
Debemos implementar la
función que será llamada cuando el cliente del
webservice haga uso del mismo. En este caso será
implementado por la función listarClientes().
function listarClientes() {
$dao = new ClienteDAO();
$listado = $dao->getList();
$objSoporte = new SoporteWS();
$respuesta = $objSoporte->convertirAVectorParaWS($listado);
return new soapval('return', 'tns:listadoClientes', $respuesta);
}
Esta función es muy
similar a la del
ejemplo
2, pero en este caso hacemos uso
de un objeto auxiliar (que he creado y el código del mismo
esta disponible para descargar al final del artículo) el
cual se encarga de la conversión del vector de objetos, en
un vector de vector. La conversión es realizada por el
método convertirAVectorParaWS del objeto $objSoporte (el
cual es de la clase SoporteWS). Al igual que en los ejemplos
anteriores, debemos convertir la respuesta en un tipo de datos
predefinido, en este caso es el que creamos recientemente
(tns:listadoClientes).
Como se puede ver, una vez
pasado el
ejemplo
1, los pasos son más
repetitivos, hemos incorporado algunos objetos de soporte para mantener
el código limpio, e intentado hacer el ejemplo cada vez un
poco más cercano al mundo real.
Módulo Cliente
El módulo cliente es
el mismo que el del
ejemplo
2,
simplemente modificamos el nombre del script del servidor y el nombre
de la función a llamar. En este caso el script del servidor
tiene como nombre "nusoap_server_ej3.php" y la función que
vamos a hacer uso en el webservice es "listarClientes"
<?php
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL)
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ej3.php';
$metodoALlamar = 'listarClientes';
$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
echo '<pre style="color: red">' . $error . '</pre>';
echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
die();
}
// 2. Llamar a la funcion listadoClientes del servidor
$result = $cliente->call(
$metodoALlamar, // Funcion a llamar
array(), // Parametros pasados a la funcion
"uri:$serverURL/$serverScript", // namespace
"uri:$serverURL/$serverScript/$metodoALlamar" // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
echo '<b>Error: ';
print_r($result);
echo '</b>';
} else {
$error = $cliente->getError();
if ($error) {
echo '<b style="color: red">Error: ' . $error . '</b>';
} else {
echo 'Respuesta: ';
print_r($result);
}
}
?>
Conclusión
Una vez que vamos avanzando en
los ejemplos de WebServices podemos ver la complejidad de los mismos se
puede mantener en un nivel similar (ayudandonos de algunos objetos de
soporte). Como ya se habrán dado cuenta, no voy a describir
la implementación de la clase SoporteWS ya que el
código de la misma es código PHP standard, y
escapa a los fines del ejemplo. Para simplificar lo que hace esta clase
es convertir un objeto en un vector, y un listado de objetos, en un
vector de vector. En el próximo ejemplo voy a hacer un
ejemplo del mundo real, en el cual se listan los usuarios y al hacer
click sobre un enlace, podemos ver todos los datos del mismo. El
código de este ejemplo se puede descargar
aquí.
Espero que los ejemplos hayan
podido introducir a todas aquellas personas que estan realizando
webservices, o estan planeando realizar webservices con PHP y NuSOAP.