Magento шаг за шагом: REST API
В предыдущей статье мы рассмотрели создание «скелета» для экспорта заказов. В этой же рассмотриим создание такого же скелета, но импорта через REST API.С Вики: REST (сокр. от англ. Representational State Transfer — «передача репрезентативного состояния») — в более употребительном узком смысле под REST понимается метод взаимодействия компонентов распределённого приложения в сети Интернет, при котором вызов удаленной процедуры представляет собой обычный HTTP-запрос (обычно GET или POST; такой запрос называют REST-запрос), а необходимые данные передаются в качестве параметров запроса. Этот способ является альтернативой более сложным методам, таким как SOAP, CORBA и RPC.
По стандартному htaccess Magento, все запросы поданные на /api/ должны отправляться на api.php:
RewriteRule ^api/([a-z][0–9a-z_]+)/?$ api.php? type=$1 [QSA, L] Почему нужно стоить использовать именно стандартный API? Помимо того, что для него уже все готово, API-запросы всегда запускаются в режиме администратора (Mage: app ()→getStore ()→isAdmin () === true), что подразумевает как языковую независимость для EAV-аттрибутов, так и отсутствие каких-либо событий из области frontend.За конфигурацию REST отвечает конфигурационный файл api2.xml в директории etc модуля, нода api2.
Итак, попробуем расширить предыдущий функционал еще и импортом.Допустим, формат вводных данных с внешней системы будет таков:
app/code/local/Easy/Interfacing/etc/api2.xml
По умолчанию все аттрибуты не должны быть массивами, что не подходит под наш формат (shipment — массив), поэтому создадим собственный фильтр, где исправим эту проблему в методе Mage_Api2_Model_Acl_Filter: collectionIn:
app/code/local/Easy/Interfacing/Model/Api2/Order/Filter.php
class Easy_Interfacing_Model_Api2_Order_Filter extends Mage_Api2_Model_Acl_Filter { public function collectionIn ($items) { $nodeName = key ($items); if (! is_numeric (key ($items[$nodeName]))) { $items[$nodeName] = array ($items[$nodeName]); } if (is_array ($items[$nodeName])) { foreach ($items[$nodeName] as &$item) { $item = $this→in ($item); } } return $items[$nodeName]; } } Не забудьте проставить ACL доступы в System > Web services > REST — Roles: и в System > Web services > REST — Attributes: И, наконец создадим сам класс API: app/code/local/Easy/Interfacing/Model/Api2/Order.php
class Easy_Interfacing_Model_Api2_Order extends Mage_Api2_Model_Resource { const RESULT_ERROR_NOT_FOUND = 404; const RESULT_ERROR_IMPORT = 500; const RESULT_SUCCESS = 200; protected $_responseItems = array (); protected function _addResult (array $item, $errorCode, $errorMessage) { $result = array ('result' => $errorCode, 'id' => $item['id']); if ($errorMessage) { $result['error'] = $errorMessage; } $this→_responseItems[] = $result; } } В нем нам особо ничего не нужно, только _addResult и пара констант кодов ошибок. Так же создадим REST-класс, унаследованный от этого: app/code/local/Easy/Interfacing/Model/Api2/Order/Rest.php class Easy_Interfacing_Model_Api2_Order_Rest extends Easy_Interfacing_Model_Api2_Order { public function dispatch () { $this→_filter = Mage: getModel ('easy_interfacing/api2_order_filter', $this); parent: dispatch (); $this→_render ($this→_responseItems); }
protected function _multiUpdate (array $filteredData)
{
foreach ($filteredData as $item) {
$order = Mage: getModel ('sales/order')→loadByIncrementId ($item['id']);
/* @var $order Mage_Sales_Model_Order */
if (!$order→getId ()) {
$this→_addResult ($item, self: RESULT_ERROR_NOT_FOUND);
continue;
}
try {
Mage: getSingleton ('easy_interfacing/order')→import ($order, $item);
$this→_addResult ($item, self: RESULT_SUCCESS);
} catch (Exception $ex) {
$order→addStatusHistoryComment ('Failed importing order: ' . $ex→getMessage ())→save ();
$this→_addResult ($item, self: RESULT_ERROR_IMPORT, $ex→getMessage ());
}
}
}
}
В нем переопределим метод dispatch, чтобы подменить фильтр на наш и сменить немного рендеринг, так как по умолчанию Magento выдаст немного кривой ответ, основанный на коллекции сообщений из getResponse ().Так как мы указывали action_type=collection, мы реализуем метод _multiUpdate. В $filteredData всегда будет находиться уже отфильтрованный массив (если из ACL аттрибутов убрать ID, то Easy_Interfacing_Model_Order: import бросит исключение, или даже крэшнется).app/code/local/Easy/Interfacing/Model/Api2/Order/Rest/Guest/V1.php
class Easy_Interfacing_Model_Api2_Order_Rest_Guest_V1 extends Easy_Interfacing_Model_Api2_Order_Rest
{
}
Guest-класс API так же нужно создать, т.к. именно он будет вызван при гостевом доступе к REST.В конечном итоге, если Вы все сделали правильно, при запросе на http:///api/rest/easy_interfacing/order/ методом PUT через любой REST-клиент вводных данных указанных выше, придет ответ вида: