В статье рассмотрим как устроеныajax запросы в OpenCart, в том числе запросы черезapi OpenCart, познакомимся с новым понятиемfront controllerи немного коснемся темыajax REST API.
Клиент
Клиентская часть OpenCart работает с использованиемjquery, а значит можно
использовать$.ajax
из этой библиотеки.Ссылка на документацию. Примеры
ajax запросов на клиентской части можно посмотреть
вadmin/view/template/sale/order_form.tpl
(.twig
для OpenCart 3.0).
Сервер
Просматривая все тот же
файлadmin/view/template/sale/order_form.tpl
(для
OpenCart 2.3)можно понять, чтов качестве адреса вызова
используется классическая схема роутинга OpenCart. Посмотрим на
один из запросов:
$.ajax({ url: 'index.php?route=customer/customer/autocomplete&token=<?php echo $token; ?>&filter_name=' + encodeURIComponent(request), ...
Все просто:url - путь до контроллера и, если надо,имя метода этого контроллера.
То есть, нам нужносоздать класс контроллера, затем из файлов представления можновызывать методы этого контроллераajax запросами.
Создадим контроллер нашего нового тестового модуля по
путиadmin/controller/extension/module/myajax.php:
class ControllerExtensionModuleMyAjax extends Controller{ public function index() { $this->response->addHeader('Content-Type: application/json'); $this->response->setOutput(json_encode( [ "success" => true, "message" => "ok", "data" => [] ] )); }}
В классе контроллера есть объектresponse
, это
экземпляр классаResponse
, который расположен по
путиsystem/library/response.php
. Он позволяет
управлять ответом сервера. Нас интересуют только 2 метода:
-
addHeader($header)
- добавить http заголовок,header
строковый аргумент -
setOutput($output)
- установить данные для вывода,output
строковый аргумент
Для формирования ответа на запрос в методе контроллера можно использовать-
$this->response
Так как OpenCart имеет 2режима доступа/контекста(admin, catalog), то передаваемые данные в запросах разные:
-
admin
- требует токен вget
параметре(получить можно из объекта класса контроллера):-
для OpenCart 2.3
token
, который берется из$this->session->data['token']
-
для OpenCart 3.0C4C, который берется изC14CC5C
-
-
catalog
- в общем случае не требует токена, но есть нюансы о которых позже
Теперь чтобы осуществитьajax запросдостаточно в файл представления(читай в html)подставить js(код для OpenCart 2.3):
$.ajax({ url: '<?php echo $admin; ?>index.php?route=extesion/module/myajax&token=<?php echo $token; ?>', type: 'get', dataType: 'json', success: function(json) { alert("success: "+json["success"]+"\n"+"message: "+json["message"]); }, error: function(xhr, ajaxOptions, thrownError) { alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); }});
В этом коде в urladmin
это путь указывающий контекст
запроса(admin или catalog). Для контекста есть 2 дефайна,
определенных вadmin/config
:
-
HTTP_SERVER
илиHTTP<b style="box-sizing: border-box;">S</b>_SERVER
- путь до директорииadmin
(проще - админка), где будет осуществлен поиск контроллера для выполнения запроса -
HTTP_CATALOG
илиC6CC15C- корень сайта, однако контроллеры будут браться из директорииC16CC7C
Ajax API
Просматривая файл
представленияadmin/view/template/sale/order_form.tpl
(OpenCart
2.3), можно увидеть что из админки осуществляются ajax запросы
наcatalog
контекст, с использованием особого
токена.
Сначала объявляется глобальная переменнаяtoken
,
затем ajax запрос на адрес/index.php?route=api/login
,
который отвечает json данными, в которых есть
ключtoken
:
var token = ''; // Login to the API$.ajax({ url: '<?php echo $catalog; ?>index.php?route=api/login', type: 'post', data: 'key=<?php echo $api_key; ?>', dataType: 'json', crossDomain: true, success: function(json) { //... if (json['token']) { token = json['token']; } }, error: function(xhr, ajaxOptions, thrownError) { alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); }});
Контроллер этого запроса находится
вcatalog/controller/api/login.php
ControllerApiLogin::index
. Он:
-
создает новую сессию
(
catalog/model/account/api.php - ModelAccountApi::addApiSession
) и -
генерирует для нее случайный токен(функция
token
находится вsystem/helper/general.php
),
который возвращается в json этого ajax запроса, если доступ по
api(api_key
)разрешен для текущего
пользователя(Админка-Система-API).
Дальше разбирая
представлениеadmin/view/template/sale/order_form.tpl
можно
увидеть, что последующиеajax запросы, которые по
адресуroute=api/...
используют этот
самыйtoken
для определения права доступа, таким
образом(в каждом api файле, в каждом методе)C25C существует такой
кусок кода для определения права осуществлять запрос:
if (!isset($this->session->data['api_id'])) { $json['error']['warning'] = $this->language->get('error_permission');} else { ...}
Ajax запросы через
catalog
контекст можно осуществлять с использованиемtoken
для безопасного доступа
А теперь копнем глубже и выясним, как это происходит внутри движка, ведь можно отправлятьajax запросыи без токена.
Просматривая код файлаindex.php
отправляемся
вsystem/startup.php
, оттуда следуем
вsystem/framework.php
в самый конец и видим такое
вот:
// Front Controller$controller = new Front($registry); // Pre Actionsif ($config->has('action_pre_action')) { foreach ($config->get('action_pre_action') as $value) { $controller->addPreAction(new Action($value)); }}
Здесь видим новое понятиеfront controller, код
которого находится вsystem/engine/front.php
в
классеFront
.
Ниже следует мое субъективное определение этого понятия :)
Подробных комментариев найти не удалось, но судя по
кодуfront controllerэтоглавный/передний
контроллер, онзапускает общий
контроллерstartup/router
относительно
директорииcontroller
контекста(admin/controller
илиcatalog/controller
),
которыйвыполняет первичные контроллеры,указанные
в$_['action_pre_action'];
в
файлеsystem/config/catalog.php
.
В коде выше происходит только добавление первичных контроллеров
воfront controller, а их исполнение осуществляется
кодом ниже, в методеdispatch
(внутри метода перед
выполнением action указанного
в$config->get('action_router')
):
// Dispatch$controller->dispatch(new Action($config->get('action_router')), new Action($config->get('action_error')));
Среди первичных контроллеров
естьstartup/session
относительноcatalog/controller
,
где вControllerStartupSession::index
находится
интересующий наскод для авторизации в api через токен.
Вкратце:
-
происходит проверка обращения к
api/
и наличияget
параметраtoken
-
удаление старых api сессий
-
выборка актуальной api сессии на основании ip адреса запросившего и его токена
-
старт сессии с id из
$_COOKIE["api"]
-
обновление времени модификации сессии, (чтобы она осталась жива, то есть не была устаревшей)
Теперь, когда исполнение кода дойдет до целевого контроллера,
$this->session->data['api_id']
уже будет инициализировано, если указана актуальная комбинация токена и ip адреса.
Ajax REST API
Данная глава описывает возможный вариант создания и встроенные средства реализации REST API в OpenCart.
Мы рассмотрели реализациюajax запросов
OpenCartдляadmin
иcatalog
контекстов.
Если говорить обadmin
, то предполагается более
рациональным реализовывать контроллеры именно
вadmin
контексте. Однако, такое не всегда возможно.
Иногда один и тот же код контроллера(возможно речь о методе
контроллера)должен использоваться в
обработчикеcatalog
события(например при изменении
заказа), так и отдельно непосредственно при работе с заказом через
админку. Чтобы устранить такие случаи можно реализовать контроллеры
вcatalog
контексте и организовать для нихбезопасный
доступ(о чем говорится в предыдущей главе).
Для реализацииREST API в OpenCartесть все необходимое:
-
объект для работы с ответом сервера в контроллере
$this->response
, а именно методыaddHeader
иsetOutput
-
безопасная работа с административным доступом через
catalog
C22Cконтекст -
единая точка входа api черезC24CC10CC25C контекст, в директориюC26CC11CC27C, можно размещать свои файлы контроллеров и при помощи ajax осуществлять к ним запросы
На стороне сервера надосоздать
контроллерывcatalog/controller/api/
, а на стороне
клиентадобавить ajax запросы в нужные файлы представленийс
использованием токена, полученного в результате ajax
запросаapi/login
. Если в этих файлах нет такого ajax
запроса, тогда необходимо добавить его, например, взяв
изadmin/view/template/sale/order_form.tpl.
Теперь чтобы
сделать REST API достаточно изучить, что это такое, несколько
ссылок: