yiisoft / router
Yii 路由器
Requires
- php: ^8.0
- psr/event-dispatcher: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0|^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- yiisoft/http: ^1.2
- yiisoft/middleware-dispatcher: ^5.0
- yiisoft/router-implementation: 1.0.0
Requires (Dev)
- maglnet/composer-require-checker: ^4.4
- nyholm/psr7: ^1.5
- phpunit/phpunit: ^9.5
- psr/container: ^1.1|^2.0
- rector/rector: ^1.0
- roave/infection-static-analysis-plugin: ^1.18
- spatie/phpunit-watcher: ^1.23
- vimeo/psalm: ^4.30|^5.22
- yiisoft/di: ^1.0
- yiisoft/dummy-provider: ^1.0.0
- yiisoft/hydrator: ^1.0
- yiisoft/test-support: ^3.0
Suggests
- yiisoft/hydrator: Needed to use `RouteArgument` attribute
- yiisoft/router-fastroute: Router implementation based on nikic/FastRoute
This package is auto-updated.
Last update: 2024-09-22 10:24:14 UTC
README
Yii Router
该包提供了兼容PSR-7的请求路由和准备在应用程序中使用PSR-15中间件。该包不是从头开始实现路由,而是提供了一个配置路由的接口,并可以与适配器包一起使用。目前,唯一的适配器是FastRoute。
功能
- 支持HTTP方法、主机和默认值的URL匹配和生成。
- 良好的IDE支持,用于定义路由。
- 支持无限嵌套的路由分组。
- 支持为单个路由和分组提供中间件。
- 准备用于路由匹配的中间件。
- 方便的
CurrentRoute
服务,用于保存有关最后匹配路由的信息。 - 开箱即用的CORS中间件支持。
需求
- PHP 8.0或更高版本。
安装
可以使用Composer安装此包。
composer require yiisoft/router
此外,您还需要一个适配器,例如FastRoute。
定义路由和URL匹配
路由器的常见用法如下
use Yiisoft\Router\CurrentRoute; use Yiisoft\Router\Group; use Yiisoft\Router\Route; use Yiisoft\Router\RouteCollection; use Yiisoft\Router\RouteCollectorInterface; use Yiisoft\Router\UrlMatcherInterface; use Yiisoft\Router\Fastroute\UrlMatcher; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; // Define routes $routes = [ Route::get('/') ->action(static function (ServerRequestInterface $request, RequestHandlerInterface $next) use ($responseFactory) { $response = $responseFactory->createResponse(); $response ->getBody() ->write('You are at homepage.'); return $response; }), Route::get('/test/{id:\w+}') ->action(static function (CurrentRoute $currentRoute, RequestHandlerInterface $next) use ($responseFactory) { $id = $currentRoute->getArgument('id'); $response = $responseFactory->createResponse(); $response ->getBody() ->write('You are at test with argument ' . $id); return $response; }) ]; // Add routes defined to route collector $collector = $container->get(RouteCollectorInterface::class); $collector->addGroup(Group::create(null)->routes($routes)); // Initialize URL matcher /** @var UrlMatcherInterface $urlMatcher */ $urlMatcher = new UrlMatcher(new RouteCollection($collector)); // Do the match against $request which is PSR-7 ServerRequestInterface. $result = $urlMatcher->match($request); if (!$result->isSuccess()) { // 404 } // $result->arguments() contains arguments from the match. // Run middleware assigned to a route found. $response = $result->process($request, $notFoundHandler);
注意:尽管
UrlGeneratorInterface
和UrlMatcherInterface
对所有可用的适配器都是通用的,但某些功能和,尤其是模式语法可能会有所不同。有关使用和配置详细信息,请参阅特定适配器文档。本文件中的所有示例均为FastRoute适配器。
中间件使用
为了简化基于PSR中间件的应用程序的使用,提供了现成的中间件
$router = $container->get(Yiisoft\Router\UrlMatcherInterface::class); $responseFactory = $container->get(\Psr\Http\Message\ResponseFactoryInterface::class); $routerMiddleware = new Yiisoft\Router\Middleware\Router($router, $responseFactory, $container); // Add middleware to your middleware handler of choice.
在路由匹配的情况下,如果匹配,则路由器中间件执行附加到路由的处理器中间件。如果没有匹配,则下一个应用程序中间件处理请求。
路由
路由可以匹配一个或多个HTTP方法:GET
、POST
、PUT
、DELETE
、PATCH
、HEAD
、OPTIONS
。为创建特定方法的路由提供了相应的静态方法。如果要一次处理多个方法,可以使用methods()
。
use Yiisoft\Router\Route; Route::delete('/post/{id}') ->name('post-delete') ->action([PostController::class, 'actionDelete']); Route::methods([Method::GET, Method::POST], '/page/add') ->name('page-add') ->action([PageController::class, 'actionAdd']);
如果您要根据路由及其参数生成URL,请使用name()
给它命名。有关详细信息,请参阅“创建URL”。
在上面的示例中,action()
是主要的中间件定义,当调用匹配结果的process()
方法时最后被调用。中间件的执行方式和接受的中间件格式由使用的中间件调度器定义。有关中间件示例,请参阅yiisoft/middleware-dispatcher的readme。
如果路由仅应用于特定的主机,可以定义如下
use Yiisoft\Router\Route; Route::get('/special') ->name('special') ->action(SpecialAction::class) ->host('https://yiiframework.cn');
可以通过defaults()
方法提供参数的默认值
use Yiisoft\Router\Route; Route::get('/api[/v{version}]') ->name('api-index') ->action(ApiAction::class) ->defaults(['version' => 1]);
在上面的示例中,我们指定如果匹配过程中没有从URL中获取到“version”,则它将是1
。
除了操作外,还可以定义在操作之前执行的其他中间件
use Yiisoft\Router\Route; Route::methods([Method::GET, Method::POST], '/page/add') ->middleware(Authentication::class) ->middleware(ExtraHeaders::class) ->action([PostController::class, 'add']) ->name('blog/add');
这通常用于可以用于多个路由的特定操作,例如身份验证。
如果需要先执行中间件或从路由中移除现有中间件,可以使用 prependMiddleware()
和 disableMiddleware()
。
如果您想将来自多个来源的路由组合起来,并希望最后一个路由优先于现有的路由,请将其标记为“覆盖”。
use Yiisoft\Router\Route; Route::get('/special') ->name('special') ->action(SpecialAction::class) ->override();
路由分组
路由可以进行分组。这对于API端点等情况非常有用。
use \Yiisoft\Router\Route; use \Yiisoft\Router\Group; use \Yiisoft\Router\RouteCollectorInterface; // for obtaining router see adapter package of choice readme $collector = $container->get(RouteCollectorInterface::class); $collector->addGroup( Group::create('/api') ->middleware(ApiAuthentication::class) ->host('https://example.com') ->routes([ Route::get('/comments'), Group::create('/posts')->routes([ Route::get('/list'), ]), ]) );
组可以有一个前缀,例如上面的 /api
。该前缀应用于每个组的路由,无论是匹配还是生成URL时。
类似于单个路由,组也可以使用 middleware()
、prependMiddleware()
和 disableMiddleware()
管理一组中间件。这些中间件在匹配路由的自身中间件和操作之前执行。
如果指定了主机,组中的所有路由只有当主机匹配时才会匹配。
自动的OPTIONS响应和CORS
默认情况下,根据定义的路由自动响应该的OPTIONS请求。
HTTP/1.1 204 No Content
Allow: GET, HEAD
这通常没问题,除非您需要CORS头信息。在这种情况下,您可以添加一个处理它的中间件,例如 tuupola/cors-middleware。
use Yiisoft\Router\Group; use \Tuupola\Middleware\CorsMiddleware; return [ Group::create('/api') ->withCors(CorsMiddleware::class) ->routes([ // ... ] ); ];
创建URL
可以使用 UrlGeneratorInterface::generate()
创建URL。假设一个路由定义如下
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Message\ResponseFactoryInterface; use Yiisoft\Yii\Http\Handler\NotFoundHandler; use Yiisoft\Yii\Runner\Http\SapiEmitter; use Yiisoft\Yii\Runner\Http\ServerRequestFactory; use Yiisoft\Router\CurrentRoute; use Yiisoft\Router\Route; use Yiisoft\Router\RouteCollection; use Yiisoft\Router\RouteCollectorInterface; use Yiisoft\Router\Fastroute\UrlMatcher; $request = $container ->get(ServerRequestFactory::class) ->createFromGlobals(); $responseFactory = $container->get(ResponseFactoryInterface::class); $notFoundHandler = new NotFoundHandler($responseFactory); $collector = $container->get(RouteCollectorInterface::class); $collector->addRoute( Route::get('/test/{id:\w+}') ->action(static function (CurrentRoute $currentRoute, RequestHandlerInterface $next) use ($responseFactory) { $id = $currentRoute->getArgument('id'); $response = $responseFactory->createResponse(); $response ->getBody() ->write('You are at test with argument ' . $id); return $response; }) ->name('test') ); $router = new UrlMatcher(new RouteCollection($collector)); $route = $router->match($request); $response = $route->process($request, $notFoundHandler); $emitter = new SapiEmitter(); $emitter->emit($response, $request->getMethod() === Method::HEAD);
然后可以这样获取该URL
use Yiisoft\Router\UrlGeneratorInterface; function getUrl(UrlGeneratorInterface $urlGenerator, $parameters = []) { return $urlGenerator->generate('test', $parameters); }
可以使用 UrlGeneratorInterface::generateAbsolute()
生成绝对URL
use Yiisoft\Router\UrlGeneratorInterface; function getUrl(UrlGeneratorInterface $urlGenerator, $parameters = []) { return $urlGenerator->generateAbsolute('test', $parameters); }
此外,还有一个方便的 UrlGeneratorInterface::generateFromCurrent()
方法。它允许生成一个当前URL的修改版本。
use Yiisoft\Router\UrlGeneratorInterface; function getUrl(UrlGeneratorInterface $urlGenerator, $id) { return $urlGenerator->generateFromCurrent(['id' => 42]); }
在上面的例子中,ID将被替换为42,其余参数保持不变。这对于修改用于过滤和/或排序的URL非常有用。
获取当前路由信息
对于此类路由
use \Yiisoft\Router\Route; $routes = [ Route::post('/post/{id:\d+}') ->action([PostController::class, 'actionEdit']), ];
可以通过以下方式获取信息
use Psr\Http\Message\ResponseInterface use Psr\Http\Message\UriInterface; use Yiisoft\Router\CurrentRoute; use Yiisoft\Router\Route; final class PostController { public function actionEdit(CurrentRoute $currentRoute): ResponseInterface { $postId = $currentRoute->getArgument('id'); if ($postId === null) { throw new \InvalidArgumentException('Post ID is not specified.'); } // ... } }
除了常用的 getArgument()
方法外,还有以下方法可用
getArguments()
- 一次性获取所有参数。getName()
- 获取路由名称。getHost()
- 获取路由主机。getPattern()
- 获取路由模式。getMethods()
- 获取路由方法。getUri()
- 获取当前URI。
文档
如果您需要帮助或有问题,Yii 论坛 是一个好地方。您还可以查看其他 Yii 社区资源。
许可
Yii路由器是免费软件。它根据BSD许可协议发布。有关更多信息,请参阅LICENSE
。
由 Yii软件 维护。