Inscrições abertas para nosso Webinar anual Adianti Framework 2024!
Clique aqui para saber mais
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
  1. <?php
  2. class CustomerService
  3. {
  4.     /**
  5.      * Retorna todos clientes entre $from e $to
  6.      * @param $from Código inicial
  7.      * @param $to Código final
  8.      */
  9.     public static function getBetween$from$to )
  10.     {
  11.         TTransaction::open('samples');
  12.         $response = array();
  13.         
  14.         // define o critério
  15.         $criteria = new TCriteria;
  16.         $criteria->add(new TFilter('id''>='$from));
  17.         $criteria->add(new TFilter('id''<='$to));
  18.         
  19.         // carrega os clientes
  20.         $all Customer::getObjects$criteria );
  21.         foreach ($all as $customer)
  22.         {
  23.             $response[] = $customer->toArray();
  24.         }
  25.         TTransaction::close();
  26.         return $response;
  27.     }
  28. }
  29. ?>



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
  1. <?php
  2. // initialization script
  3. require_once 'init.php';
  4. class AdiantiSoapServer
  5. {
  6.     public function __call($method$parameters)
  7.     {
  8.         $class    = isset($_REQUEST['class']) ? $_REQUEST['class']   : '';
  9.         $response NULL;
  10.         
  11.         // aqui implementar mecanismo de controle !!
  12.         if (!in_array($class, array('CustomerService')))
  13.         {
  14.             throw new SoapFault('server'_t('Permission denied'));
  15.         }
  16.         
  17.         try
  18.         {
  19.             if (class_exists($class))
  20.             {
  21.                 if (method_exists($class$method))
  22.                 {
  23.                     $rf = new ReflectionMethod($class$method);
  24.                     if ($rf->isStatic())
  25.                     {
  26.                         $response call_user_func_array(array($class$method),$parameters);
  27.                     }
  28.                     else
  29.                     {
  30.                         $response call_user_func_array(array(new $class($_GET), $method),$parameters);
  31.                     }
  32.                     return $response;
  33.                 }
  34.                 else
  35.                 {
  36.                     throw new SoapFault('server'TAdiantiCoreTranslator::translate('Method ^1 not found'"$class::$method"));
  37.                 }
  38.             }
  39.             else
  40.             {
  41.                 throw new SoapFault('server'TAdiantiCoreTranslator::translate('Class ^1 not found'$class));
  42.             }
  43.         }
  44.         catch (Exception $e)
  45.         {
  46.             throw new SoapFault('server'$e->getMessage());
  47.         }
  48.     }
  49. }
  50. $server = new SoapServer(NULL, array('encoding' => 'UTF-8''uri' => 'http://test-uri/'));
  51. $server->setClass('AdiantiSoapServer');
  52. $server->handle();
  53. ?>



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
  1. <?php
  2. try
  3. {
  4.     // define local do serviço
  5.     $location "http://caminho-da-aplicacao/soap.php?class=CustomerService";
  6.     // instancia cliente SOAP
  7.     $client = new SoapClient(NULL, array('encoding'   =>'UTF-8',
  8.                                          'exceptions' => TRUE,
  9.                                          'location'   => $location,
  10.                                          'uri'        => "http://test-uri/"));
  11.     // executa o método
  12.     print_r($client->getBetween(3,4));
  13. }
  14. catch (Exception $e)
  15. {
  16.     echo 'Call error: ' $e->getMessage();
  17. }
  18. ?>


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.

Pacotão Dominando o Adianti Framework 7
O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado! Versão 7.4


Dominando o Adianti 7 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:

  1. <?php
  2. /**
  3.  * Contato Active Record
  4.  * @author  <your-name-here>
  5.  */
  6. class Contato extends TRecord
  7. {
  8.     const TABLENAME 'contato';
  9.     const PRIMARYKEY'id';
  10.     const IDPOLICY =  'serial'// {max, serial}
  11.     
  12.     
  13.     private $categoria_contato;
  14.     /**
  15.      * Constructor method
  16.      */
  17.     public function __construct($id NULL$callObjectLoad TRUE)
  18.     {
  19.         parent::__construct($id$callObjectLoad);
  20.         parent::addAttribute('Razao_Social');
  21.         parent::addAttribute('categoria_contato_id');
  22.         parent::addAttribute('Fantasia');
  23.         parent::addAttribute('status');
  24.         parent::addAttribute('endereco');
  25.         parent::addAttribute('bairro');
  26.         parent::addAttribute('cep');
  27.         parent::addAttribute('cidade');
  28.         parent::addAttribute('estado');
  29.         parent::addAttribute('cpf_cnpj');
  30.         parent::addAttribute('rg_ie');
  31.         parent::addAttribute('telefone_1');
  32.         parent::addAttribute('telefone_2');
  33.         parent::addAttribute('telefone_3');
  34.         parent::addAttribute('email_1');
  35.         parent::addAttribute('email_2');
  36.         parent::addAttribute('observacao');
  37.         parent::addAttribute('data_cadastro');
  38.         parent::addAttribute('dia_vencimento');
  39.     }
  40.     
  41.     /**
  42.      * Method set_categoria_contato
  43.      * Sample of usage: $contato->categoria_contato = $object;
  44.      * @param $object Instance of CategoriaContato
  45.      */
  46.     public function set_categoria_contato(CategoriaContato $object)
  47.     {
  48.         $this->categoria_contato $object;
  49.         $this->categoria_contato_id $object->id;
  50.     }
  51.     
  52.     /**
  53.      * Method get_categoria_contato
  54.      * Sample of usage: $contato->categoria_contato->attribute;
  55.      * @returns CategoriaContato instance
  56.      */
  57.     public function get_categoria_contato()
  58.     {
  59.         // loads the associated object
  60.         if (empty($this->categoria_contato))
  61.             $this->categoria_contato = new CategoriaContato($this->categoria_contato_id);
  62.     
  63.         // returns the associated object
  64.         return $this->categoria_contato;
  65.     }
  66.     
  67. }
  68. </code>


Classe ContatoService:

  1. <?php
  2. class ContatoService
  3. {
  4.     /**
  5.      * Retorna todos Contatos com $Filtro
  6.      * @param $TipoFiltro "C" código ou "R" Razão Social 
  7.      * @param $Filtro "1" ou "iniciodonome%"
  8.      */
  9.     public static function getContatos($TipoFiltro$Filtro )
  10.     {
  11.         TTransaction::open('conexaomysql');
  12.         $response = array();
  13.         
  14.         // define o critério
  15.         $criteria = new TCriteria;
  16.         
  17.         if ($TipoFiltro == 'C')
  18.         {
  19.             $criteria->add(new TFilter('id''='$Filtro)); 
  20.         }
  21.         else if ($TipoFiltro == 'D')
  22.         {
  23.             $criteria->add(new TFilter('Razao_Social''like'$Filtro)); 
  24.         }
  25.         
  26.         // carrega os clientes
  27.         $all Contato::getObjects$criteria );
  28.         foreach ($all as $Contato)
  29.         {
  30.             $response[] = $Contato->toArray();
  31.         }
  32.         TTransaction::close();
  33.         return $response;
  34.     }
  35. }
  36. ?>


Arquivo soap_client.php

  1. <?php
  2. try
  3. {
  4.     // define local do serviço
  5.     //$location = "http://caminho-da-aplicacao/soap.php?class=CustomerService";
  6.     $location "http://localhost/SintemaInterno/index.php?class=ContatoService";
  7.     
  8.     
  9.     
  10.     // instancia cliente SOAP
  11.     $client = new SoapClient(NULL, array('encoding'   =>'UTF-8',
  12.                                          'exceptions' => TRUE,
  13.                                          'location'   => $location,
  14.                                          'uri'        => "http://test-uri/"));
  15.     // executa o método
  16.     print_r($client->getContatos('C','1'));    
  17. }
  18. catch (Exception $e)
  19. {
  20.     echo 'Call error: ' $e->getMessage();
  21. }
  22. ?>



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