Disponibilizando Web Services pelo Adianti Framework com SOAP Durante o desenvolvimento de um sistema, é comum termos de disponibilizar algumas de suas rotinas para que estas sejam executadas por aplicativos externos. O caminho mais utilizado para tal é por meio de Web Services, e SOAP é um dos protocolos que permite isto. Imagine que você desenvolveu todo um sistema que controla clientes, e agora precisa que outros sistemas possam consulta...
PD
Disponibilizando Web Services pelo Adianti Framework com SOAP  
Fechado
Durante o desenvolvimento de um sistema, é comum termos de disponibilizar algumas de suas rotinas para que estas sejam executadas por aplicativos externos. O caminho mais utilizado para tal é por meio de Web Services, e SOAP é um dos protocolos que permite isto. Imagine que você desenvolveu todo um sistema que controla clientes, e agora precisa que outros sistemas possam consultar informações a respeito destes clientes. Neste artigo veremos como disponibilizar métodos criados no Adianti Framework por meio de Web Services. Neste artigo, trabalharemos com a classe de Clientes, e criaremos um Web Service para retornar X clientes.

Bom, em primeiro lugar, provavelmente você já tem uma série de classes de modelo representando suas tabelas na pasta app/model. Junto ao tutor, temos por exemplo a classe Customer. Agora, queremos criar um Web Service para retornar X clientes. Para tal, precisamos criar uma classe de serviço. Uma classe de serviço age criando uma camada que interage com uma funcionalidade interna da aplicação e expõe esta funcionalidade para o mundo externo. Neste caso, vamos chamar a classe de CustomerService e salvar em app/service/CustomerService.php. Veja que a classe em questão, utiliza a classe Customer, já existente em app/model/Customer.php, e também usa a conexão "samples", existente em app/config/samples.ini

A classe CustomerService terá o método getBetween() que retornará todos os clientes cujo ID está entre dois valores informados. Para tal, este método receberá os parâmetros que futuramente serão passados pela chamada do Web Service. Estes parâmetros identificam o código inicial ($from) e final ($to) dos clientes a serem obtidos.

app/service/CustomerService.php
<?phpclass CustomerService{    /**     * Retorna todos clientes entre $from e $to     * @param $from Código inicial     * @param $to Código final     */    public static function getBetween( $from, $to )    {        TTransaction::open('samples');        $response = array();                // define o critério        $criteria = new TCriteria;        $criteria->add(new TFilter('id', '>=', $from));        $criteria->add(new TFilter('id', '<=', $to));                // carrega os clientes        $all = Customer::getObjects( $criteria );        foreach ($all as $customer)        {            $response[] = $customer->toArray();        }        TTransaction::close();        return $response;    }}?>



O próximo passo é habilitar um servidor SOAP no Adianti Framework. Para tal, basta salvarmos o arquivo a seguir no diretório raíz da aplicação com o nome de soap.php. Este script NÃO FAZ PARTE da instalação default do framework por questões de segurança. Como este arquivo disponibiliza as classes do framework para utilização externa, é IMPRESCINDÍVEL implementar um mecanismo de controle, ou seja, filtrar somente as requisições válidas. Para tal, foi colocado ali no arquivo um lembrete (// aqui implementar mecanismo de controle).

Não abordaremos aqui como adicionar segurança à chamada SOAP, mas uma das formas, é passando uma chave de segurança ou utilizar Token-Based Authorization. Por enquanto, faremos apenas um filtro para permitir somente algumas classes (in_array).

/soap.php
<?php// initialization scriptrequire_once 'init.php';class AdiantiSoapServer{    public function __call($method, $parameters)    {        $class    = isset($_REQUEST['class']) ? $_REQUEST['class']   : '';        $response = NULL;                // aqui implementar mecanismo de controle !!        if (!in_array($class, array('CustomerService')))        {            throw new SoapFault('server', _t('Permission denied'));        }                try        {            if (class_exists($class))            {                if (method_exists($class, $method))                {                    $rf = new ReflectionMethod($class, $method);                    if ($rf->isStatic())                    {                        $response = call_user_func_array(array($class, $method),$parameters);                    }                    else                    {                        $response = call_user_func_array(array(new $class($_GET), $method),$parameters);                    }                    return $response;                }                else                {                    throw new SoapFault('server', TAdiantiCoreTranslator::translate('Method ^1 not found', "$class::$method"));                }            }            else            {                throw new SoapFault('server', TAdiantiCoreTranslator::translate('Class ^1 not found', $class));            }        }        catch (Exception $e)        {            throw new SoapFault('server', $e->getMessage());        }    }}$server = new SoapServer(NULL, array('encoding' => 'UTF-8', 'uri' => 'http://test-uri/'));$server->setClass('AdiantiSoapServer');$server->handle();?>



Agora que já temos a classe de serviço criada, basta invocarmos o Web Service pela linha de comando. Neste caso, basta copiarmos este trecho de arquivo e salvarmos com um nome qualquer (ex: soap_client.php), e executarmos ele pela linha de comando. Antes, lembre de substituir a variável location pelo caminho de sua aplicação

soap_client.php
<?phptry{    // define local do serviço    $location = "http://caminho-da-aplicacao/soap.php?class=CustomerService";    // instancia cliente SOAP    $client = new SoapClient(NULL, array('encoding'   =>'UTF-8',                                         'exceptions' => TRUE,                                         'location'   => $location,                                         'uri'        => "http://test-uri/"));    // executa o método    print_r($client->getBetween(3,4));}catch (Exception $e){    echo 'Call error: ' . $e->getMessage();}?>


php5 soap_client.php


Pronto, você obterá como resultado os clientes 3 e 4 na forma de um array retornado pelo serviço.

PS: Ao criarmos uma camada específica para serviços (CustomerService), desoneramos a classe de modelo (Customer), e também evitamos de colocar lá chamadas para bibliotecas externas, o que não é recomendado para uma camada de modelo.

Curso Dominando o Adianti Framework

O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado!


Dominando o Adianti Framework Quero me inscrever agora!

Comentários (9)


AM

Posso utilizar uma biblioteca de SOAP externa para substituir o código SOAP.PHP ?
PD

Não há necessidade, a Soap do PHP é nativa.
JH

Pablo Dall'Oglio, no Soap nativo do php, vou ter que construir toda parte de XML na mão?
Pois se querer testar no SOAP UI nesse modelo não tem como correto ?
Como os clientes vão conectar esse webservice ?

PD

Jorge,

Não precisa definir WSDL. Estamos usando sem WSDL.
Só isso é o suficiente.

Att,
Pablo
GO

Olá Amigos!

Tenho uma aplicação na qual estou estudando as funcionalidades do framework, ela é baseada no template ERP II e tentei implementar as funcionalidades desse artigo. Quando faço a chamada do arquivo recebo a linha de erro abaixo:

Algum amigo pode me dizer onde estou errando?
Sou iniciante em PHP e no framework.

Erro:

Fatal error: Class 'SoapClient' not found in C:\wamp\www\SintemaInterno\soap_client.php on line 11

Classe Model:

<?php/** * Contato Active Record * @author  <your-name-here> */class Contato extends TRecord{    const TABLENAME = 'contato';    const PRIMARYKEY= 'id';    const IDPOLICY =  'serial'; // {max, serial}            private $categoria_contato;    /**     * Constructor method     */    public function __construct($id = NULL, $callObjectLoad = TRUE)    {        parent::__construct($id, $callObjectLoad);        parent::addAttribute('Razao_Social');        parent::addAttribute('categoria_contato_id');        parent::addAttribute('Fantasia');        parent::addAttribute('status');        parent::addAttribute('endereco');        parent::addAttribute('bairro');        parent::addAttribute('cep');        parent::addAttribute('cidade');        parent::addAttribute('estado');        parent::addAttribute('cpf_cnpj');        parent::addAttribute('rg_ie');        parent::addAttribute('telefone_1');        parent::addAttribute('telefone_2');        parent::addAttribute('telefone_3');        parent::addAttribute('email_1');        parent::addAttribute('email_2');        parent::addAttribute('observacao');        parent::addAttribute('data_cadastro');        parent::addAttribute('dia_vencimento');    }        /**     * Method set_categoria_contato     * Sample of usage: $contato->categoria_contato = $object;     * @param $object Instance of CategoriaContato     */    public function set_categoria_contato(CategoriaContato $object)    {        $this->categoria_contato = $object;        $this->categoria_contato_id = $object->id;    }        /**     * Method get_categoria_contato     * Sample of usage: $contato->categoria_contato->attribute;     * @returns CategoriaContato instance     */    public function get_categoria_contato()    {        // loads the associated object        if (empty($this->categoria_contato))            $this->categoria_contato = new CategoriaContato($this->categoria_contato_id);            // returns the associated object        return $this->categoria_contato;    }    }</code>


Classe ContatoService:

<?phpclass ContatoService{    /**     * Retorna todos Contatos com $Filtro     * @param $TipoFiltro "C" código ou "R" Razão Social      * @param $Filtro "1" ou "iniciodonome%"     */    public static function getContatos($TipoFiltro, $Filtro )    {        TTransaction::open('conexaomysql');        $response = array();                // define o critério        $criteria = new TCriteria;                if ($TipoFiltro == 'C')        {            $criteria->add(new TFilter('id', '=', $Filtro));         }        else if ($TipoFiltro == 'D')        {            $criteria->add(new TFilter('Razao_Social', 'like', $Filtro));         }                // carrega os clientes        $all = Contato::getObjects( $criteria );        foreach ($all as $Contato)        {            $response[] = $Contato->toArray();        }        TTransaction::close();        return $response;    }}?>


Arquivo soap_client.php

<?phptry{    // define local do serviço    //$location = "http://caminho-da-aplicacao/soap.php?class=CustomerService";    $location = "http://localhost/SintemaInterno/index.php?class=ContatoService";                // instancia cliente SOAP    $client = new SoapClient(NULL, array('encoding'   =>'UTF-8',                                         'exceptions' => TRUE,                                         'location'   => $location,                                         'uri'        => "http://test-uri/"));    // executa o método    print_r($client->getContatos('C','1'));    }catch (Exception $e){    echo 'Call error: ' . $e->getMessage();}?>



GO

Olá amigos!
A extensão "php_soap" estava desabilitada no meu servidor.

RESOLVIDO.


RM

Agora vou ver como fazer usando REST em vez de SOAP. Parece que o REST é mais rápido.
EA

Alguém conseguiu implementar utilizando o padrão REST?
PD

Pessoal,

Acabei de postar um artigo novo sobre REST:
www.adianti.com.br/forum/pt/view_2288?disponibilizando-web-services-

Att,
Pablo