路由服务提供者

Testing Is Documentation

tests/Router/RouterProviderTest.php路由服务提供者 - 图1

路由主要由路由服务来接入框架,可以做一些设置。

  1. namespace Common\Infra\Provider;
  2. use Admin\App\Middleware\Auth as AdminAuth;
  3. use Admin\App\Middleware\Cors;
  4. use Leevel\Auth\Middleware\Auth;
  5. use Leevel\Debug\Middleware\Debug;
  6. use Leevel\Di\IContainer;
  7. use Leevel\Log\Middleware\Log;
  8. use Leevel\Router\RouterProvider;
  9. use Leevel\Session\Middleware\Session;
  10. use Leevel\Throttler\Middleware\Throttler;
  11. class Router extends RouterProvider
  12. {
  13. /**
  14. * 控制器相对目录.
  15. *
  16. * @var string
  17. */
  18. protected string $controllerDir = 'App\\Controller';
  19. /**
  20. * 中间件分组.
  21. *
  22. * - 分组可以很方便地批量调用组件.
  23. *
  24. * @var array
  25. */
  26. protected array $middlewareGroups = [
  27. // web 请求中间件
  28. 'web' => [
  29. 'session',
  30. ],
  31. // api 请求中间件
  32. 'api' => [
  33. // API 限流,可以通过网关来做限流更高效,如果需要去掉注释即可
  34. // 'throttler:60,60',
  35. ],
  36. // 公共请求中间件
  37. 'common' => [
  38. 'log',
  39. ],
  40. ];
  41. /**
  42. * 中间件别名.
  43. *
  44. * - HTTP 中间件提供一个方便的机制来过滤进入应用程序的 HTTP 请求
  45. * - 例外在应用执行结束后响应环节也会调用 HTTP 中间件.
  46. *
  47. * @var array
  48. */
  49. protected array $middlewareAlias = [
  50. 'auth' => Auth::class,
  51. 'cors' => Cors::class,
  52. 'admin_auth' => AdminAuth::class,
  53. 'debug' => Debug::class,
  54. 'log' => Log::class,
  55. 'session' => Session::class,
  56. 'throttler' => Throttler::class,
  57. ];
  58. /**
  59. * 基础路径.
  60. *
  61. * @var array
  62. */
  63. protected array $basePaths = [
  64. '*' => [
  65. 'middlewares' => 'common',
  66. ],
  67. 'foo/*world' => [
  68. ],
  69. 'api/test' => [
  70. 'middlewares' => 'api',
  71. ],
  72. ':admin/*' => [
  73. 'middlewares' => 'admin_auth,cors',
  74. ],
  75. 'options/index' => [
  76. 'middlewares' => 'cors',
  77. ],
  78. 'admin/show' => [
  79. 'middlewares' => 'auth',
  80. ],
  81. ];
  82. /**
  83. * 分组.
  84. *
  85. * @var array
  86. */
  87. protected array $groups = [
  88. 'pet' => [],
  89. 'store' => [],
  90. 'user' => [],
  91. '/api/v1' => [
  92. 'middlewares' => 'api',
  93. ],
  94. 'api/v2' => [
  95. 'middlewares' => 'api',
  96. ],
  97. '/web/v1' => [
  98. 'middlewares' => 'web',
  99. ],
  100. 'web/v2' => [
  101. 'middlewares' => 'web',
  102. ],
  103. ];
  104. /**
  105. * 创建一个服务容器提供者实例.
  106. */
  107. public function __construct(IContainer $container)
  108. {
  109. parent::__construct($container);
  110. if ($container->make('app')->isDebug()) {
  111. $this->middlewareGroups['common'][] = 'debug';
  112. }
  113. }
  114. /**
  115. * bootstrap.
  116. */
  117. public function bootstrap(): void
  118. {
  119. parent::bootstrap();
  120. }
  121. /**
  122. * 返回路由.
  123. */
  124. public function getRouters(): array
  125. {
  126. return parent::getRouters();
  127. }
  128. }

Uses

  1. <?php
  2. use Leevel\Di\Container;
  3. use Leevel\Kernel\App;
  4. use Leevel\Router\Router;
  5. use Leevel\Router\RouterProvider;
  6. use Leevel\Router\Url;
  7. use Tests\Router\Middlewares\Demo1;
  8. use Tests\Router\Middlewares\Demo2;
  9. use Tests\Router\Middlewares\Demo3;

基本使用

QueryPHP 路由最终结果主要由 base_pathsgroupsrouters 构成。

fixture 定义

路由服务提供者 Tests\Router\RouterProvider1

  1. namespace Tests\Router;
  2. class RouterProvider1 extends RouterProvider
  3. {
  4. protected string $controllerDir = 'Tests\\Router\\Apps';
  5. protected array $middlewareGroups = [
  6. 'group1' => [
  7. 'demo1',
  8. 'demo2',
  9. ],
  10. 'group2' => [
  11. 'demo1',
  12. 'demo3:10,world',
  13. ],
  14. 'group3' => [
  15. 'demo1',
  16. 'demo2',
  17. 'demo3:10,world',
  18. ],
  19. ];
  20. protected array $middlewareAlias = [
  21. 'demo1' => Demo1::class,
  22. 'demo2' => Demo2::class,
  23. 'demo3' => Demo3::class,
  24. ];
  25. protected array $basePaths = [];
  26. protected array $groups = [
  27. 'pet' => [],
  28. 'store' => [],
  29. 'user' => [],
  30. '/api/v1' => [
  31. 'middlewares' => 'group1',
  32. ],
  33. '/api/v2' => [
  34. 'middlewares' => 'group2',
  35. ],
  36. '/api/v3' => [
  37. 'middlewares' => 'demo1,demo3:30,world',
  38. ],
  39. '/api/v3' => [
  40. 'middlewares' => ['demo1', 'group3'],
  41. ],
  42. '/api/v4' => [
  43. 'middlewares' => 'notFound',
  44. ],
  45. ];
  46. public function bootstrap(): void
  47. {
  48. parent::bootstrap();
  49. }
  50. public function getRouters(): array
  51. {
  52. return parent::getRouters();
  53. }
  54. }

路由注解缓存结果 tests/Router/Apps/AppScanRouter/data.json

  1. {
  2. "base_paths": {
  3. "\/^\\\/api\\\/v1(\\S*)\\\/$\/": {
  4. "middlewares": {
  5. "handle": [
  6. "Tests\\Router\\Middlewares\\Demo2@handle"
  7. ],
  8. "terminate": [
  9. "Tests\\Router\\Middlewares\\Demo1@terminate",
  10. "Tests\\Router\\Middlewares\\Demo2@terminate"
  11. ]
  12. }
  13. },
  14. "\/^\\\/api\\\/v2(\\S*)\\\/$\/": {
  15. "middlewares": {
  16. "handle": [
  17. "Tests\\Router\\Middlewares\\Demo3@handle:10,world"
  18. ],
  19. "terminate": [
  20. "Tests\\Router\\Middlewares\\Demo1@terminate"
  21. ]
  22. }
  23. },
  24. "\/^\\\/api\\\/v3(\\S*)\\\/$\/": {
  25. "middlewares": {
  26. "handle": [
  27. "Tests\\Router\\Middlewares\\Demo2@handle",
  28. "Tests\\Router\\Middlewares\\Demo3@handle:10,world"
  29. ],
  30. "terminate": [
  31. "Tests\\Router\\Middlewares\\Demo1@terminate",
  32. "Tests\\Router\\Middlewares\\Demo2@terminate"
  33. ]
  34. }
  35. }
  36. },
  37. "groups": [
  38. "\/pet",
  39. "\/store",
  40. "\/user",
  41. "\/api\/v1",
  42. "\/api\/v2",
  43. "\/api\/v3",
  44. "\/api\/v4"
  45. ],
  46. "routers": {
  47. "get": {
  48. "a": {
  49. "\/api\/v1": {
  50. "\/api\/v1\/petLeevel\/{petId:[A-Za-z]+}\/": {
  51. "bind": "\\Tests\\Router\\Apps\\AppScanRouter\\Controllers\\Pet@petLeevel",
  52. "var": [
  53. "petId"
  54. ]
  55. },
  56. "regex": [
  57. "~^(?|\/api\/v1\/petLeevel\/([A-Za-z]+)\/)$~x"
  58. ],
  59. "map": [
  60. {
  61. "2": "\/api\/v1\/petLeevel\/{petId:[A-Za-z]+}\/"
  62. }
  63. ]
  64. }
  65. },
  66. "static": {
  67. "\/web\/petLeevelWithPort\/": {
  68. "port": 9527,
  69. "bind": "\\Tests\\Router\\Apps\\AppScanRouter\\Controllers\\Pet@petLeevelWithPort"
  70. }
  71. }
  72. }
  73. }
  74. }
  1. public function testBaseUse(): void
  2. {
  3. $container = Container::singletons();
  4. $app = new App($container, '');
  5. $app->setAppPath(__DIR__.'/Apps/AppScanRouter');
  6. $app->setPath(__DIR__.'/Apps/AppScanRouter');
  7. $app->setRouterCachedPath(__DIR__.'/router_cached.php');
  8. $container->instance('app', $app);
  9. $container->instance('router', $router = $this->createRouter($container));
  10. $provider = new RouterProvider1($container);
  11. $this->assertNull($provider->register());
  12. $this->assertNull($provider->bootstrap());
  13. $data = file_get_contents(__DIR__.'/Apps/AppScanRouter/data.json');
  14. $this->assertSame(
  15. $data,
  16. $this->varJson(
  17. [
  18. 'base_paths' => $router->getBasePaths(),
  19. 'groups' => $router->getGroups(),
  20. 'routers' => $router->getRouters(),
  21. ]
  22. )
  23. );
  24. Container::singletons()->clear();
  25. }