environment
PHP8 + MySQL5.7 + Nginx1.20
IDE: PhpStorm
build
1. Installation
- Install via Composer
composer create-project laravel/laravel example-app
2, through the Laravel installer
composer global require laravel/installer
laravel new example-app
### Second, configuration
1. Database (configure the .env file in the root directory)
DB_CONNECTION=mysql
// host address
DB_HOST=127.0.0.1
// The port number
DB_PORT=3306
// data storage name
DB_DATABASE=laravel9
// username
DB_USERNAME=root
// password
DB_PASSWORD=
2. Time zone (configure config/app.php file)
````php
// Time zone modification, I feel that both can be defined by myself according to the actual situation
'timezone' => 'PRC', // continental time
or
'timezone' => 'Asia/Shanghai' // Shanghai time
Three, install the extension package
Only list a few necessary for the project, if necessary, you can take a look from the link below
- Code prompt tool
composer require barryvdh/laravel-ide-helper --dev
- Language Pack
composer require caouecs/laravel-lang
Use: Put the
vendor/caouecs/laravel-lang/src/zh-CN
file in theresources/lang
directory, if it is laravel9, put it directly in the root directory ```lang ```` directory
Modify config/app
:
'locale' => 'zh_CN',
- Development and debugging tool (debugbar is installed in the dev environment)
composer require barryvdh/laravel-debugbar --dev
Unified Response response
I don't use dingo for development here. Personally, it's not very easy to use. We define it ourselves below.
First, we need to create a Helpers
directory under the app
directory
- Encapsulating a unified status code (ResponseEnum)
Create aResponseEnum.php
file in theapp/Helpers
directory<?php
namespace App\Helpers;
class ResponseEnum
{
// 001 ~ 099 means system status; 100 ~ 199 means authorized service; 200 ~ 299 means user service
/*------------------------------------------------ -------------------------------------------*/
// The beginning of 100 indicates information prompt, this kind of status indicates a temporary response
// 100 - continue
// 101 - switch protocol
/*------------------------------------------------ -------------------------------------------*/
// 200 means the server successfully accepted the client request
const HTTP_OK = [200001, 'The operation succeeded'];
const HTTP_ERROR = [200002, 'Operation failed'];
const HTTP_ACTION_COUNT_ERROR = [200302, 'Frequent operations'];
const USER_SERVICE_LOGIN_SUCCESS = [200200, 'Login successful'];
const USER_SERVICE_LOGIN_ERROR = [200201, 'Login failed'];
const USER_SERVICE_LOGOUT_SUCCESS = [200202, 'Logout successful'];
const USER_SERVICE_LOGOUT_ERROR = [200203, 'Logout failed'];
const USER_SERVICE_REGISTER_SUCCESS = [200104, 'Registration successful'];
const USER_SERVICE_REGISTER_ERROR = [200105, 'Registration failed'];
const USER_ACCOUNT_REGISTERED = [23001, 'The account is registered'];
/*------------------------------------------------ -------------------------------------------*/
// The one at the beginning of 300 indicates that the server redirects and points to other places, and the client browser must take more actions to realize the request
// 302 - The object has moved.
// 304 - Not modified.
// 307 - Temporary redirect.
/*------------------------------------------------ -------------------------------------------*/
// The ones at the beginning of 400 indicate that the client has an error request error, the data cannot be requested, or cannot be found, etc.
// 400 - Bad Request
const CLIENT_NOT_FOUND_HTTP_ERROR = [400001, 'Request failed'];
const CLIENT_PARAMETER_ERROR = [400200, 'Parameter error'];
const CLIENT_CREATED_ERROR = [400201, 'Data already exists'];
const CLIENT_DELETED_ERROR = [400202, 'Data does not exist'];
// 401 - Access Denied
const CLIENT_HTTP_UNAUTHORIZED = [401001, 'Authorization failed, please log in first'];
const CLIENT_HTTP_UNAUTHORIZED_EXPIRED = [401200, 'The account information has expired, please log in again'];
const CLIENT_HTTP_UNAUTHORIZED_BLACKLISTED = [401201, 'The account is logged in on another device, please log in again'];
// 403 - Forbidden
// 404 - file or directory not found
const CLIENT_NOT_FOUND_ERROR = [404001, 'The page was not found'];
// 405 - HTTP verb not allowed to access this page (method not allowed)
const CLIENT_METHOD_HTTP_TYPE_ERROR = [405001, 'HTTP request type error'];
// 406 - The client browser does not accept the MIME type of the requested page
// 407 - Proxy authentication required
// 412 - precondition failed
// 413 - Request entity too large
// 414 - Request URI too long
// 415 - Unsupported media type
// 416 - The requested range cannot be satisfied
// 417 - Execution failed
// 423 - Locked error
/*------------------------------------------------ -------------------------------------------*/
// The beginning of 500 indicates a server error, the server is terminated due to code, or for some reason
// Server operation error code: 500 ~ 599 at the beginning, followed by 3 digits
// 500 - Internal server error
const SYSTEM_ERROR = [500001, 'Server Error'];
const SYSTEM_UNAVAILABLE = [500002, 'The server is under maintenance and temporarily unavailable'];
const SYSTEM_CACHE_CONFIG_ERROR = [500003, 'Cache configuration error'];
const SYSTEM_CACHE_MISSED_ERROR = [500004, 'cache miss'];
const SYSTEM_CONFIG_ERROR = [500005, 'System configuration error'];
// Business operation error code (external service or internal service call)
const SERVICE_REGISTER_ERROR = [500101, 'Registration failed'];
const SERVICE_LOGIN_ERROR = [500102, 'Login failed'];
const SERVICE_LOGIN_ACCOUNT_ERROR = [500103, 'Account or password error'];
const SERVICE_USER_INTEGRAL_ERROR = [500200, 'Insufficient points'];
//501 - The header value specifies an unimplemented configuration
//502 - The web server received an invalid response when acting as a gateway or proxy server
//503 - Service unavailable. This error code is specific to IIS 6.0
//504 - Gateway timed out
//505 - HTTP version not supported
/*------------------------------------------------ -------------------------------------------*/
}
2. Create a business exception capture Exception file
Create a ```BusinessException.php``` file in the ```app/Exceptions``` directory for throwing business exceptions
````php
<?php
namespace App\Exceptions;
useException;
class BusinessException extends Exception
{
/**
* Business exception constructor
* @param array $codeResponse status code
* @param string $info Custom return information, if not empty, the message text information in codeResponse will be replaced
*/
public function __construct(array $codeResponse, $info = '')
{
[$code, $message] = $codeResponse;
parent::__construct($info ?: $message, $code);
}
}
- Custom return exception
Modify theHandler.php
file in theapp/Exceptions
directory<?php
namespace App\Exceptions;
use App\Helpers\ApiResponse;
use App\Helpers\ResponseEnum;
use Illuminaate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;
class Handler extends ExceptionHandler
{
useApiResponse;
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<Throwable>>
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
//
});
}
public function render($request, Throwable $exception)
{
// If it is a production environment, return 500
if (!config('app.debug')) {
$this->throwBusinessException(ResponseEnum::SYSTEM_ERROR);
}
// request type error exception thrown
if ($exception instanceof MethodNotAllowedHttpException) {
$this->throwBusinessException(ResponseEnum::CLIENT_METHOD_HTTP_TYPE_ERROR);
}
// Parameter validation error exception is thrown
if ($exception instanceof ValidationException) {
$this->throwBusinessException(ResponseEnum::CLIENT_PARAMETER_ERROR);
}
// Route does not exist exception thrown
if ($exception instanceof NotFoundHttpException) {
$this->throwBusinessException(ResponseEnum::CLIENT_NOT_FOUND_ERROR);
}
// custom error exception thrown
if ($exception instanceof BusinessException) {
return response()->json([
'status' => 'fail',
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
'data' => null,
'error' => null,
]);
}
return parent::render($request, $exception);
}
}
Fourth, encapsulate the unified message (ApiResponse) returned by the API
Create ```ApiResponse.php``` file in ```app/Helpers``` directory
````php
<?php
namespace App\Helpers;
use App\Helpers\ResponseEnum;
use App\Exceptions\BusinessException;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
trait ApiResponse
{
/**
* success
* @param null $data
* @param array $codeResponse
* @return JsonResponse
*/
public function success($data = null, $codeResponse=ResponseEnum::HTTP_OK): JsonResponse
{
return $this->jsonResponse('success', $codeResponse, $data, null);
}
/**
* fail
* @param array $codeResponse
* @param null $data
* @param null $error
* @return JsonResponse
*/
public function fail($codeResponse=ResponseEnum::HTTP_ERROR, $data = null, $error=null): JsonResponse
{
return $this->jsonResponse('fail', $codeResponse, $data, $error);
}
/**
*json response
* @param $status
* @param $codeResponse
* @param $data
* @param $error
* @return JsonResponse
*/
private function jsonResponse($status, $codeResponse, $data, $error): JsonResponse
{
list($code, $message) = $codeResponse;
return response()->json([
'status' => $status,
'code' => $code,
'message' => $message,
'data' => $data ?? null,
'error' => $error,
]);
}
/**
* Successful paging return
* @param $page
* @return JsonResponse
*/
protected function successPaginate($page): JsonResponse
{
return $this->success($this->paginate($page));
}
private function paginate($page)
{
if ($page instanceof LengthAwarePaginator){
return [
'total' => $page->total(),
'page' => $page->currentPage(),
'limit' => $page->perPage(),
'pages' => $page->lastPage(),
'list' => $page->items()
];
}
if ($page instanceof Collection){
$page = $page->toArray();
}
if (!is_array($page)){
return $page;
}
$total = count($page);
return [
'total' => $total, //Total data
'page' => 1, // current page number
'limit' => $total, // the number of data bars per page
'pages' => 1, // the page number of the last page
'list' => $page // data
];
}
/**
* Business exception return
* @param array $codeResponse
* @param string $info
* @throws BusinessException
*/
public function throwBusinessException(array $codeResponse=ResponseEnum::HTTP_ERROR, string $info = '')
{
throw new BusinessException($codeResponse, $info);
}
}
- Create a base controller class
- Create a
BaseController.php
in theapp/Http/controller
directory as the base class of Api, and then inherit Controller in the base classBaseController.php
, and introduce the unified message returned by the encapsulation APImessage (ApiResponse)<?php
namespace App\Http\Controllers;
use App\Helpers\ApiResponse;
class BaseController extends Controller
{
// API interface response
useApiResponse;
}
6. Use
1. Return success information
````php
return $this->success($data);
- Return failure information
return $this->fail($codeResponse);
- Throwing an exception
$this->throwBusinessException($codeResponse);
- Paging
return $this->successPaginate($data);
Unified form parameter input validation
- Create
Create aVerifyRequestInput.php
file in theApp\Helpers
directory, and introduceApiResponse
, so that the form parameters can be verified more easily, among which `verifyData`
method to customize validation fields and rules<?php
namespace App\Helpers;
use App\Helpers\ResponseEnum;
use App\Exceptions\BusinessException;
use Illuminate\Validation\Rule;
trait VerifyRequestInput
{
useApiResponse;
/**
* Verify ID
* @param $key
* @param null $default
* @return mixed|null
* @throws BusinessException
*/
public function verifyId($key, $default=null)
{
return $this->verifyData($key, $default, 'integer|digits_between:1,20');
}
/**
* Check if it is an integer
* @param $key
* @param null $default
* @return mixed|null
* @throws BusinessException
*/
public function verifyInteger($key, $default=null)
{
return $this->verifyData($key, $default, 'integer');
}
/**
* Verify if it is a number
* @param $key
* @param null $default
* @return mixed|null
* @throws BusinessException
*/
public function verifyNumeric($key, $default=null)
{
return $this->verifyData($key, $default, 'numeric');
}
/**
* Check if it is a string
* @param $key
* @param null $default
* @return mixed|null
* @throws BusinessException
*/
public function verifyString($key, $default=null)
{
return $this->verifyData($key, $default, 'string');
}
/**
* Check if it is a boolean
* @param $key
* @param null $default
* @return mixed|null
* @throws BusinessException
*/
public function verifyBoolean($key, $default=null)
{
return $this->verifyData($key, $default, 'boolean');
}
/**
* Verify if it is an enumeration
* @param $key
* @param null $default
* @param array $enum
* @return mixed|null
* @throws BusinessException
*/
public function verifyEnum($key, $default=null, array $enum=[])
{
return $this->verifyData($key, $default, Rule::in($enum));
}
/**
- Custom verification parameters
- @param $key string field
- @param $default string default value
- @param $rule string validation rule
- @return mixed|null
- @throws BusinessException
*/
public function verifyData($key, $default, $rule)
{
$value = request()->input($key, $default);
$validator = \Validator::make([$key => $value], [$key => $rule]);
if (is_null($value)){
$this->throwBusinessException(ResponseEnum::CLIENT_PARAMETER_ERROR);
}
if ($validator->fails()){
$this->throwBusinessException(ResponseEnum::CLIENT_PARAMETER_ERROR, $validator->errors()->first());
}
return $value;
}
}
2. Use
```VerifyRequestInput``` needs to be introduced in the ```App\Http\Controllers\BaseController``` controller base class
````php
use App\Helpers\VerifyRequestInput;
// Validate the form parameter input request
use VerifyRequestInput;
- Case:
There is aindex
method, we useverifyId
to verify the parameters of the request when getting the parameterspublic function index() { $id = $this->verifyId('id', null); }
When we request, because the incoming parameter is a string
http://127.0.0.1:8000/api/user/index?id=xddd
So return `
The id must be an integer
, prompting that the id must be an integer
Create service layer Service
If the project is relatively small and there are few interfaces, the business logic can be placed in the controller and model layers. Otherwise, you need to create a Service layer to store some more complex business logic.
-
In the ``app`
directory, create a folder named
Services``` -
Create the base class
BaseService.php
in the newly createdServices
directory, and use the singleton mode to avoid wasting memory and make it easy to call<?php
namespace App\Services;
use App\Helpers\ApiResponse;
class BaseService
{
// Introduce api unified return message
useApiResponse;
protected static $instance;
public static function getInstance()
{
if (static::$instance instanceof static){
return self::$instance;
}
static::$instance = new static();
return self::$instance;
}
protected function __construct(){}
protected function __clone(){}
}
3. Use
For example, to implement a function to obtain user information
1. Create a ``UserService.php``` file in the Service layer
````php
<?php
namespace App\Services;
use App\Services\BaseService;
class UserService extends BaseService
{
// get user information
public function getUserInfo()
{
return ['id' => 1, 'nickname' => 'Zhang San', 'age' => 18];
}
}
- Add a
info
method in the controllerUserController
, and call the getUserInfo() method in the service layeruse App\Services\UserService;
public function info()
{
$user = UserService::getInstance()->getUserInfo();
return $this->success($user);
}
3. Return
![image.png](https://cdn.elephdev.com/uploads/20220328/26be2011a059aa8c85777c53bede9fb9.png)
Post comment 取消回复