Christian escribió un artículo hace unos días sobre la manera de usar NuSOAP para crear un servicio web. El artículo describe en detalles el procedimiento. No obstante, probar de retornar un arreglo es un trabajo bastante complejo en NuSOAP, o por lo menos esta mal documentado. Una excelente referencia (en Inglés) sobre el tema se puede encontrar en el blog de Lyingonthecovers, pero el artículo faltaba (he puesto un comentario ahí) una noción importante que es que NuSOAP debe tener un ‘return’ => ‘xsd:Array’ en su método register() para retornar el formato correcto.
En este artículo, revisaremos como retornar arreglos.
Retornar arreglos simples
Primero, imaginamos, como en el artículo en Inglés de Lyingonthecovers, que queremos hacer un servicio web que retorna, en el caso de Dokeos, detalles sobre un curso.
La función que se encargar de recojer la información se llamará getCourseDetails(), tomará solo un parámetro tipo string en entrada (para parametros complejos, ver el ejemplo de Christian) y retornará un arreglo del tipo siguiente:
Array(
['code'] => ‘ABC’,
['title'] => ‘English alphabet’,
['url'] => ‘http://www.example.com/ABC’,
['teacher'] => ‘Yannick Warnier’,
['language'] => ‘english’
)
Hemos definido nuestras necesidades, ahora vamos más adelante y registramos el servicio mismo y sus tipos de datos:
$server = new soap_server();
$server->configureWSDL(‘WSCourse’, ‘urn:WSCourse’);
// definimos el tipo complejo (arreglo asociativo, =’struct’) de detalles de curso
$server->wsdl->addComplexType(
‘courseDetails’,
‘complexType’,
’struct’,
‘all’,
”,
array(
‘name’=>’code’ , ‘type’=>’xsd:string’,
‘name’=>’title’ , ‘type’=>’xsd:string’,
‘name’=>’url’ , ‘type’=>’xsd:string’,
‘name’=>’teacher’, ‘type’=>’xsd:string’,
‘name’=>’language’,'type’=>’xsd:string’,
)
);
Por favor apunten que declaramos un tipo, pero no hay ninguna relación, al nivél de esta declaración, entre el tipo y un método. Este tipo podrá ser reutilizado para otros métodos también.
// Registramos el método y su parámetro de entrada
$server->register(‘getCourseDetails’, // nombre método
array(‘username’ => ‘xsd:string’), // parametros entrantes al servicio
array(‘return’ => ‘tns:courseDetails’), // valor(es) retornado(s)
‘urn:WSCourse’, // namespace (espacio de nombre)
‘urn:WSCourse#getCourseDetails’, // acción SOAP
‘rpc’, // estílo
‘encoded’, // tipo de uso
‘This service returns a list of courses’ // documentación
);
En este caso, usamos directamente un ’struct’ como valor de retorno. Usamos el marcador ‘tns:’ (probablemente Type NameSpace o algo así) para decir que es un tipo complejo definido por otro lado, y definimos que tipo exactamente queremos usar.
Esto es lo que debería ocurir y, para este caso (no verificado), tal vez funcionaría. Si no funciona, prueben remplazar tns:courseDetails por xsd:Array, simplemente (vemos más abajo casos probados).
En el caso un poco más complejo en que tenga que devolver un arreglo de estos courseDetails, como hago?
Arreglos de arreglos
Una estructura a dos niveles no se puede definir en solo una definición de ComplexType. En sí, se tiene que definir cada nivel como un ComplexType:
$server->wsdl->addComplexType(
‘courseDetails’,
‘complexType’,
’struct’,
‘all’,
”,
array(
‘name’=>’code’ , ‘type’=>’xsd:string’,
‘name’=>’title’ , ‘type’=>’xsd:string’,
‘name’=>’url’ , ‘type’=>’xsd:string’,
‘name’=>’teacher’, ‘type’=>’xsd:string’,
‘name’=>’language’,'type’=>’xsd:string’,
)
);
Nada cambia para esta primera parte. Ahora definimos el arreglo que va a contener estos structs:
$server->wsdl->addComplexType(
‘courseList’,
‘complexType’,
‘array’,
”,
‘SOAP-ENC:Array’,
array(),
array(
array(‘ref’=>’SOAP:ENC:arrayType’,
‘wsdl:arrayType’=>’tns:courseDetails[]‘)
),
‘tns:courseDetails’
);
Bueno, hay mucho que todavía no hemos detallado ahí, pero no es directamente el objetivo de este artículo. Una cosa es importante: esto es la forma de declarar un arreglo (no asociativo, es decir con indices numéricos unicamente) del ComplexType courseDetails.
Una vez que tenemos esto listo, la lógica nos haría pensar que simplemente debería registrar este tipo complejo en mi servicio web:
// Registramos el método y su parámetro de entrada
$server->register(‘getCourseDetails’, // nombre método
array(‘username’ => ‘xsd:string’), // parametros entrantes al servicio
array(‘return’ => ‘tns:courseList’), // valor(es) retornado(s)
‘urn:WSCourse’, // namespace (espacio de nombre)
‘urn:WSCourse#getCourseDetails’, // acción SOAP
‘rpc’, // estílo
‘encoded’, // tipo de uso
‘This service returns a list of courses’ // documentación
);
… y ahí es donde perdimos horas buscando. En realidad, parece que hay algo malo ahí, en la forma en que NuSOAP (a lo menos versión de Agosto de 2008) retorna este valor, que es incorrecto. Resulta que el cliente SOAP de PHP5 no entiende el valor retornado. Ni para este arreglo de structs, ni para el struct mismo.
Abandonar la definición de tipos complejos
La solución es de abandonar la idea de definir el tipo de valor retornado, y simplemente usar xsd:Array como valor de retorno:
// Registramos el método y su parámetro de entrada
$server->register(‘getCourseDetails’, // nombre método
array(‘username’ => ‘xsd:string’), // parametros entrantes al servicio
array(‘return’ => ‘xsd:Array’), // valor(es) retornado(s)
‘urn:WSCourse’, // namespace (espacio de nombre)
‘urn:WSCourse#getCourseDetails’, // acción SOAP
‘rpc’, // estílo
‘encoded’, // tipo de uso
‘This service returns a list of courses’ // documentación
);
No hay lógica ahí, es cierto, pero a lo menos espero que les ayudarán. Me estoy comunicando con los desarrolladores de NuSOAP para averiguar el tema.
Escrito por ywarnier
Escrito por cfasanando