关于 Repository 的设计模式
设计 Repository 的抽象基类,BaseRepository:
为了提高代码的 重用率
,我只在基础类上写了,每个模型所必须要的操作,CURD 在到具体的 Repository 上去做实现:
<?php
namespace App\Repositories;
use App\Exceptions\GeneralException;
/**
* 抽象的 Repository 类
*
* @package App\Repositories
*/
abstract class BaseRepository
{
/**
* 根据主键查找
*
* @param $id
* @param $trashed
* @return mixed
*/
public function find($id, $trashed = false)
{
if ($trashed) {
return $this->query()->withTrashed()->findOrFail($id);
}
return $this->query()->findOrFail($id);
}
/**
* 查询资源集合
*
* @param bool $query_string
* @param bool $keys
* @param int $paginate
* @param bool $trashed
* @return mixed
* @throws GeneralException
*/
public function getAll($query_string = false, $keys = false, $paginate = 15, $trashed = false)
{
try {
$query = $this->query();
if ($query_string && is_array($keys)) {
foreach ($keys as $key => $value) {
$query->orWhere($value, 'like', "%$query_string%");
}
}
if ($trashed) {
$query->withTrashed();
}
return $query->paginate($paginate);
} catch (Exception $exception) {
throw new GeneralException('未知错误,导致查询失败', 500);
}
}
/**
* 创建查询构造器
*
* @return mixed
*/
public function query()
{
return call_user_func(static::MODEL.'::query');
}
/**
* 序列化模型实例
*
* @param array $attributes
* @return mixed
*/
abstract protected function serialization(array $attributes);
}
模型的 Repository,继承自上面设计的基类:
<?php
namespace App\Repositories;
use App\Models\Company;
use App\Exceptions\GeneralException;
/**
* Class CompanyRepository
*
* @author George <jinrenjie@me.com>
* @package App\Repositories
*/
class CompanyRepository extends BaseRepository
{
/**
* 定义数据模型
*/
const MODEL = Company::class;
/**
* 创建企业信息
*
* @param array $attributes
* @return Company
* @throws GeneralException
*/
public function store(array $attributes)
{
$compnay = $this->serialization($attributes);
try {
$compnay->save();
return $compnay;
} catch (Exception $exception) {
throw new GeneralException('创建企业信息失败');
}
}
/**
* 更新企业信息
*
* @param Company $company
* @param array $attributes
* @return Company
* @throws GeneralException
*/
public function update(Company $company, array $attributes)
{
if (is_array($attributes)) {
foreach ($attributes as $key => $value) {
$company->$key = $value;
}
$company->saveOrFail();
return $company;
}
throw new GeneralException('要更新的属性必须是数组');
}
/**
* 删除企业信息
*
* @param Company $company
* @param bool $force
* @return bool|null
* @throws GeneralException
*/
public function delete(Company $company, $force = false)
{
try {
return $force ? $company->forceDelete() : $company->delete();
} catch (Exception $exception) {
throw new GeneralException('删除企业信息失败');
}
}
/**
* 序列化用户输入
*
* @param array $attributes
* @return Company
*/
protected function serialization(array $attributes)
{
$company = self::MODEL;
$company = new $company();
$company->title = $attributes['title'];
$company->introduction = array_get($attributes, 'introduction', null);
$company->url = array_get($attributes, 'url', null);
$company->logo = array_get($attributes, 'logo', null);
$company->address = array_get($attributes, 'address', null);
$company->contact = array_get($attributes, 'contact', null);
return $company;
}
}
这一层只处理数据的 CURD,并返回对应的操作结果,除了抛出异常劲量不涉及响应和请求……这样Controller 里只要调用方法而无需考虑异常处理。
<?php
namespace App\Http\Controllers\Interfaces;
use App\Models\Company;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Repositories\CompanyRepository;
use App\Extensions\Library\MaterialHandling;
use App\Http\Requests\Interfaces\Company\DeleteRequest;
use App\Http\Requests\Interfaces\Company\UpdateRequest;
use App\Http\Requests\Interfaces\Company\CreateRequest;
use App\Http\Requests\Interfaces\Company\ChangeLogoRequest;
use App\Http\Requests\Interfaces\Company\QueryResourceRequest;
use App\Http\Requests\Interfaces\Company\QueryCollectionRequest;
/**
* Class CompanyController
*
* @package App\Http\Controllers\Interfaces\User
*/
class CompanyController extends Controller
{
use MaterialHandling;
/**
* 定义保存 CompanyRepository 的实例
* @var CompanyRepository
*/
protected $companyRepository;
/**
* CompanyController constructor.
* @param $companyRepository
*/
public function __construct(CompanyRepository $companyRepository)
{
$this->companyRepository = $companyRepository;
}
/**
* 获取企业信息集合
*
* @param QueryCollectionRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(QueryCollectionRequest $request)
{
//获取分页大小
$paginate = $request->get('paginate', 15);
//获取模糊查询字符串
$query_string = $request->get('query_string', false);
//获取是否显示软删除的数据
$trashed = $request->get('trashed', false);
//定义需要模糊查询的字段
$keys = [
'title',
'introduction',
'address'
];
$collections = $this->companyRepository
->getAll($query_string, $keys, $paginate, $trashed);
return $this->success($collections);
}
/**
* 根据企业 ID 获取企业信息
*
* @param Company $company
* @param QueryResourceRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function show(Company $company, QueryResourceRequest $request)
{
return $this->success($company);
}
/**
* 创建企业信息
*
* @param CreateRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function create(CreateRequest $request)
{
$attributes = $request->all();
$company = $this->companyRepository->store($attributes);
return $this->created($company);
}
/**
* 更新企业信息
*
* @param Company $company
* @param UpdateRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function update(Company $company, UpdateRequest $request)
{
$attributes = $request->all();
$company = $this->companyRepository->update($company, $attributes);
return $this->updated($company);
}
/**
* 删除企业信息
*
* @param Company $company
* @param DeleteRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function delete(Company $company, DeleteRequest $request)
{
$this->companyRepository->delete($company);
return $this->deleted();
}
/**
* 更改企业 Logo
*
* @param Company $company
* @param ChangeLogoRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function changeLogo(Company $company, ChangeLogoRequest $request)
{
$file = $request->file('logo');
$path = $this->store($file, $request->user());
$result = $this->companyRepository->update($company, ['logo' => $path]);
return $this->updated($result);
}
}
控制器里的自定义响应,我参照了@王举 的文章:Laravel5.5+passport 放弃 dingo 开发 API 实战,让 API 开发更省心。
我还把 鉴权
和表单验证及错误信息
放到了 专门的 Request 里面去处理这样整体结构也更加清晰了,比如我的注册请求:
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Foundation\Http\FormRequest;
/**
* 用户注册请求
*
* @author George <jinrenjie@me.com>
* @package App\Http\Requests\Auth
*/
class RegisterRequest extends FormRequest
{
/**
* 定义授权规则
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* 定义验证规则
*
* @return array
*/
public function rules()
{
return [
'username' => 'required|alpha_dash|min:6|max:16|unique:users',
'password' => 'required|confirmed|min:8|max:32',
'mobile' => 'required|min:11|max:11|unique:users',
];
}
/**
* 定义错误消息
*
* @return array
*/
public function messages()
{
return [
'username.required' => '请填写用户名',
'username.alpha_dash' => '用户名只能是字母、数字、及下划线',
'username.min' => '用户名不得少于6个字符',
'username.max' => '用户名不得超过16个字符',
'username.unique' => '该用户名称已存在,请使用其他名称注册',
'password.required' => '请填写密码',
'password.confirmed' => '两次填写的密码不一致',
'password.min' => '密码最少8个字符',
'password.max' => '密码最多32个字符',
'mobile.required' => '请填写您的手机号码',
'mobile.min' => '您输入的号码不满11位',
'mobile.max' => '号码不得超过11位',
'mobile.unique' => '该手机号码已被注册',
];
}
/**
* 验证用户输入的验证码是否正确
*
* @param $validator
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (Cache::get($this->get('mobile'), false) !== $this->get('verification')) {
$validator->errors()->add('verification', '你输入的验证码有误');
} else {
Cache::forget($this->get('mobile'));
}
});
}
}
当然缺点就是要增加很多代码量,但是对于团队开发来说这样也许比较规范吧……
如果你有更好的分离方法,欢迎一起讨论,谢谢!
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: