菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
2018
7

关于 Repository 的设计模式

原创
05/13 14:22
阅读数 2523

file

设计 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'));
            }
        });
    }
}

当然缺点就是要增加很多代码量,但是对于团队开发来说这样也许比较规范吧……

如果你有更好的分离方法,欢迎一起讨论,谢谢!

发表评论

0/200
2018 点赞
7 评论
收藏
为你推荐 换一批