Веб-сервіс — програмна система, розроблена для забезпечення взаємодії між декількома компʼютерами через мережу. У веб-додатку це зазвичай набір 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
.
При описі методів і властивостей класу, які повинні бути доступні через веб-сервіс, нам необхідно визначити типи параметрів і значень. Для цього можуть бути використані наступні типи:
xsd:string
;xsd:int
;xsd:float
;xsd:boolean
;xsd:date
;xsd:time
;xsd:dateTime
;xsd:string
;xsd:struct
;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.