一、说明
-
首先说明的是,本文使用到了最新版本的 Lumen 7.*,为了便于新手理解,尽可能保留了 Lumen 框架的原有结构
-
接着介绍一下重点的代码目录
./ ./app ./app/Base # 基础类 ./app/Helpers # 辅助函数 ./app/Middwares # 辅助函数 ./app/Helpers/function.php # 常用辅助函数 ./app/Helpers/regular.php # 正则辅助函数 ./app/Structs # 结构体类 ./app/V1 # v1版本接口目录 ./app/V1/codes.php # v1版本状态码 ./app/V2 # v2版本接口目录 ............others............ ./bootstrap/app.php # 初始化入口文件 ./config/codes.php # 系统状态码配置文件 ./config/switcher.php # 接口降级开关配置文件 ./routes/v1/*.php # v1版本路由 ............others............
时间紧张的缘故,依旧并没有在代码中添加完整注释,所以需要读者按照本文提供的思路,慢慢理解。
二、开始
-
让我们从框架一个请求的处理过程来梳理(简化)
request -> router -> middware -> controller -> response
router
非常容易理解,我们跳过后,直接将目光移到
middleware
,在 './app/Middwares ' 目录下建立了以下3个
middleware
类
<?php
# 在 Form 中间件,会针对表单类型的请求,做一些前置验证
class Form
{
public function handle($request, Closure $next, $f)
{
$class = app($f);
if ($class instanceof BaseForm) {
$class->handle($request);
} else {
server_exception('05511');
}
return $next($request);
}
}
# 在 Logger 中间件,会 fire 一个 RouteEvent 记录一些请求的日志
class Logger
{
public function handle($request, Closure $next)
{
event(new RouteEvent($request->route()));
return $next($request);
}
}
# 在 Switcher 中间件,会判断当前接口是否已经降级下线
class Switcher
{
public function handle($request, Closure $next)
{
$router = $request->route();
if (config('switcher.' . $router[1]['uses']) === 'off') {
server_exception('00500');
}
return $next($request);
}
}
当然不能忘了,所有
middleware
类都要在入口文件中 显式定义
<?php
# 读者可以思考一下,这里为什么没有使用 $app->middleware() 方法
$app->routeMiddleware([
'form' => App\Middleware\Form::class,
'logger' => App\Middleware\Logger::class,
'switcher' => App\Middleware\Switcher::class,
]);
-
第一小节说完了
middleware
,继续到达下一层
controller
。本文的 代码 结构已经移除了 './app/Controllers ' 这个默认目录,就直接看到 './app/V1/Controllers ' 目录,在下已经提前创建了1个简单示例
controller
类
middleware('form:App\\V1\\Form\\UserStoreForm', ['only' => ['store']]); } public function index() { $users[] = [ 'name' => 'AdamTyn', 'email' => 'tynadam@foxmail.com', 'mobile' => '1888888888', ]; # 调用资源类的 collection() 方法简单生成资源集合类 success(UserResource::collection($users)); } public function show() { $user = [ 'name' => 'AdamTyn', 'email' => 'tynadam@foxmail.com', 'mobile' => '1888888888', ]; # 使用资源类,针对数据做一些后置处理 success(new UserResource($user)); } public function store(Request $request) { // do somethings success($request->all()); } }
由于之前的 Lumen业务篇:接口开发之自定义表单验证 一文已经对 表单验证类 做过介绍,故此不做赘述。不难看出,本文在之前教程的基础上,增加了
resource
类的使用
原因很好理解,接口开发往往都会涉及多个 RPC 相互调用,Laravel/Lumen 给开发者提供了一种优雅的方式 聚合不同 services 的接口数据,也即上述提到的
resource
类
<?php
class UserResource extends BaseResource
{
const RESOURCE_NAME = 'UserResource';
public function toArray($request)
{
$append = [
'caller' => 'UserResource'
];
$data = parent::toArray($request);
return $append + $data;
}
}
-
上一节介绍了
controller
,细腻的读者会发现在
controller
直接调用了
success()
方法完成了response
的输出。通过 './app/Helpers/function.php ' 文件可以查看到以下具体实现
withCode($code)->withMessage($message)->withData($data); print_r($res->toJson()); die; } } if (!function_exists('output_with_meta')) { function output_with_meta(string $code, string $message = '', $data = null, array $meta = []) { $res = new App\Structs\Base; $res->withCode($code)->withMessage($message)->withData($data)->withMeta($meta); print_r($res->toJson()); die; } } # success 方法只是固定了 00200 状态码,实际上还是 output 和 output_with_meta if (!function_exists('success')) { function success($data = null, array $meta = []) { $code = '00200'; count($meta) > 0 ? output_with_meta($code, '', $data, $meta) : output($code, '', $data); } }
《难道一直都是 success()
输出吗?不能 errors()
吗?》
当然可以有 errors()
,但是 output()
以及 output_with_meta
方法可以提供更细致输出,读者完全可以自己再增加一个 errors()
,又有何不可呢?
-
当大家看到这里的时候,就要开始介绍本文的核心目录 './app/Structs ',该目录下定义了4个 结构体类,为了缩减篇幅,简略的展示部分代码内容
done) { $this->result = [ 'scroll' => $this->resource->hasMorePages(), # 移动端瀑布流是否可以加载更多(bool) 'pagination' => [ 'total' => $this->resource->total(), # 总数量(int) 'count' => $this->resource->count(), # 当前数量(int) 'per_page' => $this->resource->perPage(), # 单页最大数量(int) 'current_page' => $this->resource->currentPage(), # 当前页号(int) 'last_page' => $this->resource->lastPage() # 最后页号(int) ], 'list' => $this->resource->items() # 单页数据集(array) ]; $this->done(); } return $this->result; } }
结构体思想得益于在下对 OOP 越发深入的认知,其实读者也可以这样理解:
《什么才是标准化的输出?》
,应该就是 拥有固定结构 的输出。
-
至此,相信读者已经跟着在下的思路,对本教程的 代码 有了具象的了解。更为优雅的细节将会留给你们自己去发现。文章最后再将 './config' 目录下的 配置文件 做简单展示
'成功', '00500' => '已下线', '05500' => 'Event类必须定义EVENT_NAME常量', '05510' => 'Form类必须定义FORM_NAME常量', '05511' => '不存在的Form类', '05520' => 'Listener类必须定义LISTENER_NAME常量', '05530' => 'Resource类必须定义RESOURCE_NAME常量', ]; $v1 = app_path('V1/codes.php'); $v1 = include_once $v1; return ($system + $v1); # ./config/switcher.php return [ 'App\\V1\\Controllers\\UserController@index' => 'on', 'App\\V1\\Controllers\\UserController@store' => 'on', 'App\\V1\\Controllers\\UserController@show' => 'off', # off表示下线该接口 ];
作者:AdamTyn
链接:www.jianshu.com/p/26e3e1ee6…
来源:简书