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.

Found a typo or you think this page needs improvement?
Edit it on github !