Web Service

Web service é um sistema de software projetado para suportar interações máquina-máquina interoperáveis através de uma rede. No contexto de aplicações Web geralmente refere-se a um conjunto de APIs que podem ser acessadas através da Internet e executadas em um sistema remoto que hospeda o serviço solicitado. Por exemplo, um cliente baseado em Flex, poderá chamar uma função implementada no lado do servidor rodando uma aplicação Web baseada em PHP. Web Service se baseia em SOAP como a camada principal da pilha de protocolo de comunicação.

O Yii fornece as classes CWebService e CWebServiceAction para simplificar o trabalho de implementação de Web Service em uma aplicação Web. As APIs são agrupadas dentro de classes chamadas de prestadores de serviço. O Yii irá gerar para cada classe uma especificação WSDL que descreve quais APIs estão disponíveis e como elas devem ser chamadas pelo cliente. Quando uma API é chamada por um cliente, o Yii irá instanciar o prestador de serviço correspondente e chamar a API requisitada para executar a requisição.

Nota: A classe CWebService é depende da Extensão PHP SOAP. Tenha certeza que você possui ela habilitada antes de testar os exemplos disponíveis nesta seção.

1. Definindo um Prestador de Serviço

Como mencionado acima, o prestador de serviços é uma classe que define os métodos que podem ser chamados remotamente. O Yii se baseia em comentários de documentação e reflexão de classes para identificar quais métodos podem ser chamados remotamente e quais são os seus parâmetros e valores retornados.

Vamos iniciar com um simples serviço de cotação de ações. Este serviço permite uma requisição de um cliente para cotar uma ação específica. Definimos o prestador de serviços como a seguir. Note que definimos a classe prestadora de serviço StockController como extensão de CController. Isto não é obrigatório. Explicaremos mais adiante por que fazemos dessa forma.

class StockController extends CController
{
    /**
     * @param string símbolo da ação
     * @return float preço da ação
     * @soap
     */
    public function getPrice($symbol)
    {
        $prices=array('IBM'=>100, 'GOOGLE'=>350);
        return isset($prices[$symbol])?$prices[$symbol]:0;
        //...retorna o preço da ação para o $symbol
    }
}

Acima declaramos o método getPrice para ser a API do Web Service, marcando-o com a tag @soap no comentário de documentação. Contamos com a documentação de comentário para especificar o tipo de dados dos parâmetros de entrada e dos valores de retorno. APIs adicionais podem ser declaradas de forma semelhante.

2. Declarando Ações do Web Service

Uma vez definido o prestador de serviço, precisamos fazer com que ele esteja disponível para os clientes. Particularmente, precisamos criar uma ação de controle para expor este serviço. Isto pode ser feito facilmente declarando uma ação CWebServiceAction na classe de controle. Para exemplificar, colocamos ela na classe StockController.

class StockController extends CController
{
    public function actions()
    {
        return array(
            'quote'=>array(
                'class'=>'CWebServiceAction',
            ),
        );
    }
 
    /**
     * @param string símbolo da ação
     * @return float preço da ação
     * @soap
     */
    public function getPrice($symbol)
    {
        //...retorna o preço da ação para o $symbol
    }
}

Isto é tudo o que precisamos para criar um Web Service! Se tentar acessar a ação através da URL http://hostname/path/to/index.php?r=stock/quote, vamos ver um monte de conteúdo XML que é o WSDL para o Web Service que definimos .

Dica: Por padrão, CWebServiceAction assume que o controller corrente é o prestador de serviço. É por isso que definimos o método getPrice dentro da classe StockController.

3. Utilizando um Web Service

Para completar o exemplo, vamos criar um cliente que utiliza o Web Service que acabamos de criar. O cliente de exemplo é escrito em PHP, porém, ele poderia ser em outra linguagem como Java, C#, Flex, etc.

$client=new SoapClient('http://hostname/path/to/index.php?r=stock/quote');
echo $client->getPrice('GOOGLE');

Executando o script acima em modo Web ou console e veremos que 350 é o preço para GOOGLE.

4. Tipos de dados

Quando declaramos métodos e propriedades de classes que são acessadas remotamente, precisamos especificar o tipo de dados dos parâmetros de entrada e saída. A seguir, os tipos de dados mais primitivos que podemos utilizar:

  • str/string: mapeado para xsd:string;
  • int/integer: mapeado para xsd:int;
  • float/double: mapeado para xsd:float;
  • bool/boolean: mapeado para xsd:boolean;
  • date: mapeado para xsd:date;
  • time: mapeado para xsd:time;
  • datetime: mapeado para xsd:dateTime;
  • array: mapeado para xsd:string;
  • object: mapeado para xsd:struct;
  • mixed: mapeado para xsd:anyType.

Se um tipo não é um dos descritos acima, ele será considerado como um tipo composto que consiste de propriedades. Um tipo composto é representado em termos de uma classe e suas propriedades como variáveis públicas da classe, marcadas com a tag @soap em seu comentário de documentação.

Podemos utilizar também o tipo array adicionando [] no final do tipo primitivo ou composto. Isto poderia especificar um array de um tipo específico.

Abaixo um exemplo que define a Web API getPosts que retorna um array de objetos Post.

class PostController extends CController
{
    /**
     * @return Post[] uma lista de Post
     * @soap
     */
    public function getPosts()
    {
        return Post::model()->findAll();
    }
}
 
class Post extends CActiveRecord
{
    /**
     * @var integer ID do post
     * @soap
     */
    public $id;
    /**
     * @var string título do post
     * @soap
     */
    public $title;
 
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
}

5. Mapeamento de Classes

Para receber parâmetros de tipo composto de um cliente, um aplicativo precisa declarar o mapeamento de tipos WSDL para as classes PHP correspondentes. Isto é realizado configurando a propriedade classMap de CWebServiceAction.

class PostController extends CController
{
    public function actions()
    {
        return array(
            'service'=>array(
                'class'=>'CWebServiceAction',
                'classMap'=>array(
                    'Post'=>'Post',  // ou simplesmente 'Post'
                ),
            ),
        );
    }
    ......
}

6. Interceptando Chamadas a Método Remoto

Com a implementação da interface IWebServiceProvider, um prestador de serviço pode interceptar chamadas a método remoto. Em IWebServiceProvider::beforeWebMethod, o prestador de serviços pode recuperar o estado atual da instância de CWebService e obter o nome do método que está sendo chamado atualmente através de CWebService::methodName. Ele pode retornar false se o método remoto não pode ser chamado por algum motivo (por exemplo, acesso não autorizado).

$Id: topics.webservice.txt 1808 2010-02-17 21:49:42Z qiang.xue $

Be the first person to leave a comment

Please to leave your comment.