Router
Triangle Router сопоставляет HTTP-метод и путь с callback, извлекает параметры, хранит middleware маршрута и строит URL по имени. Исполнение контроллера и формирование HTTP-ответа выполняет Engine-HTTP; сам dispatch возвращает результат поиска, а не ответ клиенту.
Установка
Заголовок раздела «Установка»composer require triangle/routerПакет объявляет PHP ^8.1 и triangle/engine ^8.1. Главный класс — Triangle\Router, без дополнительного пространства Router перед именем класса.
Маршрут
Заголовок раздела «Маршрут»В config/route.php приложения:
use Triangle\Router;
Router::get('/users/{id:\d+}', static function ($request, string $id) { return ['id' => $id];})->name('users.show');Первый аргумент callback при исполнении Engine-HTTP — request. Параметр id поступает как строка, даже если ограничен цифрами. Существование пользователя, доступ к нему и допустимые диапазоны проверяются отдельно.
Помимо get доступны post, put, patch, delete, head, options и any. Для явного списка методов используйте Router::route(['GET', 'POST'], $path, $callback). Методы задаются в верхнем регистре; any регистрирует метод *.
Callback может быть замыканием, массивом [Controller::class, 'method'] или строкой Controller@method. Регистрация проверяет существование класса/метода; создание экземпляра и внедрение зависимостей происходят в HTTP Engine.
Параметры и группы
Заголовок раздела «Параметры и группы»{id} по умолчанию соответствует одному непустому сегменту без /. После двоеточия можно задать выражение, например {id:\d+}. Опциональные части в квадратных скобках разрешены только в конце: /articles[/{slug}]. Несбалансированные скобки и некорректные определения отклоняются при разборе.
Router::group('/api', static function (): void { Router::get('/health', static fn ($request) => ['ok' => true]);});Префикс группы добавляется к путям внутри неё; вложенные группы накапливают префиксы. Callback группы выполняется сразу при регистрации. Не используйте регистрацию групп как обработчик пользовательского запроса.
Когда маршруты становятся доступны
Заголовок раздела «Когда маршруты становятся доступны»Bootstrap собирает route.php приложения и включённых плагинов, после чего создаёт dispatcher. В обычном Triangle-процессе это часть запуска.
Для отдельного процесса после регистрации выполните:
Router::collect([]);$result = Router::dispatch('GET', '/users/42');Пустой список не очищает зарегистрированные маршруты: он создаёт dispatcher из уже накопленных данных. До collect dispatcher не готов. Маршрут, добавленный после сборки, не появится в dispatch до следующей сборки.
Collect загружает файлы через require_once. Он не является hot reload изменённого route.php и не очищает старые регистрации. При изменении конфигурации перезапускайте соответствующие процессы приложения; публичного Router::clear в этой реализации нет.
Результат dispatch
Заголовок раздела «Результат dispatch»| Результат | Значение |
|---|---|
| FOUND | callback, именованные параметры и RouteObject |
| METHOD_NOT_ALLOWED | Список методов, для которых этот путь существует |
| NOT_FOUND | Подходящего пути нет |
HEAD пробует GET, если отдельный HEAD не найден. Затем проверяются маршруты any. Сам router не удаляет тело ответа для HEAD и не отправляет заголовок Allow: это обязанности HTTP-слоя.
URL по имени
Заголовок раздела «URL по имени»$url = Router::getByName('users.show')?->url(['id' => 42, 'page' => 2]);Результат — /users/42?page=2. Именованные параметры подставляются в путь, остаток становится query string. Неизвестное имя возвращает null.
URL-генератор не проверяет regex маршрута и не кодирует сегменты: id=a/b создаст дополнительный сегмент. До подстановки проверьте значение и при необходимости примените rawurlencode к отдельному сегменту. Не кодируйте целиком весь URL.
Вызов url без параметров возвращает исходный pattern, включая {id} и квадратные скобки опциональных частей. Если параметров недостаточно, необработанные placeholders могут остаться в строке; такой результат нельзя считать готовой ссылкой.
Middleware и fallback
Заголовок раздела «Middleware и fallback»Маршрут принимает middleware через ->middleware(ClassName::class) или список классов. Массив разворачивается при сохранении, а Middleware Bootstrap ещё раз учитывает порядок при сборке HTTP-цепочки. Проверяйте ожидаемый порядок при смешивании одиночных и списочных регистраций.
Router::fallback регистрирует callback для HTTP-обработки отсутствующего маршрута. Прямой dispatch по-прежнему возвращает NOT_FOUND; он сам fallback не исполняет. Fallback callback собирается с withGlobal=false, поэтому на него нельзя автоматически распространять политику глобальных middleware.
Регистрация
Заголовок раздела «Регистрация»| API | Назначение |
|---|---|
| get/post/put/patch/delete/head/options(path, callback) | Один HTTP-метод |
| any(path, callback) | Fallback метода * |
| route(methods, path, callback) | Строка либо массив методов |
| group(prefix, callback) | Группа с префиксом; возвращает Router группы |
| resource(name, controller, actions = null, prefix = ”) | CRUD-маршруты по существующим методам контроллера либо списку actions |
| collect(paths) | Загрузка route.php и построение dispatcher |
| dispatch(method, path) | Поиск без исполнения callback |
Resource создаёт index (GET /name), store (POST /name), create (GET /name/create), edit (GET /name/{id}/edit), show (GET /name/{id}), update (PUT /name/{id}), patch (PATCH /name/{id}) и destroy (DELETE /name/{id}). Без actions регистрируются только существующие методы. Дополнительные явно перечисленные actions получают any /name/action[/{id}].
Prefix используется для имён маршрутов, но ветка patch его не добавляет: имя получается name.patch. Не полагайтесь на одинаковое именование всех resource actions с prefix без проверки.
Child(path, callback = null) имеет иной контракт, чем group: параметр path в реализации не применяется, а callback вызывается без проверки на null. Используйте group для префикса; отсутствие обязательности callback в сигнатуре child не делает вызов без callback рабочим.
RouteObject
Заголовок раздела «RouteObject»Методы getName/name, getPath, getMethods, getCallback, middleware/getMiddleware, param/setParams и url. Name дополнительно обновляет глобальный реестр имён; повторное имя заменяет ссылку в реестре. SetParams объединяет значения, param без имени возвращает всю карту.
Url подставляет именованные значения, затем допускает числовые позиционные параметры; остаток проходит http_build_query. Проверка полноты, соответствия regex и escaping path segments не выполняется.
Формат dispatch
Заголовок раздела «Формат dispatch»FOUND: [Dispatcher::FOUND, callback, parameters, routeObject].
METHOD_NOT_ALLOWED: [Dispatcher::METHOD_NOT_ALLOWED, allowedMethods].
NOT_FOUND: [Dispatcher::NOT_FOUND].
Проверяйте первый элемент до чтения остальных. Список parameters ассоциативный, значения сегментов — строки. Query string не является частью route pattern: передавайте путь, который подготовил HTTP-слой.
Управление маршрутизацией по умолчанию
Заголовок раздела «Управление маршрутизацией по умолчанию»DisableDefaultRoute(plugin = ”, app = null) отключает default routing выбранной области. IsDefaultRouteDisabled проверяет область, класс или controller/action и учитывает атрибут DisableDefaultRoute.
Внутри disableDefaultRoute есть ветка для массива controller/action, но аргумент объявлен ?string: массив будет отклонён PHP до этой ветки. Для конкретного action используйте поддерживаемую аннотацию либо явную проверку прав в маршруте; не показывайте недостижимую ветку как работающий API.
Fallback и внутренние объекты
Заголовок раздела «Fallback и внутренние объекты»Fallback(callback, plugin = ”) возвращает RouteObject. GetFallback(plugin, status = 404) собирает callback Engine-HTTP и кеширует его по plugin; status не входит в ключ кеша. Разные вызовы для одного plugin не гарантируют отдельную цепочку на каждый status.
Instance, routeParser, dataGenerator, data и routes предоставляют доступ к текущему реестру. Стандартные реализации — parser Std и GroupCountBased generator/dispatcher. Их наличие не означает публичный API сброса или безопасное конкурентное изменение таблицы во время запросов.