Веб-сервисы
Веб-сервис — программная система, разработанная для обеспечения взаимодействия между несколькими компьютерами через сеть. В веб-приложении это обычно набор API, который можно использовать через интернет для выполнения действий на удалённом сервере, обслуживающем веб-сервис. К примеру, клиент, основанный на Flex, может вызывать функции, реализованные на сервере в PHP-приложении. В качестве базового уровня протокола используется SOAP.
Для того, чтобы упростить задачу создания веб-сервиса, в Yii включены CWebService и CWebServiceAction. API сгруппированы по классам, которые называются провайдерами. Для каждого класса Yii генерирует WSDL, описывающий функционал предоставляемого API и правила его использования клиентом. При обработке вызова клиента, Yii создаёт соответствующий ему экземпляр провайдера, вызывает метод API и отвечает на запрос.
Примечание: Для работы CWebService требуется расширение PHP SOAP. Убедитесь, что оно включено, прежде, чем пробовать примеры, описанные далее.
Создание провайдера
Как уже было описано, провайдер — это класс, реализующий методы, которые могут быть вызваны удалённо. Для того, чтобы определить, какие методы могут быть вызваны удалённо и какое значение возвращать, 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 могут быть описаны точно таким же образом.
Реализация действия веб-сервиса
После создания провайдера необходимо сделать его доступным для клиентов.
Для этого необходимо описать действие контроллера 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
.
Использование веб-сервиса
Для того, чтобы наш пример был полным, создадим клиент, использующий веб-сервис,
который мы только что создали. В примере клиент будет написан на PHP, но для его
реализации можно использовать и другие языки, такие как Java
, C#
, Flex
и т.д.
$client=new SoapClient('http://hostname/path/to/index.php?r=stock/quote'); echo $client->getPrice('GOOGLE');
Запустив данный скрипт через браузер или в консоли, вы должны получить 350
,
что соответствует цене акций GOOGLE
.
Типы данных
При описании методов и свойств класса, которые должны быть доступны через веб-сервис, нам необходимо определить типы параметров и возвращаемых значений. Для этого могут быть использованы следующие типы:
- 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); } }
Сопоставление классов
Для получения от клиента параметров составного типа, в приложении должны быть заданы соответствия типов WSDL классам PHP. Для этого необходимо настроить свойство classMap класса CWebServiceAction.
class PostController extends CController { public function actions() { return array( 'service'=>array( 'class'=>'CWebServiceAction', 'classMap'=>array( 'Post'=>'Post', // или просто 'Post' ), ), ); } … }
Перехват удалённого вызова метода
Если реализован интерфейс IWebServiceProvider, провайдер может перехватывать удалённые вызовы методов. Используя IWebServiceProvider::beforeWebMethod можно получить текущий экземпляр CWebService. Через CWebService::methodName — название вызываемого метода. Если метод по каким либо причинам (например, отсутствие прав на его выполнение) не должен быть вызван, необходимо вернуть false.