phpsoftbox / router
Router component for the PhpSoftBox framework
Installs: 5
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/phpsoftbox/router
Requires
- php: ^8.4
- psr/container: ^2.0
- psr/http-message: ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/simple-cache: ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.93
- phpsoftbox/cli-app: dev-master
- phpsoftbox/cs-fixer: ^1.0.1
- phpsoftbox/http-message: dev-master
- phpunit/phpunit: ^11.2
This package is auto-updated.
Last update: 2026-02-06 10:49:19 UTC
README
Лёгкий роутер PhpSoftBox позволяет регистрировать маршруты, группировать их, навешивать middleware, валидировать параметры и генерировать URL по имени маршрута.
Состав пакета:
PhpSoftBox\Router\RouteCollector— регистрация маршрутов, групп, ресурсных маршрутов, глобальных middleware.PhpSoftBox\Router\RouteResolver— поиск подходящего маршрута по PSR-7 запросу.PhpSoftBox\Router\Dispatcher— исполнение обработчика маршрута с учётом middleware.PhpSoftBox\Router\Router— фасад (PSR-15 RequestHandler), объединяющий resolver+dispatcher и предоставляющийurlFor().PhpSoftBox\Router\Handler\ContainerHandlerResolver— резолвер обработчиков через DI-контейнер (PSR-11).PhpSoftBox\Router\ParamTypesEnum— встроенные валидаторы параметров маршрута.
Мы используем собственные реализации PSR-7/PSR-17 (PhpSoftBox\Http\Message\*).
Быстрый старт
use PhpSoftBox\Http\Message\Response; use PhpSoftBox\Http\Message\ServerRequest; use PhpSoftBox\Http\Message\Uri; use PhpSoftBox\Router\{RouteCollector, RouteResolver, Dispatcher, Router}; $routes = new RouteCollector(); $routes->get('/hello', fn($r) => new Response(200, [], 'OK'), name: 'hello'); $routes->get('/users/{id}/{extra?}', [UserController::class, 'show'], name: 'user.show'); $router = new Router(new RouteResolver($routes), new Dispatcher(), $routes); // Обработка входящего запроса $request = new ServerRequest('GET', new Uri('https://example.com/hello')); $response = $router->handle($request); // 200 OK // Генерация URL по имени $url = $router->urlFor('user.show', ['id' => 42]); // "/users/42"
Регистрация маршрутов
get(post|put|delete|any)(string $path, callable|array|string $handler, array $middlewares = [], ?string $name = null, ?string $host = null)resource(string $path, string $controller, array $except = [], array $middlewares = [], array $routeMiddlewares = [], ?string $namePrefix = null)addControllerMiddleware(string $controller, array $middlewares, array $only = [], array $except = [])
В middleware можно передавать как экземпляры, так и строки (alias, группа или class‑string).
Middleware для контроллеров
$routes->addControllerMiddleware(UserController::class, ['auth']); $routes->addControllerMiddleware(UserController::class, ['admin'], only: ['store', 'update']);
Рекомендуется вешать middleware на маршруты или группы; контроллеры/экшены — для точечных случаев.
Примеры
$rc = new RouteCollector(); // Обычные маршруты $rc->get('/posts', [PostController::class, 'index']); $rc->get('/posts/{slug}', [PostController::class, 'show']); $rc->post('/posts', [PostController::class, 'store']); // Invokable-класс $rc->get('/ping', PingAction::class); // Опциональные параметры: сегмент "/{slug?}" можно опустить $rc->get('/blog/{slug?}', [BlogController::class, 'show']); // Ограничение по хосту и метод ANY $rc->any('/internal/ping', [SysController::class, 'ping'], host: 'api.example.com'); // Именованные маршруты $rc->get('/u/{id}', [UserController::class, 'show'], name: 'users.show');
Группы и middleware
use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Message\ServerRequestInterface; use PhpSoftBox\Http\Message\Response; $rc = new RouteCollector(); // Глобальный middleware $rc->addMiddleware(new class implements MiddlewareInterface { public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): \Psr\Http\Message\ResponseInterface { return $handler->handle($request); } }); // Группа с префиксом и своим набором middleware $rc->group('/api', function (RouteCollector $r) { $r->get('/users', fn($r) => new Response(200)); }, [new class implements MiddlewareInterface { public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): \Psr\Http\Message\ResponseInterface { return $handler->handle($request); } }]);
Resource (CRUD) маршруты
use PhpSoftBox\Auth\Middleware\AuthMiddleware; use PhpSoftBox\Session\CsrfMiddleware; $rc->resource( '/users', UserController::class, except: [], middlewares: [new AuthMiddleware()], routeMiddlewares: [ 'store' => [new CsrfMiddleware()], 'update' => [new CsrfMiddleware()], ], namePrefix: 'users' ); // Сгенерирует: GET /users (users.index), GET /users/{id} (users.show), POST /users (users.store), // PUT /users/{id} (users.update), DELETE /users/{id} (users.destroy)
Можно передавать строки вместо экземпляров middleware, если диспетчер умеет их резолвить:
use PhpSoftBox\Application\Middleware\KernelRouteMiddlewareResolver; use PhpSoftBox\Router\Dispatcher; $dispatcher = new Dispatcher( handlerResolver: null, middlewareResolver: new KernelRouteMiddlewareResolver($kernel->middlewareManager(), $container), );
Валидация параметров
use PhpSoftBox\Router\ParamTypesEnum as T; $rc->get('/users/{id}', [UserController::class, 'show'], validators: ['id' => T::INT]); $rc->get('/posts/{slug}', [PostController::class, 'show'], validators: [ 'slug' => fn(string $v) => preg_match('~^[a-z0-9-]+$~', $v) === 1, ]);
Поведение
- Несоответствие валидатору бросает
InvalidRouteParameterException(сообщение включает имя параметра). - Несоответствие пути/метода/хоста ведёт к отсутствию маршрута (404) или
MethodNotAllowedException(405).
Генерация URL: Router::urlFor()
$router->urlFor('users.show', ['id' => 10]); // "/u/10" $router->urlFor('user.show', ['id' => 42]); // "/users/42" $router->urlFor('user.show', ['id' => 42, 'x' => 1]); // лишние параметры игнорируются $router->urlFor('user.show', ['id' => 42, 'extra' => 'q']); // для "/users/{id}/{extra?}" => "/users/42/q"
Правила
- Обязательные плейсхолдеры
{param}должны быть предоставлены — иначеRouteNotFoundException. - Опциональные сегменты
/{param?}удаляются, если параметр не передан. - В пути нормализуются повторяющиеся слеши, завершающий слеш отбрасывается (кроме корня).
Данные маршрута в request attributes
id/slugи прочие параметры маршрута кладутся вattributes.- Дополнительно доступны
_route(имя или путь маршрута) и_route_params(все параметры).
Интеграция
Routerреализует PSR-15RequestHandlerInterfaceи работает с нашими PSR-7/17 реализациями (PhpSoftBox\Http\Message\*).- Для DI можно прокидывать
RouteCollectorвRouteResolver, затем собратьRouter:
$routes = new RouteCollector(); $resolver = new RouteResolver($routes); $router = new Router($resolver, new Dispatcher(), $routes);
Пример DI-резолвера обработчиков (PSR-11)
use PhpSoftBox\Router\Handler\ContainerHandlerResolver; use PhpSoftBox\Router\Dispatcher; $dispatcher = new Dispatcher(new ContainerHandlerResolver($container)); $router = new Router(new RouteResolver($routes), $dispatcher, $routes);
Если контейнер поддерживает call() (например PHP-DI), он будет использован для инъекций в методы.
CLI
router:list router:cache router:cache-clear
Кеш маршрутов
Кеш сохраняется через CacheInterface. В кеш попадают только обработчики
в виде Class::method или invokable‑класс, а middleware должны быть строками
(alias, группа или class‑string). Замыкания и кастомные валидаторы не поддерживаются.
use PhpSoftBox\Router\Cache\RouteCache; use PhpSoftBox\Router\RouteCollector; $collector = new RouteCollector(); $collector->get('/users/{id}', [UserController::class, 'show'], validators: ['id' => ParamTypesEnum::INT]); $cache = new RouteCache($cacheStorage); $cache->dump($collector, 'dev'); $routes = $cache->load('dev');