Tuesday, February 24th, 2009 | Author: zedmaster

Objetivo

O objetivo deste tutorial é ensinar a criar um Servidor SOAP, utilizando
a biblioteca do Zend Framework.
Pedi para o meu amigo Artista Frustrado, elaborar uma introdução a webservice, e fazer exemplos em outras linguagens, confira.

Material

Componentes do Zend Framework:

  • Zend_Loader
  • Zend_Soap
  • Zend_Soap_Client
  • Zend_Soap_AutoDiscover

Arquivos soap.tar.bz2:

/index.php
/client.php
/Client
    /Calculadora.php
/Server
    /Calculadora.php
    /ServerSoap.php
/README

Testado no seguinte ambiente:

  • Versão do Zend Framework testada: 1.7.5
  • Sistema Operacional: Linux
  • Distribuição: Debian Lenny
  • Versão do PHP: PHP 5.2.6-1+lenny2
  • Versão do Apache: Apache/2.2.9 (Debian)

Material recomendado para leitura:

SOAP

O SOAP é um protocolo de comunicação entre o web service e o cliente. Suas especificações não são simplesmente uma transferência de XML basica, são envolvidas diversas regras para aplicações em diveras plataformas e formatos de XML.

Quando utilizar SOAP?

Quando você não quer disponibilizar a apresentação da camada so seu aplicativo, e sim, apenas algumas funcionalidades, evitando abrir conexões com bancos.

Quando você tem que iteragir com outros sistemas homogeneos. Exemplo, o seu fornecedor tem uma aplicação em .NET e precisa acessar uncionalidades do seu sistema que é feito em PHP. Assim, temos linguagens, sistemas operacionais e banco de dados diferentes podendo se comunicar.

Quando você quer centralizar as regras de negócios no servidor. Usando clientes que acessam o servidor, sendo eles qualquer dispositivo (PDA, Terminal, celular etc.)

Configurando o Ambiente

Temos a seguinte estrutura de pastas:

/soap
    /index.php
    /client.php
   /Client
        /Calculadora.php
    /Server
        /Calculadora.php
        /ServerSoap.php
    /README
/zf

Na pasta soap é aonde ficam os arquivos e na pasta zf a biblioteca do Zend Framework.

- Descompacte o arquivo soap.tar.bz2 na sua pasta web (no meu caso foi na pasta /var/www)

- Configure o apache para apontar para a pasta do soap
No Linux:


    ServerName soap.localhost
    DocumentRoot /mnt/dados/www/soap

- Adicione no arquivo hosts: 127.0.0.1 soap.localhost
No Linux: adicione a linha no arquivo /etc/hosts

- Reinicie o apache

- Teste no browser os endereços:
– http://soap.localhost
– http://soap.localhost?wsdl

- Finalmente execute o cliente:
No Linux:

:# php cliente.php

Deve aparecer a seguinte resposta:
##############################

Lista das funções disponíveis:
array(3) {
  [0]=>
  string(12) "string ola()"
  [1]=>
  string(25) "int somar(int $a, int $b)"
  [2]=>
  string(45) "string objeto(string $objeto, string $metodo)"
}

ola() -> Oi

somar(2,2) -> 4

calculadora->somar(3,3) -> 6

calculadora->naoexiste() -> O método: naoexiste() não foi implementado.

##############################

Pronto você já esta usando SOAP.

Exemplo

O nosso exemplo consiste em um servidor web rodando um web service em PHP com Zend_Soap_Client Zend Framework, e um cliente também em PHP que acessa a mesma máquina através do console, no endereço http://soap.localhost.

O cliente deve solicitar ao servidor algumas funções, e obter suas respostas.

O arquivo index.php contém o código para a criação do arquivo WSDL e do servidor SOAP.
O Zend_Soap_AutoDiscover cria o arquivo WSDL para o servidor SOAP.
O Zend_Soap que executa as funções cadastradas no WSDL, por isso que é passado por parâmetro a url http://soap.localhost/index.php?wsdl .

arquivo index.php

set_include_path(
    '../zf/ZendFramework-1.7.5/library/'
    . PATH_SEPARATOR . get_include_path()
);

require_once "Server/Calculadora.php";
require_once "Server/Soap.php";
require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();

ini_set("soap.wsdl_cache_enabled", 0); //** Limpa o cache

if(isset($_GET['wsdl'])) {
    //** Cria o arquivo WSDL automaticamente
    $autodiscover = new Zend_Soap_AutoDiscover();
    $autodiscover->setClass('ServerSoap');
    $autodiscover->handle();
} else {
    //** Executa o servidor SOAP
    $soap = new Zend_Soap_Server("http://soap.localhost/index.php?wsdl");
    $soap->setClass('ServerSoap');
    $soap->handle();
}

IMPORTANTE: Deve-se colocar o tipo de dados que os métodos recebem e retornam usando os tipos de dados do PHPDOC. Veja nos comentários do exemplo.

arquivo Server/Soap.php

class ServerSoap
{
    /**
     *  @return string
     */
    public function ola()
    {
        return "Oi";
    }

    /**
     * @param int $a
     * @param int $b
     * @return int
     */
    public function somar($a,$b)
    {
        return $a + $b;
    }

    /**
     * Executa uma classe vinda do cliente.
     *
     * @param string $objeto
     * @param string $metodo
     * @return string
     */
    public function objeto($objeto, $metodo)
    {
        $tmp = unserialize($objeto);

        //** Verifica se o método existe para o $objeto
        $class_methods = get_class_methods($tmp);
        foreach ($class_methods as $method_name) {
            if($method_name == $metodo)
            {
                $tmp->$metodo();
                return serialize($tmp);
            }
        }

        $tmp->msg = "O método: {$metodo}() não foi implementado.";
        return serialize($tmp);
    }
}

O Zend_Soap_Client conecta no servidor SOAP, passando a url do WSDL. Para acessar as funções cadastradas basta a variável instanciada e o nome da função.

arquivo client.php:

set_include_path(
    '../zf/ZendFramework-1.7.5/library/'
    . PATH_SEPARATOR . get_include_path()
);

require_once "Client/Calculadora.php";
require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();

ini_set("soap.wsdl_cache_enabled", 0); //** Limpa o cache

//** Inicia a conexão com o cliente
$client = new Zend_Soap_Client("http://soap.localhost/index.php?wsdl");

echo "\n##############################\n\n";

echo "Lista das funções disponíveis:\n";
var_dump($client->getFunctions());

//** Chama a função ola()
echo "\nola() -> ".$client->ola() ."\n\n";

//** Chama a função somar(a,b)
echo "somar(2,2) -> ".$client->somar(2,2) ."\n\n";

//** Cria o objeto Calculadora e passa para o SOAP executar a soma
$calculadora = new Calculadora(3,3);

$soapCalculadora =  $client->objeto(serialize($calculadora), "somar"); //* A Calculadora tem que ser serializada antes de passar para o SOAP.
$unserializeCalculadora = unserialize($soapCalculadora); //* A Calculadora tem que ser deserializada antes de chamar o metodo resposta().
echo "calculadora->somar(3,3) -> ".$unserializeCalculadora->resposta()."\n\n"; 

$erroCalculadora = $client->objeto(serialize($calculadora), "naoexiste");//** Tentando executar um método inexistente.
$erroCalculadora = unserialize($erroCalculadora);
echo "calculadora->naoexiste() -> ".$erroCalculadora->msg."\n";

echo "\n##############################\n\n";

A classe Calculadora

Temos duas instâncias do objeto Calculadora, uma para o servidor , aonde contém o método calcular() e a do cliente aonde temos o método resposta().
Para passar o objeto Calculadora do cliente para o servidor, e depois do servidor para o cliente, usamos uma técnica chamada serialização.

Server/Calculadora.php

/**
 * Classe calculadora do servidor
 *
 */
class Calculadora
{
    public $a;
    public $b;
    public $resposta;

    /**
     * Executa a soma
     *
     */
    public function somar()
    {
        $this->resposta = $this->a + $this->b;
    }
}

Client/Calculadora.php

/**
 * Classe calculadora do cliente
 *
 */
class Calculadora
{
    public $a;
    public $b;
    public $resposta;

    /**
     * Construtor da classe
     *
     * @param int $a
     * @param int $b
     * @return void
     */
    public function __construct($a, $b)
    {
        $this->a = $a;
        $this->b = $b;
    }

    /**
     * Retorna a resposta da soma
     *
     * @return int
     */
    public function resposta()
    {
        return $this->resposta;
    }
}

Para dúvidas ou críticas construtivas entre em contato.

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

3 Responses

  1. 1
    Peu 

    Estou tentando fazer algo parecido, mas que nao eh diferente do que voce fez. Apenas estou iniciando o servidor em um controller. O problema e que sempre recebo uma mensagem de erro:

    [WSDL] SOAP-ERROR: Parsing WSDL: Couldn’t find

    Nao sei o que esta acontecendo. Tem alguma ideia ?

  2. 2
    zedmaster 

    Só vendo o código.

  3. 3
    Giolvani 

    cara,

    muito bom seu exemplo, isso vai me ajudar muito!!! rs…

    parabéns…

Leave a Reply

Please insert the signs in the image: