架构图
1、Request log 请求报文日志,这里加请求报文的原因是,很多情况下的BUG是低频难复现的。原请求报文能很好的排查问题。这一层也可以放在中间件(Middleware)来处理 参考示例:
input();
$Uri = $request->getRequestUri();
$UriArray = explode('?',$Uri);
$UriArray = explode('/',$UriArray[0]);
$this->dataRecodes('请求报文', $params, $UriArray[3]);
return $next($request);
}
}
class Helper
{
/**
* @Notes: 记录接口日志信息
* @Author: Dong Xiannan
* @Date: 2021/8/5 3:50 下午
* @Description: 描述
* @param $title
* @param $data
* @param string $file
*/
public static function dataRecodes($title, $data, $file = 'log')
{
$date = date("Ymd");
if (!is_dir(storage_path('logs/' . $date))) {
mkdir(storage_path('logs/' . $date), 0777, TRUE);
}
$content = "================" . $title . ' ' . date('Y-m-d H:i:s') . "===================\n";
file_put_contents(storage_path('logs/' . $date . '/' . $file . '.log'), $content . var_export($data, 1) . PHP_EOL, 8);
return;
}
2、Middleware 中间件 不做过多说明 全局中间件、中间组、路由中间件 根据实际场景合理利用
3、Request 层 这里我在中间件和控制器中间加了一层Request 主要用来做参数校验 示例:
class TestRequest extends BaseRequest
{
public function rules()
{
return [
'nickname' => 'required',
'account_name' => 'required',
'role_id' => 'required',
'subject_id' => 'required',
'commission' => 'required',
] + parent::rules();
}
public function messages()
{
return [
] + parent::messages();
}
public function attributes()
{
return [
'nickname' => '昵称',
'account_name' => '账号',
'role_id' => '角色ID',
'subject_id' => '主体ID',
'commission' => '佣金比例',
] + parent::attributes();
}
}
4、Controller(控制器) 将复杂的业务逻辑从控制器抽离出来放在Service(服务层)防止控制器臃肿,难懂,不易维护
class UserController extends Controller
{
protected $userRepository;
protected $userService;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request, UserService $userService, UserTransformer $userTransformer, UserFormatter $userFormatter)
{
$user = $userService->getUserAll();
return response()->json($userFormatter->format($request, $userTransformer->transform($user)));
}
5、Service层 商业逻辑,不是简单的查询数据,而是特定的任务,例如判断用户是否是会员,设置用户权限等等,这些操作建议放在Service,之后Controller再调用它
class UserService
{
protected $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function getUserAll()
{
if(1 == 1){//会员
return $this->userRepository->getUaerAll();
}else{
//todo
}
}
6、Repository层 ,跟Eloquent/DB操作相关的,例如增删改查,直接和数据库打交道的基础操作抽出来放在Repository中,这样Model会变得很干净
class UserRepository
{
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function getUaerAll()
{
return $this->user->all();
}
7、Transformer ,转换器,例如在仓库repository中有一个获取所有用户信息的查询操作:
$this->user->all();但有些地方我们不需要用到那么多个字段,我只想有name和email字段,难道我要去改all()里面的参数,变成
$this->user->all(['name','email'])?这样另外的地方又要全部字段,这不就冲突了?这时候Transformer就有用了,其实原理是对$this->user->all()获得的数据进行筛选后再输出,加了个筛选器。(另外转化器还可以将输出字段和数据字段差异话,起到保护作用,还可以去除烂尾字段id、created_at、updated_at等)
class UserTransformer
{
public function transform(Collection $collection)
{
$user = $collection->map(function ($user){
return [
'name' => $user->name,
'email' => $user->email
];
});
return $user;
}
8、Formatter 主要用于保持API返回格式的一致
class UserFormatter
{
public function format(Request $request, $items)
{
return [
'link' => $request->fullUrl(),
'method' => $request->method(),
'code' => Response::HTTP_OK,
'message' => '',
'items' => $items
];
}
9、return log(返回报文),返回报文和请求报文是成对出现的 放在日志系统讨论
10、错误码:错误码需要统一化
- 正确返回 code :0 或者 200
- 系统错误 code:-1 或 500 系统错误是不需要给用户看的 例如数据库连接失败等
- 业务错误 code: 1001、1002、1003等 业务错误是需要给用户显示的 例如 验证码发送失败,请重新发送! 用户名密码错误等