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
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
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
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.
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
- <?php
- class 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 script
- require_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
- <?php
- try
- {
- // 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.
Posso utilizar uma biblioteca de SOAP externa para substituir o código SOAP.PHP ?
Não há necessidade, a Soap do PHP é nativa.
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 ?
Jorge,
Não precisa definir WSDL. Estamos usando sem WSDL.
Só isso é o suficiente.
Att,
Pablo
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:
Classe ContatoService:
Arquivo soap_client.php
Olá amigos!
A extensão "php_soap" estava desabilitada no meu servidor.
RESOLVIDO.
Agora vou ver como fazer usando REST em vez de SOAP. Parece que o REST é mais rápido.
Alguém conseguiu implementar utilizando o padrão REST?
Pessoal,
Acabei de postar um artigo novo sobre REST:
www.adianti.com.br/forum/pt/view_2288?disponibilizando-web-services-
Att,
Pablo