路由 & 控制器

路由文件默认在 usr/routes.php,你也可以根据自己的情况修改配置文件,指定路由文件路径。

控制器文件默认在 usr/Controller文件夹内。

路由配置

支持的(请求)方法:

  1. $route->map($method, $path, $handler); // method 可以是数组 ['GET', 'POST`]
  2. $route->get($path, $handler);
  3. $route->get($path, $handler);
  4. $route->post($path, $handler);
  5. $route->put($path, $handler);
  6. $route->patch($path, $handler);
  7. $route->delete($path, $handler);
  8. $route->head($path, $handler);
  9. $route->options($path, $handler);
  10. $route->any($path, $handler); // GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

?> 路由配置修改后需要重启(restart)或者重新加载(reload)服务。

路由处理器可以是一个匿名函数

  1. $route->get('/hello/{name}', function (\Cabal\Core\Http\Server $server, \Psr\Http\Message\ServerRequestInterface $request, $vars = []) {
  2. return "hello " . $vars['name'];
  3. });

http://localhost:9501/hello/cabal

也可以是一个函数

  1. function hello (\Cabal\Core\Http\Server $server, \Psr\Http\Message\ServerRequestInterface $request, $vars = []) {
  2. return "hello " . $vars['name'];
  3. }
  4. $route->get('/hello/{name}', 'hello');

也可以是一个类中的方法,可以是动态方法也可以是静态方法

文件 usr/Controller/HelloController.php 内容如下:

  1. namespace Controller;
  2. use Psr\Http\Message\ServerRequestInterface;
  3. use Cabal\Core\Http\Server;
  4. class HelloController
  5. {
  6. function getWorld(Server $server, ServerRequestInterface $request, $vars = [])
  7. {
  8. return "hello " . $vars['name'];
  9. }
  10. static public function staticWorld(Server $server, ServerRequestInterface $request, $vars = [])
  11. {
  12. return "hello " . $vars['id'];
  13. }
  14. }

增加路由配置:

  1. $route->get('/hello2[/{name}]', 'Controller\\HelloController@getWorld');
  2. $route->get('/hello3/{id:\d+}', 'Controller\\HelloController::staticWorld');

?> 路径规则支持正则等配置,具体可以查看 fastRoute文档

路由组

  1. $route->group([
  2. 'namespace' => 'Controller',
  3. 'basePath' => '/group',
  4. ], function ($route) {
  5. $route->get('/hello2[/{name}]', 'HelloController@getWorld');
  6. $route->get('/hello3/{id:\d+}', 'HelloController::staticWorld');
  7. });

或者

  1. $route->group([
  2. 'basePath' => '/group',
  3. ], function ($route) {
  4. $route->get('/hello2[/{name}]', 'HelloController@getWorld');
  5. $route->get('/hello3/{id:\d+}', 'HelloController::staticWorld');
  6. })->namespace('Controller');

中间件

中间件和其他框架的中间件类似,不做太多描述,下面是简单的应用,多个中间件的情况可以自己实现后看下效果。

  • $middlewareArgs 为使用中间件时传入的参数.
  • $next($server, $request, $vars); 为下一个中间件或者控制器,要中断请不要调用它。
  1. // 在 routes.php 文件内 定义中间件
  2. $dispatcher->addMiddleware('before', function (\Cabal\Core\Http\Server $server, \Psr\Http\Message\ServerRequestInterface $request, $vars, $next, $middlewareArgs = []) {
  3. // code..
  4. return "before " . $middlewareArgs['name']; // 直接返回,不执行控制器代码,会继续执行其他中间件
  5. });
  6. $dispatcher->addMiddleware('after', function (\Cabal\Core\Http\Server $server, \Psr\Http\Message\ServerRequestInterface $request, $vars, $next, $middlewareArgs = []) {
  7. $response = $next($server, $request, $vars); // 先调用控制器
  8. // code..
  9. return "after: " . $response; // 返回,如果还有其他中间件会继续执行其他中间件
  10. });
  11. // 使用中间件
  12. $route->group([
  13. 'basePath' => '/group',
  14. 'namespace' => 'Controller',
  15. ], function ($route) {
  16. $route->get('/hello2[/{name}]', 'HelloController@getWorld');
  17. $route->get('/hello3/{id:\d+}', 'HelloController::staticWorld');
  18. })->middleware(['after']);
  19. $route->get('/hello2[/{name}]', 'Controller\\HelloController@getWorld')
  20. ->middleware(['before' => ['name' => 'middleware']]);
  21. $route->get('/hello3/{id:\d+}', 'Controller\\HelloController::staticWorld')
  22. ->middleware(['before' => ['name' => 'middleware']]);

域名&协议

路由支持按协议或者域名过滤请求。

  1. $route->group([
  2. 'basePath' => '/group',
  3. ], function ($route) {
  4. $route->get('/hello2[/{name}]', 'HelloController@getWorld');
  5. $route->get('/hello3/{id:\d+}', 'HelloController::staticWorld');
  6. })->host('www.qq.com')
  7. ->scheme('https');
  8. $route->get('/hello3/{id:\d+}', 'HelloController::staticWorld')
  9. ->host('www.qq.com')
  10. ->scheme('https');

过滤控制器/API控制器

控制器继承 Cabal\Core\Base\FilterController 并实现 rules 方法,返回对应方法的规则即可自动约束请求参数。

!> 校验只会校验请求参数,路由匹配出来的参数($vars)不参与校验!

我们使用的校验类为:vlucas/valitron,支持的配置项和语法请参考该项目文档。

  1. <?php
  2. namespace App\Controller;
  3. use Cabal\Core\Http\Request;
  4. use Cabal\Core\Base\FilterController;
  5. class UserController extends FilterController
  6. {
  7. public function rules()
  8. {
  9. return [
  10. 'get' => [
  11. 'id' => ['required', 'integer'],
  12. 'email' => ['required', 'email', ['lengthMin', 4]],
  13. ],
  14. ];
  15. }
  16. public function get(\Server $server, Request $request, $vars = [])
  17. {
  18. return [
  19. 'action' => __METHOD__,
  20. 'input' => $request->all(),
  21. 'vars' => $vars,
  22. ];
  23. }
  24. }

请求参数没通过校验系统会抛出一个Cabal\Core\Exception\BadRequestException异常,你可以在routes.php中自定义异常处理来决定你的请求响应。

  1. use Cabal\Core\Exception\BadRequestException;
  2. $dispatcher->registerExceptionHandler(function ($server, $ex, $chain, $request) {
  3. if ($ex instanceof BadRequestException) {
  4. return [
  5. 'code' => 1,
  6. 'msg' => $ex->getMessage(),
  7. 'msgs' => $ex->getMessages(),
  8. ];
  9. }
  10. return [
  11. 'code' => -1,
  12. 'msg' => 'Internal Server Error',
  13. ];
  14. });

代码提示

为了让 routes.php 有代码提示 请保留下面注释:

  1. /**
  2. * @var \Cabal\Core\Dispatcher $dispatcher
  3. */
  4. /**
  5. * @var \Cabal\Route\RouteCollection $route
  6. */