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.