Подход REST в PHP

Продолжим тему начатую в прошлой статье про подход REST, рассмотрим со стороны сервера с использованием языка PHP. Согласно принципу REST нам предстоит реализовать четыре операции: GET, PUT, POST и DELETE.

Примеры будут построены на основе классической схемы построения современных web приложений построенной по потерну MVC (Model View Controller). Мой код будет базироваться на моем движке, но я думаю кто знаком с патерном MVC смогут понять, я рассмотрю только основные заморочки.

Рассмотрим подробней как ExtJS передает и принимает данные. Адрес по которому ExtJs обращается для работы с данными настраивается в Ext.data.HttpProxy параметром url.


var proxy = new Ext.data.HttpProxy({
    url: '/controller'
});
 

Также если не охота связываться или по каким то причинам не возможно использовать разные HTTP методы. То можно указать для них другие урлы и методы вот так:


var proxy = new Ext.data.HttpProxy({
    url: '/controller',
    api: {
        load: {url: '/controller/load', method: 'GET'},
        create: '/controller/create',
        destroy: '/controller/destroy',
        save: '/controller/update'
    }    
});
 

Но мы то пойдем джедайским путем и будем использовать HTTP методы.

Первая проблема состоит в том, что PHP не разбирает переданные параметры методом PUT поэтому — это предстоит сделать нам, взяв их прям из потока php://input.Для начала создадим класс который будет прозрачно возвращать нам данные независимо от метода.


class Request {
    public $params,$method;
    public function __construct() {
        $this->method = $_SERVER["REQUEST_METHOD"]; // Получим метод
        if($this->method == 'PUT'){ // Если метод PUT парсим параметры в ручную :)
            $this->params = array();
            $putdata = file_get_contents('php://input'); // Взяли все данные
            parse_str($putdata,$this->params);   // Распарсили
        }  else {
            this->params = $_REQUEST;
        }
    }  
}
 

Вот такой получился у нас простенький класс.

Вторая проблема может возникнуть при удаление и обновление. ExtJs идентификатор объекта добавляет в адрес скрипта вот так /url/id. Большинство MVC фраемворков данный формат хорошо разбирают и как правило передают во внутрь метода контроллера. Что делать если ваш движок этого не умеет, тогда можно сделать переадресацию с помощью mod rewrite. Либо, например, указав в качестве урла /app.php?/controller, а там уже парсить строку запроса самому, взяв из переменной $_SERVER["PATH_INFO"]. Например вот такой регуляркой preg_match ('/^\/([a-z]+\w)\/([0–9]+)$/', $_SERVER["PATH_INFO"], $matches).

Третья проблема -это то что ExtJs для вставке новой и изменение старой записи параметры передает в качестве JSON строке, в переменной с именем указанном в Ext.data.Store, в переменной root вообще-то это не большая проблема, берем и конвертируем с помощью функции json_decode (stripslashes ($param['data'])).

Формат отдачи данных для ExtJs единый для всех методов.Нужно передать флаг success об успешности операции. Также передается массив данных, которые претерпели изменения в переменной, которая указана в Ext.data.Store в переменной root.

Теперь создадим наш контроллер, который будет обрабатывать пользователей нашего сайта.


class CRestController extends Controller {
    public function rest($params) { // в метод передается как раз список параметров, идущих после названия метода разделенных слешем
        $request = new Request();
        $id = isset($params[0])?$params[0]:false;    // вытащим id он у нас идет первым
        $data = isset($request->params['data'])?json_decode(stripslashes($param['data'])):false;    // Распарсим наши JSON данные
        try {        
            switch ($this->request->method) { // Данные функции должны быть определены в конечных контроллерах
                case 'GET':
                    return $this->load(); // Получение списка параметров
                    break;
                case 'POST':
                    return $this->create($data);
                    break;
                case 'PUT':
                    return $this->update($id,$data);
                    break;
                case 'DELETE':
                    return $this->destroy($id);
                    break;
            }
        } catch(Exception $ex)
        {
            return new JsonView($this,array(
                'success' => false,
                'message' => $ex->getMessage()
            ));
        }            
    }
}
 

Рассматривать каждый метод не буду, их реализация зависит от используемого движка. Но все они должны вернуть клиенту структуру такого вида:


{
    success:true, // Флаг успешности операции
    message:'',   // Сообщение если нужно
    data:[ // При удаление и если при обновление данные сервер не изменяет, параметр не нужен
        /* массив данных согласно структуре заданной в Ext.data.Record */
    ]  
}
 

У меня в движке, это происходит примерно так:


function load(){
    return new JsonView($this,array(
        'success' => true,
        'data'    => MUser::getAll()
    ));        
}
 

В моем движке JsonView отвечает за вывод данных в JSON, вы же можете для этих целях использовать функцию json_encode. Я постарался как можно понятней изложить суть вопроса, но если, что-то все таки не понятно, спрашивайте в комментариях. Также на сайте ExtJS появился пример использования этой технологии, можете посмотреть там

Понравилась статья? Помогите блогу перейдите по рекламе, вам это ничего не будет стоить.


Комментарии.

Написать комментарий