Функции-хелперы

Для более удобной работы с API предусмотрены вспомогательные PHP функции.

abortx()

Выбрасывает соответствующее исключение HttpException для указанного кода.

Аргументы:

  • (int) code - HTTP код.
  • (string) message - сообщение об ошибке.
  • (string) title - заголовок для страницы, выводящей ошибку.
  • (array) headers - массив HTTP заголовков.
$router->get('items/{$id}', function($id) use($modx) {
    $item = $modx->getObject('itemClass', ['id' => (int)$id]);
    if ($item === null) {
        abortx(404, 'Item not found!');
    }
    return jsonx($item->toArray(), ['X-Some-Header' => 'Some value']);
});

Из коробки доступны исключения для следующих кодов -

  • 400 - Bad request.
  • 401 - Unauthorized.
  • 403 - Forbidden.
  • 404 - Not found.
  • 406 - Not Acceptable.
  • 415 - Unsupported media type.
  • 500 - Internal Server Error.
  • 503 - Service Unavailable.

Исключения можно расширять для адаптации к задаче и добавлять свои собственные. Для этого нужно в файле core/config/exceptions.php для нужного кода указать соответствующий класс исключения.

return [
    401 => Zoomx\Exceptions\myUnauthorizedHttpException::class,
];

Для кодов для всех исключений кроме 400, 401 и 403 срабатывает событие OnRequestError. В плагине доступны следующие переменные -

  • $error_type - класс исключения.
  • $error_code - код ошибки.
  • $error_pagetitle - заголовок для страницы.
  • $error_message - сообщение.
  • $e - объект исключения.

filex()

Используется для управления скачиванием файлов. Может вернуть как содержимое файла, так и вывести диалог для сохранения. Удобно использовать для проксирования запросов, когда нужно исключить прямой доступ к статическому файлу.

Аргументы:

  • (string) path - абсолютный путь к файлу.
  • (bool) isAttachment - скачать файл.
  • (bool) deleteFileAfterSend - удалить файл после скачивания.
$router->get('files/{file}', function ($file) {
    // Проверить права
    if (!$modx->user->isMember('Subscribers')) {
        abortx(403, 'Только члены группы "Subscribers" могут скачивать файлы.');
    }
    // Не искать ресурс с указанным URI.
    zoomx()->autoloadResource(false);  
    // Фильтрация имени файла
    $file = basename($file);
    // Скачать файл
    return filex(MODX_CORE_PATH . "path/to/subscribers/files/$file", true);
});

Можно изменить имя скачиваемого файла

$router->get('files/{file}', function ($file) use ($modx) {
    ...
    return filex(MODX_CORE_PATH . "path/to/files/$file", true)->downloadAs('newFileName');
});

В случае, когда нужно отобразить содержимое файла в браузере, в ответе необходимо указать правильный тип контента. Иначе браузер не сможет отобразить его корректно.

$router->get('files/modx.pdf', function () {
    zoomx()->autoloadResource(false); 
    
    return filex(MODX_CORE_PATH . "path/to/files/modx.pdf")->withHeaders(['Content-Type' => 'application/pdf']);
});

Чтобы немного упростить задачу с типом контента в системе предусмотрен автоматический детектор. Для управления им предназначена системная настройка zoomx_autodetect_content_type. Изначально он включен и срабатывает, если не указан заголовок Content-Type. Принцип работы у него следующий -

  1. Первым делом он проверяет URI на наличие расширения файла. По нему определяется mime тип запрашиваемого файла.
  2. Если расширение не найдено, он проверяет mime тип указанного файла.
  3. Если тип не удалось определить, то указывается дефолтное значение 'text/html'.

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

$router->get('files/modx.pdf', function () {
    zoomx()->autoloadResource(false); 
    
    return filex(MODX_CORE_PATH . "path/to/files/modx.pdf");
});

Ещё одна из возможностей - парсить запрашиваемый файл. Что это даёт? В файлах скриптов и стилей можно указывать теги шаблонизатора. Это добавляет альтернативу подходу, когда основной функционал размещают в файле скриптов, а инициализацию делают отдельно в секции <head>.

Чтобы распарсить файл, нужно вызывать метод parse и передать в него массив параметров.

# HTML
<body>
  ...
  <script src="js/scripts.js"></script>
</body>
</html>

# router.php
$router->get('js/scripts.js', function () {
    zoomx()->autoloadResource(false); 
    
    return filex(MODX_ASSETS_PATH . "js/scripts.js")->parse(['foo' => 'bar']);
});

jsonx()

Возвращает объект класса Json\Response. Его задача подготовить данные, перевести в JSON формат и отправить пользователю с правильным заголовком.

Аргументы:

  • (array) data - данные.
  • (array) headers - масссив HTTP заголовков.
  • (int) code - HTTP код статуса для ответа. По-умолчанию 200.
$router->get('api/foo', function() {
    return jsonx(['foo' => 'bar'], ['X-Some-Header' => 'Some value']);
});

// Ответ
{
  success: true,
  data: {
      foo: "bar"
  },
  meta: {
  	total_time: "0.0230 s",
  	query_time: "0.0000 s",
  	php_time: "0.0230 s",
  	queries: 1,
  	memory: "2 048 kb"
  }
}

Если указать код 400 и выше, то свойство success в массиве ответа будет иметь значение false. А данные будут помещены в свойство errors.

{
  success: false,
  data: {},
  errors: {
      foo: "bar" // данные из функции jsonx
  },
  meta: {
  	...
  }
}

В случае, если в коде сработает исключение или PHP ошибка, то в errors будут их данные

...
errors: {
    "code": 500,
    "title": "Error 500: Internal Server Error",
    "message": "Сообщение об ошибке"
},
...

В запрос добавляются информационные данные. Отключить их можно с помощью системной настройки zoomx_include_request_info.

Важно!

Указанный выше пример сработает без ошибки 404 в двух случаях - если в запросе есть заголовок Content-Type со значением application/json или отключена автоматическая загрузка ресурса в системных настройках. В противном случае нужно отключить загрузку ресурса в самом роуте с помощью zoomx()->autoloadResource(false); или define('ZOOMX_API_MODE', true);. Вариант с заголовком оптимальнее.

$router->get('api/foo', function() {
    zoomx()->autoloadResource(false); // или define('ZOOMX_API_MODE', true);
    
    return jsonx(['foo' => 'bar'], ['X-Some-Header' => 'Some value']);
});

parserx()

Возвращает объект текущего шаблонизатора.

echo parserx()->parse($string, $placeholders);  // === zoomx('parser') === zoomx()->getParser();

redirectx()

Используется для более удобной переадресации.

Аргументы:

  • (string) url — новый URL для переадресации.
  • (int) code — код переадресации. По-умолчанию, 302.
  • (array) headers — массив HTTP заголовков.
$router->get('first.html',  function () use ($modx) {
    // Вместо 
    // $modx->sendRedirect('second.html', ['responseCode' => $_SERVER['SERVER_PROTOCOL'] . ' 301 Moved Permanently']);
    
    return redirectx('second.html', 301);
});

viewx()

Возвращает объект класса ZoomView.

Аргументы:

  • (string) tpl - имя файла шаблона.
  • (array) data - переменные шаблона.
$router->get('articles/{alias}', function($alias) {
    return viewx('article.tpl', ['foo' => 'bar']);
});

Шаблон должен располагаться в папке, в которой храняться шаблоны Smarty.

zoomx()

Возвращает инстанс главного сервис-класса компонента.

Аргумент:

  • (string) property - название свойства, в котором хранится соответствующий объект. Из коробки доступны "modx", "parser", "request", "response", "elementService", "router". Это системные объекты. Также можно получить кастомные объекты, зарегистрированные пользователем, используя функционал контейнера зависимостей.
# Получить обычный чанк MODX. 
$content = zoomx()->getChunk('modx.chunk', $params);
# Запустить сниппет MODX.
zoomx()->runSnippet('modx.snippet', $params);
# Запустить файловый сниппет.
zoomx()->runSnippet('file_snippet.php', $params);
# Получить ресурс из кэша. Если кэша нет, то из БД.
$resource = zoomx()->getResource('post1'); // В параметре можно передать как URI так и id ресурса.
# Замена $modx->getOption('setting', null, 'default')
zoomx()->config('setting', 'default');

Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.