文章目录
优雅的组织Laravel的项目结构
1.1 简介
在以前的开发中,所有的业务、数据库操作都写到了控制器中,导致控制器过于臃肿,不便阅读,而Laravel是一个优雅的框架,于是就想先组织一个优雅项目结构!~
1.2 目录介绍
更改的只有App
目录,目录结构如下:
├── Console
│ └── Kernel.php
├── Exceptions
│ ├── ApiException.php
│ ├── Handler.php
│ └── RequestInvalidException.php
├── Helper
├── Http
│ ├── Controllers
│ ├── Kernel.php
│ └── Middleware
├── Models
│ └── UserModel.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── Repositories
├── Requests
│ ├── Api
│ ├── BaseRequest.php
│ └── Mini
├── Services
│ ├── Api
│ ├── BaseService.php
│ └── Mini
└── Traits
└── ApiResponseTrait.php
说明:
新增加了目录Requests, Repositories, Services, Traits, Helper, Models目录。
1.2.1 Models目录
该目录下创建的类文件均是模型文件,仅仅定义模型还有其关联模型之间的关联,不进行任何其他的查询操作。
如 UserModel.php :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class UserModel extends Authenticatable implements JWTSubject
{
protected $table = 'users';
protected $fillable = ['username','password','keyId'];
use Notifiable;
// Rest omitted for brevity
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
1.2.2 Requests目录
该目录为表单验证类的目录,该目录下的Request类需要继承BaseRequest类, 然后通过注入到控制器中进行表单验证。
BaseRequest
代码如下:
<?php
namespace App\Requests;
use App\Traits\ApiResponseTrait;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use App\Exceptions\RequestInvalidException;
class BaseRequest extends FormRequest
{
use ApiResponseTrait;
/**
* 默认允许访问, 权限控制中间件已经进行过滤了!
* @return bool
*/
public function authorize()
{
return true;
}
// 验证失败抛接口异常。
public function failedValidation(Validator $validator)
{
$error = $validator->errors()->first();
throw new RequestInvalidException($error, 10000);
}
}
- 定义的异常类
RequestInvalidException
<?php
namespace App\Exceptions;
use App\Traits\ApiResponseTrait;
use Exception;
use Throwable;
class RequestInvalidException extends Exception
{
use ApiResponseTrait;
public function __construct(string $message = "", int $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
public function render($request){
// 如果是 AJAX 请求则返回 JSON 格式的数据
// if ($request->expectsJson()) {
// return response()->json(['msg' => $this->message], $this->code);
// }
// return view('error', ['msg' => $this->message]);
// 始终返回Json
return $this->error($this->code,$this->message);
}
}
RegisterRequest.php
代码如下 (用来校验用户注册的表单)
<?php
namespace App\Request\AboutUser;
class RegisterRequest extends \App\Request\BaseRequest
{
public function rules(): array
{
return [
'username' => [
'required',
'unique:users',
'max:11',
'min:5',
'regex:/^[0-9a-zA-Z_]*$/'
],
'password' => 'required|max:16|min:8'
];
}
public function messages() : array
{
return [
'username.required'=>'用户名不能为空',
'username.max'=>'用户名长度不能超过11个字符',
'username.min'=>'用户名长度不能少于5个字符',
'username.unique'=>'用户名已存在',
'username.regex'=>'用户名只能由字母和数字组成',
'password.required'=>'密码不能为空',
'password.max'=>'密码长度不能超过16个字符',
'password.min'=>'密码长度不能少于8个字符'
];
}
}
- 在控制器中使用
RegisterRequest.php
//用户注册
public function register(RegisterRequest $request): \Illuminate\Http\JsonResponse
{
// 1.新增用户
$account = $request->validated();
// 2.得到随机字符串 Key
$account['keyId'] = KeyModel::create(['value'=>Tools::random(16)])->id;
// 3.将密码进行加密
$account['password'] = Hash::make($account['password']);
// 4.插入数据并返回响应
$user = UserModel::create($account);
return $this->data($user,'注册成功');
}
1.2.3 Repositories目录
该目录下的类文件作用是进行数据的操纵(增删改查), 通过依赖注入方式引入模型类进行操作。
- 如
UserRepository
代码:
<?php
namespace App\Repositories;
use App\Models\UserModel;
class UserRepository
{
protected $model;
public function __construct(UserModel $model)
{
$this->model = $model;
}
public function getUserById($id)
{
return $this->model->find($id);
}
}
1.2.4 Services目录
该目录下的类文件主要用于业务逻辑的处理,通过注入Repository类进行数据操纵, 该目录下的Service都必须继承一个基类BaseService
:
<?php
namespace App\Services;
use App\Traits\ApiResponseTrait;
/**
* Class BaseService
* @package App\Services
*/
class BaseService
{
use ApiResponseTrait;
}
处理用户相关业务逻辑的UserService.php
代码如下:
<?php
namespace App\Services\Api;
use App\Repositories\UserRepository;
use App\Services\BaseService;
class UserService extends BaseService
{
protected $repository;
public function __construct(UserRepository $repository)
{
$this->repository = $repository;
}
/**
* 用户登录
* @param $params
* @return false|string
*/
public function login($params)
{
// 这里仅作演示,不必在意细节
return $this->repository->getUserById($params['id']);
}
/**
* 用户注销
*/
public function logout()
{
return $this->data(true, '注销成功');
}
}
1.2.5 Traits目录
该目录下主要定义一些Trait,提高代码复用率。 如ApiResponseTrait.php
代码:
<?php
namespace App\Traits;
/** 接口返回格式定义
* Class ApiResponseTrait
* @package App\Traits
*/
trait ApiResponseTrait
{
/**
* 返回成功数据
* @param $data
* @param string $msg
* @return false|string
*/
public function data($data, $msg='')
{
$resp = [
'status' => 1,
'data'=>$data,
'msg' => $msg,
'errno' => 0
];
return response()->json($resp);
}
/**
* 返回错误信息
* @param $errno
* @param string $msg
* @return false|string
*/
public function error($errno, $msg='')
{
$resp = [
'status' => 0,
'errno' => $errno,
'data' => [],
'msg' => $msg,
];
return response()->json($resp);
}
}
1.2.6 Helper目录
该目录也是为了提高代码复用率,不过该文件夹下定义的是一些自定义函数。
1.2.7 Controllers目录
该目录下有两个子目录Api
和Mini
, Api
是PC
端接口, Mini
是小程序端接口。
贴上一个控制器代码:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Requests\Api\User\LoginRequest;
use App\Services\Api\UserService;
/**
* 用户相关模块
* Class UserController
* @package App\Http\Controllers\Api
*/
class UserController extends Controller
{
public function __construct(UserService $service)
{
$this->service = $service;
}
// 用户登录
public function login(LoginRequest $request)
{
return $this->service->login($request->validated());
}
}
可以看到一个控制器方法仅有一行代码。
1.3 总结
引进Service和Repository层精简控制器代码,提高了代码的可读性。
Trait和Helper提高代码复用率,且方便集中管理。
通过依赖注入避免了new的使用, Laravel会递归的拿构造函数和参数进行注入实例。