RestUserController с методами:actionIndex — список пользователейactionView — просмотр пользователяactionCreate — создание пользователяactionUpdate — обновление пользователяactionDelete — удаление пользователяRestUser, которая представляет из себя ActvieRecord таблицы rest_users.actionCreate, задача которого, создание нового пользователя RestUser,class RestUserController extends Controller
{
...
public function actionCreate()
{
$model = new RestUser();
if (isset($_POST) && ($data = $_POST)) { // проверяем отправлен ли POST запрос
$model->attributes = $data; // пишем в модель новые атрибуты
if ($model->save()) { // проверяем атрибуты, если валидны - то сохраняем
$this->redirect(array('view', 'id' => $model->id));
}
}
$this->render('create', array('model' => $model)); // отображаем html-форму добавления
}
...
}
/restUser/create — отображается html-форма добавления нового пользователя, если отправляем POST-запрос на этот адрес, то отрабатывает логика валидации и добавления, затем либо перенаправляет нас на просмотр пользователя, либо отображает html-форму c ошибками.curl http://test.local/api/users \
-u demo:demo \
-d email="user@test.local" \
-d password="passwd"
< HTTP/1.1 201 Created
< Content-Type: application/json
< WWW-Authenticate: Basic realm="App"
< Location: http://test.local/api/users/TEST_ID
{
"object":"rest_user",
"id":"TEST_ID",
"email":"user@test.local",
"name":"Test REST User"
}
redirect и render, а также добавлением правил рендеринга моделей.onException и onError, а также добавлением дополнительной функциональности к базовой модели CActiveRecord и контроллеру CController при помощи поведений.class RestUserController extends Controller
{
...
public function actionCreate()
{
$model = new RestUser();
if ($this->isPost() && ($data = $_POST)) { // добавился метод isPost наряду с isPut и isDelete
$model->attributes = $data;
if ($model->save()) {
$this->redirect(array('view', 'id' => $model), true, 201); // возвращаем объект
}
}
$this->render('create', array('model' => $model), false, array('model')); // в ответе только model
}
...
}
redirect в качестве параметра id не $model->id, а объекта $model, для того чтобы созданный объект был возвращен клиенту. Также, третьим параметром добавлен код ответа 201 — это необходимо для соответсвия стандарту, т.к. вместе с ответом передается заголовок Location, содержащий адрес созданного объекта. HTTP-коды 3xx в ответе не позволяются.render, в нем содержится перечисление полей из массива $data, передаваемых в ответе клиенту. Если праметр null то возвращается весь массив $data.curl http://test.local/api/users \
-u demo:demo \
-d email="user@test.local"
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< WWW-Authenticate: Basic realm="App"
{
"error":{
"params":[
{
"code":"required",
"message":"Password cannot be blank.",
"name":"password"
}
],
"type":"invalid_param_error",
"message":"Invalid data parameters"
}
}
RestUser это поле password. Для этого определим в правиле список возвращаемых полей.rulesclass RestUser extends CModel
{
public function rules()
{
return array(
...
array('id, email, name', 'safe', 'on' => 'render'),
);
}
}
getRenderAttributes, добавленном в модель, который будет возвращать массивом все доступные для отображения атрибуты, рекурсивно проходя по связям объекта, если они указаны в правиле.\rest\Service, который занимается основной обработкой событий и правильным отображением данных. У данного сервиса есть две группы адаптеров auth и renderer. auth находятся адаптеры, осуществляющие аутентификацию — по умолчанию доступен адаптер HTTP basic auth.renderer находятся адаптеры, осуществляющие отображение данных — по умолчанию доступны два адаптера JSON и XML.main.phpYiiBase::setPathOfAlias('rest', realpath(__DIR__ . '/../extensions/yii-rest-api/library/rest'));
return array(
'basePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..',
'name' => 'My Web Application',
'preload' => array('restService'),
'import' => array(
'application.models.*',
'application.components.*',
),
'components' => array(
'restService' => array(
'class' => '\rest\Service',
'enable' =>strpos($_SERVER['REQUEST_URI'], '/api/') !== false, // для примера
),
'urlManager' => array(
'urlFormat' => 'path',
'showScriptName' => false,
'baseUrl' => '',
'rules' => array(
array('restUser/index', 'pattern' => 'api/v1/users',
'verb' => 'GET', 'parsingOnly' => true),
array('restUser/create', 'pattern' => 'api/v1/users',
'verb' => 'POST', 'parsingOnly' => true),
array('restUser/view', 'pattern' => 'api/v1/users/<id>',
'verb' => 'GET', 'parsingOnly' => true),
array('restUser/update', 'pattern' => 'api/v1/users/<id>',
'verb' => 'PUT', 'parsingOnly' => true),
array('restUser/delete', 'pattern' => 'api/v1/users/<id>',
'verb' => 'DELETE', 'parsingOnly' => true),
array('restUser/index2', 'pattern' => 'api/v2/users',
'verb' => 'GET', 'parsingOnly' => true), // к примеру, если нужно будет сменить версию API
)
),
),
);
/**
* @method bool isPost()
* @method bool isPut()
* @method bool isDelete()
* @method string renderRest(string $view, array $data = null, bool $return = false, array $fields = array())
* @method void redirectRest(string $url, bool $terminate = true, int $statusCode = 302)
* @method bool isRestService()
* @method \rest\Service getRestService()
*/
class RestUserController extends Controller
{
public function behaviors()
{
return array(
'restAPI' => array('class' => '\rest\controller\Behavior')
);
}
// если поле $fields не определено, есть возвращаемые поля по умолчанию
public function render($view, $data = null, $return = false, array $fields = array('count', 'model', 'data'))
{
if (($behavior = $this->asa('restAPI')) && $behavior->getEnabled()) {
if (isset($data['model']) && $this->isRestService() &&
count(array_intersect(array_keys($data), $fields)) == 1) {
$data = $data['model']; // по логике нашего API, возвращаемый объект мы никак не оборачиваем, но детали конкретной реализации - на ваше усмотрение
$fields = null;
}
return $this->renderRest($view, $data, $return, $fields);
} else {
return parent::render($view, $data, $return);
}
}
public function redirect($url, $terminate = true, $statusCode = 302)
{
if (($behavior = $this->asa('restAPI')) && $behavior->getEnabled()) {
$this->redirectRest($url, $terminate, $statusCode);
} else {
parent::redirect($url, $terminate, $statusCode);
}
}
}
/**
* @method array getRenderAttributes(bool $recursive = true)
* @method string getObjectId()
*/
class RestUser extends CActiveRecord
{
/**
* @return array
*/
public function behaviors()
{
return array(
'renderModel' => array('class' => '\rest\model\Behavior')
);
}
}
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
комментарии (17)