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.

Функция ajax(..)

Эта 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

Для 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

Примеры использования Z_FLY:

  1. Скачивание файла. Несмотря, на то что, в 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;
}
  1. Генерация 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
  1. Использование Z_FLY для API запросов. Если в приложении, кроме запросов API, имеется веб интерфейс, то скорее всего, как в примере выше, нужно блокировать вызовы в common_c::head_y($action) и common_c::tail_y(), вернуть из c_api::head_y($action) true - это очистит предустановленный шаблон для тела страницы Jet. Если же приложение - полностью API микро сервис, то в общем контроллере, можно произвести общие действия для разных контроллеров микро сервиса.
⚠️ **GitHub.com Fallback** ⚠️