7. SOAP e produto cartesiano

Até agora vimos como passar, através do procolo SOAP, valores escalares ou listas de valores escalares. Não vimos nenhum exemplo com valores estruturados, designados por registos ou produtos cartesianos. Por exemplo, o tipo Aluno que é constituído pelos campos nome e nota.

Depois de alguns testes, verificamos que a classe NuSOAP é capaz de lidar com qualquer estrutura de dados do PHP, podendo esta ser algo muito complexa como listas de listas ou listas de produtos cartesianos. Para exemplificar este ponto iremos implementar um serviço que recebe uma lista de Aluno e devolve o aluno com a nota mais alta, ou seja, recebe uma lista de produtos cartesianos e devolve um produto cartesiano.

Exemplo 2.31. O servidor lista de Aluno: notaMaisAlta

<?php
require_once('../lib/nusoap.php');

$server = new soap_server;
                   
$server->register( 'notaMaisAlta', 
                   array('l'=>'ListaAluno'),
                   array('res'=>'Aluno' ),
                   'uri:ws.di.uminho.pt/Estruturas',
                   'uri:ws.di.uminho.pt/Estruturas/notaMaisAlta',
                   'rpc',    
                   'encoded');

function notaMaisAlta($l)
{
  $maluno = $l[0];
  for ($i = 1; $i < count($l); $i++) 
    {
      if($l[$i]['nota'] > $maluno['nota'])
        $maluno = $l[$i];
    } 
  return new soapval('res', 'Aluno', $maluno, false, 'uri:ws.di.uminho.pt/Estruturas');
}

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?>

Este método, notaMaisAlta, parte do pricípio de que a lista que é passada ao servidor não é vazia. Vejamos agora o cliente para uma instância específica da lista de Aluno.

Exemplo 2.32. O cliente lista de Aluno: notaMaisAlta

<?php
// Teste com listas de listas
require_once('../lib/nusoap.php');

$location = 'http://localhost:8888/nusoap-0.9.5/SOAP-structs/serv-structs.php';

$client = new nusoap_client( $location, false);
$namespace = 'uri:ws.di.uminho.pt/Estruturas';
$soapaction = 'uri:ws.di.uminho.pt/Estruturas/notaMaisAlta';

$err = $client->getError();
if ($err) 
  {
    echo '<p><b>Erro na criação do cliente: ' . $err . '</b></p>';
  }
else
  {
    $res1 = $client->call('notaMaisAlta', 
                          array('l' => array( array('nome'=>'Ana', 'nota'=>13), 
                                              array('nome'=>'Carlos', 'nota'=>15), 
                                              array('nome'=>'Rui', 'nota'=>14))), 
                          $namespace, $soapaction );

    if ($client->fault) 
      {
        echo '<p><b>Fault: ';
        print_r($res1);
        echo '</b></p>';
      } 
    else 
      {
        $err = $client->getError();
        if ($err) 
          {
            echo '<p><b>Erro: ' . $err . '</b></p>';
          } 
        else 
          {
            print_r($res1);
          }
      }
  }
  
// Display the request and response
echo '<h2>Request</h2>';
echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) . '</pre>';
echo '<h2>Response</h2>';
echo '<pre>' . htmlspecialchars($client->response, ENT_QUOTES) . '</pre>';
?>

Note no seguinte exemplo como a estrutura de dados é comunicada ao servidor.

Exemplo 2.33. Pedido: Aluno com notaMaisAlta de uma Lista de Aluno

POST /nusoap-0.9.5/SOAP-structs/serv-structs.php HTTP/1.0
Host: localhost:8888
User-Agent: NuSOAP/0.9.5 (1.123)
Content-Type: text/xml; charset=ISO-8859-1
SOAPAction: "uri:ws.di.uminho.pt/Estruturas/notaMaisAlta"
Content-Length: 828

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope 
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns8423:notaMaisAlta xmlns:ns8423="uri:ws.di.uminho.pt/Estruturas">
      <l xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="unnamed_struct_use_soapval[3]">
        <item>
          <nome xsi:type="xsd:string">Ana</nome>
          <nota xsi:type="xsd:int">13</nota>
        </item>
        <item>
          <nome xsi:type="xsd:string">Carlos</nome>
          <nota xsi:type="xsd:int">15</nota>
        </item>
        <item>
          <nome xsi:type="xsd:string">Rui</nome>
          <nota xsi:type="xsd:int">14</nota>
        </item>
      </l>
    </ns8423:notaMaisAlta>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Cada registo é codificado num elemento item que por sua vez tem como subelemento os campos do array associativo que está a ser passado como parâmetro, neste caso, nome e nota.

A resposta a este pedido, que devolve a informação de um aluno mostra-se a seguir.

Exemplo 2.34. Resposta: Aluno com notaMaisAlta de uma Lista de Aluno

HTTP/1.1 200 OK
Date: Wed, 26 Dec 2012 13:52:15 GMT
Server: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By: PHP/5.3.6
X-SOAP-Server: NuSOAP/0.9.5 (1.123)
Content-Length: 649
Connection: close
Content-Type: text/xml; charset=ISO-8859-1

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope 
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:notaMaisAltaResponse xmlns:ns1="uri:ws.di.uminho.pt/Estruturas">
      <res xmlns:ns4285="uri:ws.di.uminho.pt/Estruturas" xsi:type="ns4285:Aluno">
        <nome xsi:type="xsd:string">Carlos</nome>
        <nota xsi:type="xsd:int">15</nota>
      </res>
    </ns1:notaMaisAltaResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>