For the complete documentation index, see llms.txt. This page is also available as Markdown.

Работа с запросом (Request)

Данные HTTP запроса в JohnCMS представлены классом \Johncms\Http\Request. Это тонкая обёртка над Symfony\Component\HttpFoundation\Request: доступны все методы HttpFoundation (getClientIp(), isSecure(), getPathInfo(), бэги query, request, cookies, files, headers, server, attributes), а обёртка добавляет к ним несколько коротких методов для самых частых операций чтения.

Как получить запрос

Запрос принадлежит одному циклу обработки, поэтому он не является сервисом контейнера. Способ получить его ровно один: запрос передают туда, где он нужен.

В контроллере — аргумент действия

Объявите параметр с типом Request — запрос подставится в него автоматически:

<?php

declare(strict_types=1);

namespace Johncms\Modules\MyModule\Application\Controllers;

use Johncms\Http\Request;
use Symfony\Component\HttpFoundation\Response;

final class MyController
{
    public function view(Request $request, int $id): Response
    {
        $page = $request->queryInt('page', 1);

        // ...
    }
}

Запрос подставляется по типу параметра, а параметры маршрута — по имени, поэтому порядок аргументов роли не играет.

Запрос объявляют только те действия, которые действительно его читают. Если действие лишь показывает форму — параметр не нужен.

В middleware — аргумент handle()

В сервисе, который живёт дольше запроса

Варианты в порядке предпочтения:

  1. принять нужный факт параметром (строку адреса, хост — см. ClientInfoDTO);

  2. принять Request параметром того метода, который его читает, если нужен целый набор полей;

  3. прочитать текущий запрос из Symfony\Component\HttpFoundation\RequestStack.

Стек — крайний вариант и допустим только в system/src/; в Application-слое модуля это тот же скрытый захват запроса, только в другой форме. Он оправдан, когда вызывающих десятки и передать запрос неоткуда (PaginationFactory, Theme, Environment).

В шаблоне — факт, а не запрос

Шаблон не обращается к запросу. Нужный ему факт отдаёт тонкий сервис поверх стека, и шаблон резолвит именно этот сервис:

Получение данных из строки запроса ($_GET)

Пользователь открыл http://domain.com/?user_id=123&search=john:

Первым параметром идёт имя параметра запроса, вторым — значение по умолчанию. Отдельного аргумента с фильтром нет: тип задаёт сам метод.

Получение данных из тела запроса ($_POST и JSON)

Методы body* читают тело запроса независимо от того, пришло оно формой или JSON:

Проверить наличие ключа (например, галочки в форме) можно так:

Метод запроса проверяется через isPost() или общий isMethod():

Некорректные данные

queryInt() и bodyInt() мягко относятся к мусору: ?id=abc вернёт значение по умолчанию, а не ошибку. Но массив в скалярном параметре (?id[]=1) — это попытка подмены типа, она намеренно не подавляется и превращается в ответ 400 Bad Request.

Если нужна строгая семантика, обращайтесь к бэгам HttpFoundation напрямую — там неверное значение бросает исключение:

Строки приходят обрезанными

Все строки в теле формы и в строке запроса обрезаются по краям (trim) глобальным middleware TrimStringsMiddleware до того, как отработает контроллер. Это касается и чтения через бэги напрямую. Тело в формате JSON не обрезается.

Параметры маршрута

Параметры маршрута — это не данные запроса, их объявляют аргументами действия по имени, и они приводятся к типу аргумента:

При необходимости все параметры совпавшего маршрута доступны как атрибуты запроса:

Cookies, заголовки и данные сервера

Для них используются штатные бэги HttpFoundation:

Получение файлов ($_FILES)

Загруженные файлы доступны в бэге files. Для одного поля:

Для всех сразу — $request->files->all(). Множественное поле (<input type="file" name="photos[]" multiple>) возвращается уже нормальным списком объектов, собирать структуру $_FILES вручную не нужно.

Элемент бэга — это Symfony\Component\HttpFoundation\File\UploadedFile, то есть HTTP-тип. Он не должен покидать слой HTTP: контроллер преобразует его в \Johncms\Http\UploadedFileDTO с помощью \Johncms\Http\UploadedFileMapper, и дальше — в use case, сервисы, хранилище — передаётся уже DTO.

Сам DTO умеет проверять успешность загрузки и переместить файл, поэтому оригинальный HTTP-объект дальше не нужен:

Доступные поля DTO: clientName, mimeType, size, tmpPath, error.

Последнее обновление

Это было полезно?