0 follower

Веб-сервисы

Веб-сервис — программная система, разработанная для обеспечения взаимодействия между несколькими компьютерами через сеть. В веб-приложении это обычно набор API, который можно использовать через интернет для выполнения действий на удалённом сервере, обслуживающем веб-сервис. К примеру, клиент, основанный на Flex, может вызывать функции, реализованные на сервере в PHP-приложении. В качестве базового уровня протокола используется SOAP.

Для того, чтобы упростить задачу создания веб-сервиса, в Yii включены CWebService и CWebServiceAction. API сгруппированы по классам, которые называются провайдерами. Для каждого класса Yii генерирует WSDL, описывающий функционал предоставляемого API и правила его использования клиентом. При обработке вызова клиента, Yii создаёт соответствующий ему экземпляр провайдера, вызывает метод API и отвечает на запрос.

Примечание: Для работы CWebService требуется расширение PHP SOAP. Убедитесь, что оно включено, прежде, чем пробовать примеры, описанные далее.

1. Создание провайдера

Как уже было описано, провайдер — это класс, реализующий методы, которые могут быть вызваны удалённо. Для того, чтобы определить, какие методы могут быть вызваны удалённо и какое значение возвращать, Yii использует специальные комментарии и reflection.

Попробуем реализовать простой сервис, отдающий информацию о котировках акций определённой компании. Для этого нам потребуется реализовать провайдер, как показано ниже. Стоит отметить, что наследуем класс провайдера StockController от CController. Наследование не является обязательным. Мы опишем, зачем оно нужно, ниже.

class StockController extends CController
{
    /**
     * @param string индекс предприятия
     * @return float цена
     * @soap
     */
    public function getPrice($symbol)
    {
        $prices=array('IBM'=>100, 'GOOGLE'=>350);
        return isset($prices[$symbol])?$prices[$symbol]:0;
        //...возвращаем цену для компании с индексом $symbol
    }
}

Выше мы описали, что метод getPrice является частью API веб-сервиса, пометив его в комментарии тэгом @soap. Там же мы описали типы параметров и возвращаемого значения. Дополнительные методы API могут быть описаны точно таким же образом.

2. Реализация действия веб-сервиса

После создания провайдера необходимо сделать его доступным для клиентов. Для этого необходимо описать действие контроллера CWebServiceAction. В нашем примере мы используем StockController:

class StockController extends CController
{
    public function actions()
    {
        return array(
            'quote'=>array(
                'class'=>'CWebServiceAction',
            ),
        );
    }
 
    /**
     * @param string индекс предприятия
     * @return float цена
     * @soap
     */
    public function getPrice($symbol)
    {
        //...возвращаем цену для компании с индексом $symbol
    }
}

Это всё, что требуется для создания веб-сервиса. Теперь при обращении к URL http://hostname/path/to/index.php?r=stock/quote, мы получим объёмистый XML, на самом деле являющийся WSDL описанного нами веб-сервиса.

Подсказка: По умолчанию, при использовании CWebServiceAction подразумевается, что текущий контроллер является провайдером. Именно поэтому мы определили метод getPrice в классе StockController.

3. Использование веб-сервиса

Для того, чтобы наш пример был полным, создадим клиент, использующий веб-сервис, который мы только что создали. В примере клиент будет написан на PHP, но для его реализации можно использовать и другие языки, такие как Java, C#, Flex и т.д.

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

Запустив данный скрипт через браузер или в консоли, вы должны получить 350, что соответствует цене акций GOOGLE.

4. Типы данных

При описании методов и свойств класса, которые должны быть доступны через веб-сервис, нам необходимо определить типы параметров и возвращаемых значений. Для этого могут быть использованы следующие типы:

  • str/string: соответствует xsd:string;
  • int/integer: соответствует xsd:int;
  • float/double: соответствует xsd:float;
  • bool/boolean: соответствует xsd:boolean;
  • date: соответствует xsd:date;
  • time: соответствует xsd:time;
  • datetime: соответствует xsd:dateTime;
  • array: соответствует xsd:string;
  • object: соответствует xsd:struct;
  • mixed: соответствует xsd:anyType.

Если тип не является одним из приведённых выше, он воспринимается как составной тип, состоящий из свойств. Этот тип соответствует классу, а его свойства — public-переменным класса, отмеченных в комментариях @soap.

Также можно использовать массивы. Для этого необходимо дописать [] в конец примитивного или составного типа. Таким образом мы получим массив с элементами заданного типа.

Ниже приведён пример определения метода API getPosts, возвращающего массив объектов класса Post.

class PostController extends CController
{
    /**
     * @return Post[] список записей
     * @soap
     */
    public function getPosts()
    {
        return Post::model()->findAll();
    }
}
 
class Post extends CActiveRecord
{
    /**
     * @var integer ID записи
     * @soap
     */
    public $id;
    /**
     * @var string заголовок записи
     * @soap
     */
    public $title;
 
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
}

5. Сопоставление классов

Для получения от клиента параметров составного типа, в приложении должны быть заданы соответствия типов WSDL классам PHP. Для этого необходимо настроить свойство classMap класса CWebServiceAction.

class PostController extends CController
{
    public function actions()
    {
        return array(
            'service'=>array(
                'class'=>'CWebServiceAction',
                'classMap'=>array(
                    'Post'=>'Post',  // или просто 'Post'
                ),
            ),
        );
    }
    ......
}

6. Перехват удалённого вызова метода

Если реализован интерфейс IWebServiceProvider, провайдер может перехватывать удалённые вызовы методов. Используя IWebServiceProvider::beforeWebMethod можно получить текущий экземпляр CWebService. Через CWebService::methodName — название вызываемого метода. Если метод по каким либо причинам (например, отсутствие прав на его выполнение) не должен быть вызван, необходимо вернуть false.