J действия в контроллерах - energy-coresky/air GitHub Wiki
AJAX запросы очень популярны в веб. Такие запросы можно делать программно из javascript, а в ответах, можно не высылать полный код всей страницы для браузера, но только часть или даже закодированные JSON или другим способом данные. Но классический AJAX имеет недостатки: если при обычных запросах, во время разработки, возникли ошибки, то они сразу заметны в ответе браузера, так же легко организовать нотификацию об ошибках. Ответ на AJAX, можно заметить только в инструментах разработчика браузера. И второе: для организации обычного запроса, достаточно написать ссылку в теге <a..>, а для составления AJAX, нужно написать относительно большой код. Кроме того, объект XMLHTTPRequest не распознает ответ сервера, при кодах ответа отличных от 200, хотя его альтернатива fetch - распознает. Для устранения вышеописанных недостатков, в коде Coresky применяются специальные средства: функция-обёртка ajax(..)
в файле sky.js, действия в контроллерах с префиксом j_ для TOP-VIEW и специальный тип протекания скрипта J_FLY.
В коде Coresky, определяется три типа протекания скриптов. Значение типа содержится в свойстве $sky->fly
:
-
0 === $sky->fly
- обычное протекание скрипта, которое включает layout страницы, а перед закрывающим тегом</body>
, в скрытом теге<div style="display:none">
, выводится отладочная информация, в режиме DEBUG. -
J_FLY
- специальный тип протекания скрипта для AJAX. Имеет много сервисного функционала в ядре Coresky. В большинстве случаев, для реализации AJAX, удобно использовать этот способ. -
Z_FLY
- остальные способы протекания скриптов. В режиме отладки, нотификация об ошибках не может возникнуть сразу же (popup с инструментами разработчика), но возникает позже при первой возможности. Этот способ протекания скриптов, обычно, программисту, необходимо инициировать вручную, использовав методMVC::mime(..)
, хотя, в некоторых случаях$sky->fly
устанавливается автоматически ядром Coresky.
Эта javascript функция упрощает составление запросов AJAX и автоматически инициирует тип протекания скрипта J_FLY
. Всегда используется метод POST. Общий синтаксис и варианты использования:
void ajax(j_, postfields, func, c_) /* где:
j_ - action, действие в контроллере
postfields - данные в теле POST запроса
func - callback функция для обработки ответа сервера
c_ - указать контроллер явно
*/
// 1) активировать запрос в j_test(..) действие "своего" контроллера, ответ не анализировать
ajax('test')
// 2) то же самое, но еще передать данные в теле POST запроса
ajax('test', {id: 1})
// 3) то же, но с анализом ответа сервера
ajax('test', {id: 1}, function (r) {
alert(r)
})
// 4) то же, но без передачи данных в теле POST запроса
ajax('test', function (r) {
alert(r)
})
// 5) явно указать контроллер, запрос уйдет на c_main::j_test(..)
ajax('test', {id: 1}, function (r) {
alert(r)
}, 'main')
// 6) ответ сервера запишется так: $('#content').html(r)
ajax('test', 'content')
// 7) и так можно:
ajax('test', {id: 1}, 'content')
// 8) и так:
ajax('test', {id: 1}, $('#content'))
В примерах выше, "свой" контроллер, определяется на основании адреса запроса базовой страницы, т.е. предыдущего запроса с 0 === $sky->fly
из location.href
.
Первым параметром функции ajax(..)
, также может быть массив:
// 9) запрос уйдёт на c_controller::empty_j(..):
ajax(['controller'])
// 10) а так на c_controller::j_action(..):
ajax(['controller', 'action'])
// второй и т.д. параметры, можно комбинировать как и в примерах выше
Если использован массив в первом параметре для некоторого вызова ajax(..)
, то в последующих вызовах, "свой" контроллер будет c_controller::
, т.е. схема определения "своего" контроллера изменится. Однако, если в четвёртом (третьем) параметре некоторого вызова ajax(..)
, явно указан контроллер, то будет использован именно он.
На первый взгляд, такая схема "жонглирования" параметрами функции кажется запутанной. Но на самом деле, это не вносит никаких неудобств и здорово сокращает код на javascript.
Можно установить обработчик ошибок и хендлеры, которые будут вызываться перед запросами и после возвращения результата:
sky.a.error = function (r) { // JSON response always
console.log('AJAX error=' + r.err_no);
alert(r.catch_error); // visualization from Jet is possible
};
sky.a.start = function (ctrl1, j_) {
console.log('AJAX started');
};
sky.a.finish = function (timeout_id) {
console.log('AJAX finished');
};
На DEV, когда генерируются ошибки с номерами менее 100 в $sky->error_no
, автоматически появляется popup с инструментами разработчика и трассировкой. Но при большем значении номера ошибки и на DEV и на Prod, вызывается javascript обработчик ошибок sky.a.error
. Ошибки с номерами 700..799, можно использовать не как ошибки, а некоторый функционал. В файле view/error.jet, можно определять отдельные шаблоны для каждого номера ошибки. Если такие шаблоны не определены, то будет использоваться общий для всех номеров ошибок магический шаблон error._. Для генерации ошибок, необходимо вернуть из действия в контроллере INTEGER значение с номером ошибки: return 777;
Для J_FLY, в HTTP запросе, всегда присутствует заголовок: X-Action-J. Утилита SkyGate, для j_ действий, автоматически устанавливает метод POST, другие типы HTTP запросов, установить нельзя. Также, подразумевается, что семантическая часть адреса запроса отсутствует и он имеет однозначную форму:
Query string может быть продолжена, но начало однозначное:
https://example.net/?controller=action...
Значение заголовка X-Action-J, может содержать секцию кода приложения. Например, root admin раздел. J_FLY устанавливается ядром автоматически, если нет семантической части URI и переданы заголовки $_SERVER['HTTP_X_ACTION_J']
, $_SERVER['HTTP_X_REQUESTED_WITH'] == xmlhttprequest
.
Для j_ действий контроллеров, как и для a_ действий, можно настроить SkyGate и передать переменные в j_ действие.
В общем контроллере, обычно присутствует код, устанавливающий layout по умолчанию для 0 === $sky->fly
, а для других типов $sky->fly
, по умолчанию layout не используется:
<?php
class common_c extends Controller
{
use HOOK_C;
function head_y($action) {
global $sky;
$sky->fly or MVC::$layout = 'desktop';
. . .
}
. . .
}
Примеры использования Z_FLY:
- Скачивание файла. Несмотря, на то что, в
common_c::head_y($action)
,$sky->fly
равен нулю, и установится layout, обычно скрипт нужно закончить с помощьюthrow new Stop
, и шаблоны не будут использованы. ВызовMVC::mime
устанавливает mime-type и тип протекания скрипта Z_FLY. Нужно не забывать это делать в подобных случаях. Всё сработало бы верно с типом протекания =0. Но если в скрипте имеется ошибка, popup с информацией об ошибке не будет показан, хотя ошибка запишется в error-log. А если верно указан Z_FLY, popup при первом удобном случае будет показан. Это даёт возможность оперативно устранять неточности:
function a_download ($fn) {
MVC::mime('application/octet-stream'); # set Z_FLY & content-type
// also set other header's with header(..) function
for (; ob_get_level(); ob_end_clean());
readfile($fn);
throw new Stop;
}
- Генерация SVG изображения на backend, которое, в дальнейшем может быть использовано в HTML теге <img ../> или css:
<?php
class c_svg extends Controller
{
function head_y($action) { # common_c::head_y($action) will not called
# if you need common_c::head_y($action) call,
# call it directly: parent::head_y($action)
# common code for layout here
header('Cache-Control: private, max-age=3600');
# set other headers. Content-Type will set from @mime Jet operator
return [/* set variables for layout */];
}
function tail_y() { # common_c::tail_y() will not called
return '_svg.layout'; # set own layout for this controller
}
function a_img1($params) {
# action code
return [
# set variables for image here
# use vars with y_ prefix for tuning layout's variables
];
}
function a_img2($params) {
# action code
return [
# set variables for image here
];
}
}
Шаблон для контроллера в файле view/_svg.jet:
#.img1
image template
#.img1
#.img2
image template
#.img2
#.layout
@mime(image/svg+xml)<svg@block(`` as xlink) xmlns="http://www.w3.org/2000/svg"
@if($box) viewBox="{{$box}}"~if
width="{{$y_width}}" height="{{$y_height}}" fill="currentColor">
@inc(*)
</svg>
#.layout
- Использование Z_FLY для API запросов. Если в приложении, кроме запросов API, имеется веб интерфейс, то скорее всего, как в примере выше, нужно блокировать вызовы в
common_c::head_y($action)
иcommon_c::tail_y()
, вернуть изc_api::head_y($action)
true - это очистит предустановленный шаблон для тела страницы Jet. Если же приложение - полностью API микро сервис, то в общем контроллере, можно произвести общие действия для разных контроллеров микро сервиса.