1. Request log the request message log. The reason for adding the request message here is that in many cases, the BUG is difficult to reproduce at low frequency. The original request message can well troubleshoot the problem. This layer can also be placed in Middleware to handle the reference example:
<?php namespace App\Http\Middleware; use App\Http\Controllers\Controller; use Closure; class ApiCheck extends Controller { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $params = $request->input(); $Uri = $request->getRequestUri(); $UriArray = explode('?',$Uri); $UriArray = explode('/',$UriArray[0]); $this->dataRecodes('Request message', $params, $UriArray[3]); return $next($request); } }
class Helper { /** * @Notes: Record interface log information * @Author: Dong Xiannan * @Date: 2021/8/5 3:50 afternoon * @Description: describe * @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 middleware does not explain too much. The global middleware, intermediate group and routing middleware are used reasonably according to the actual scenario
3. Request layer here, I added a layer between middleware and controller. Request is mainly used as an example of parameter verification:
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' => 'nickname', 'account_name' => 'account number', 'role_id' => 'role ID', 'subject_id' => 'subject ID', 'commission' => 'commission rate ', ] + parent::attributes(); } }
4. The Controller separates the complex business logic from the Controller and puts it in the Service layer to prevent the Controller from being bloated, difficult to understand and difficult to maintain
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. The business logic of the Service layer is not simply querying data, but specific tasks, such as judging whether a user is a member, setting user permissions, etc. it is recommended to put these operations in the Service, and then call it by the Controller
class UserService { protected $userRepository; public function __construct(UserRepository $userRepository) { $this->userRepository = $userRepository; } public function getUserAll() { if(1 == 1){//member return $this->userRepository->getUaerAll(); }else{ //todo } }
6. The Repository layer is related to Eloquent/DB operations, such as adding, deleting, modifying and querying. The basic operations directly dealing with the database are extracted and placed in the Repository, so that the Model will become very clean
class UserRepository { protected $user; public function __construct(User $user) { $this->user = $user; } public function getUaerAll() { return $this->user->all(); }
7. Transformer, for example, there is a query operation to obtain all user information in the warehouse repository:
$this->user->all(); But in some places, we don't need to use so many fields. I just want to have name and email fields. Should I change the parameters in all() to
$this->user->all(['name','email'])? In this way, all fields are required in other places. Isn't this a conflict? At this time, the Transformer is useful. In fact, the principle is to filter the data obtained by $this - > User - > all(), then output it, and add a filter. (in addition, the converter can also protect the difference between the output field and the data field, and remove the unfinished field id, created_at, updated_at, etc.)
class UserTransformer { public function transform(Collection $collection) { $user = $collection->map(function ($user){ return [ 'name' => $user->name, 'email' => $user->email ]; }); return $user; }
8. Formatter is mainly used to keep the API return format consistent
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 (return message). The return message and request message appear in pairs and are discussed in the log system
10. Error code: the error code needs to be unified
- Correct return code: 0 or 200
- System error code:-1 or 500 system errors do not need to be shown to users, such as database connection failure
- Business error code: 1001, 1002, 1003 and other business errors need to be displayed to the user. For example, the verification code failed to be sent. Please send it again! Wrong user name and password, etc