Быстрый старт

Начните работу с Waypoint за 5 минут.

Содержание

Установка

Установите Waypoint через Composer:

composer require ascetic-soft/waypoint

Требования:

  • PHP >= 8.4
  • ext-mbstring

Опциональные PSR-пакеты

Ядро работает на чистом PHP. Для PSR-15 обработки запросов (middleware, DI, Router::handle()) установите PSR-пакеты:

composer require psr/http-message psr/http-server-handler psr/http-server-middleware psr/container

Быстрый старт

Waypoint разделяет регистрацию маршрутов (RouteRegistrar) и диспетчеризацию запросов (Router).

Шаг 1: Зарегистрируйте маршруты

use AsceticSoft\Waypoint\RouteRegistrar;

$registrar = new RouteRegistrar();

$registrar->get('/hello/{name}', function (string $name) use ($responseFactory) {
    $response = $responseFactory->createResponse();
    $response->getBody()->write("Hello, {$name}!");
    return $response;
});

Шаг 2: Создайте роутер

use AsceticSoft\Waypoint\Router;

$router = new Router($container, $registrar->getRouteCollection());

Шаг 3: Обработайте запрос

use Nyholm\Psr7\ServerRequest;

$request  = new ServerRequest('GET', '/hello/world');
$response = $router->handle($request);

Waypoint автоматически извлекает {name} из URL и внедряет его в обработчик. Ручной разбор не нужен.


Использование контроллеров

Для реальных приложений используйте классы контроллеров вместо замыканий:

$registrar = new RouteRegistrar();

$registrar->get('/users',             [UserController::class, 'list']);
$registrar->post('/users',            [UserController::class, 'create']);
$registrar->get('/users/{id:\d+}',    [UserController::class, 'show']);
$registrar->put('/users/{id:\d+}',    [UserController::class, 'update']);
$registrar->delete('/users/{id:\d+}', [UserController::class, 'destroy']);

Методы контроллера получают параметры маршрута автоматически с приведением типов:

class UserController
{
    public function show(int $id, UserRepository $repo): ResponseInterface
    {
        // $id автоматически приведён к int
        // $repo разрешён из PSR-11 контейнера
        $user = $repo->find($id);
        // ...
    }
}

Параметры маршрута сопоставляются по имени и автоматически приводятся к типу, объявленному в сигнатуре метода (int, float, bool). Сервисы контейнера разрешаются по type-hint.


Использование атрибутов

Вместо ручной регистрации объявляйте маршруты прямо на контроллерах:

use AsceticSoft\Waypoint\Attribute\Route;

#[Route('/api/users', middleware: [AuthMiddleware::class])]
class UserController
{
    #[Route('/', methods: ['GET'], name: 'users.list')]
    public function list(): ResponseInterface { /* ... */ }

    #[Route('/{id:\d+}', methods: ['GET'], name: 'users.show')]
    public function show(int $id): ResponseInterface { /* ... */ }

    #[Route('/', methods: ['POST'], name: 'users.create')]
    public function create(ServerRequestInterface $request): ResponseInterface { /* ... */ }
}

Затем загрузите их:

$registrar = new RouteRegistrar();

// Загрузить конкретные классы
$registrar->loadAttributes(UserController::class, PostController::class);

// Или просканировать директорию
$registrar->scanDirectory(__DIR__ . '/Controllers', 'App\\Controllers');

// С фильтрацией по имени файла
$registrar->scanDirectory(__DIR__ . '/Controllers', 'App\\Controllers', '*Controller.php');

Полный пример запуска

<?php
// bootstrap.php

use AsceticSoft\Waypoint\Cache\RouteCompiler;
use AsceticSoft\Waypoint\RouteRegistrar;
use AsceticSoft\Waypoint\Router;
use AsceticSoft\Waypoint\Exception\RouteNotFoundException;
use AsceticSoft\Waypoint\Exception\MethodNotAllowedException;

require_once __DIR__ . '/vendor/autoload.php';

$cacheFile = __DIR__ . '/cache/routes.php';
$compiler  = new RouteCompiler();

// В продакшене: загрузка из кэша; иначе регистрация и компиляция
if ($compiler->isFresh($cacheFile)) {
    $router = new Router($container);
    $router->loadCache($cacheFile);
} else {
    $registrar = new RouteRegistrar();
    $registrar->scanDirectory(__DIR__ . '/Controllers', 'App\\Controllers');

    // Компиляция для следующего запроса
    $compiler->compile($registrar->getRouteCollection(), $cacheFile);

    $router = new Router($container, $registrar->getRouteCollection());
}

// Глобальные middleware
$router->addMiddleware(CorsMiddleware::class);

// Обработка запроса
try {
    $response = $router->handle($request);
} catch (RouteNotFoundException $e) {
    // 404 Not Found
} catch (MethodNotAllowedException $e) {
    // 405 Method Not Allowed
    $allowed = $e->getAllowedMethods();
}

Что дальше?

  • Маршрутизация — Регистрация маршрутов, параметры, группы и атрибуты
  • Middleware — Глобальные и маршрутные PSR-15 middleware
  • Продвинутое — Внедрение зависимостей, генерация URL, кэширование и диагностика
  • Внутреннее устройство — Алгоритмы, структуры данных и диаграммы архитектуры
  • Справочник API — Полный справочник по всем публичным классам и методам