Laravel开发实践orm程序员

repository实作

2016-12-07  本文已影响3028人  小聪明李良才

对于CRUD来说,其最难的是R操作,因为会有各种各样的查询方式,提供的查询接口有:

public function find($id, $columns = ['*']);
public function findByField($field, $value, $columns = ['*']);
public function findWhere(array $where, $columns = ['*']);
public function findWhereIn($field, array $values, $columns = ['*']);
public function findWhereNotIn($field, array $values, $columns = ['*']);

然后默认的实现是Prettus\Repository\Eloquent\BaseRepository,基本上就是对Eloquent\Builder的一个封装。

但是一些更复杂的查询怎么满足呢?我们难道需要每次有新的查询都去新增findCondition接口吗?显然我们不能这么做,这个时候Criteria就隆重登场了,先看个接口:

interface CriteriaInterface
{
    /**
     * Apply criteria in query repository
     *
     * @param                     $model
     * @param RepositoryInterface $repository
     *
     * @return mixed
     */
    public function apply($model, RepositoryInterface $repository);
}

所有的Criteria都需要实现apply方法,看一个可能是实现:

class LengthOverTwoHours implements CriteriaInterface {
    public function apply($model, Repository $repository)
    {
        $query = $model->where('length', '>', 120);
        return $query;
    }
}

通过定义LengthOverTwoHours来对Model新增查询,这样子我们每次有新的查询条件,只要新建Criteria即可,满足了开放封闭原则。

接着我们来使用下l5-repository。首先通过命令php artisan make:entity Book来生成文件,然后在AppServiceProvider@register中新增

$this->app->register( RepositoryServiceProvider::class);

接着产生一个Controller

php artisan make:controller -r BookController

在里面我们可以使用注入进Repository

public function __construct( BookRepository $bookRepository )
{
    $this->bookRepository = $bookRepository;
}

然后一些具体的操作可以去看https://github.com/andersao/l5-repository,写的非常详细。

最后介绍下怎么产生criteria,通过下面的命令

php artisan make:criteria My

然后添加下面代码

class MyCriteria implements CriteriaInterface
{
    /**
     * Apply criteria in query repository
     *
     * @param Builder                    $model
     * @param RepositoryInterface $repository
     *
     * @return mixed
     */
    public function apply($model, RepositoryInterface $repository)
    {
        $model = $model->where('user_id','=', \Auth::user()->id );
        return $model;
    }
}

就能够使用了,然后在controller中,我们通过下面的方式查询

public function index()
{
  $this->repository->pushCriteria(new MyCriteria());
  $books = $this->repository->all();
  ...
}

Presenters优化

接着我们讲Presenters部分。

我们再强调下Presenter解决的问题:把日期、金额、名称之类的呈现(presentation)逻辑抽离出来。在l5-repository这个功能其实不是很满意,我们希望的是1 Presenter中介绍的那种样子,原先样子是:

class Article extends Eloquent
{
    public function getDate(){/*...*/}

    public function getTaiwaneseDateTime(){/*...*/}

    public function getWesternDateTime(){/*...*/}

    public function getTaiwaneseDate(){/*...*/}

    public function getWesternDate(){/*...*/}
}

抽离出来后是:

class Article extends Eloquent
{
    public function present()
    {
        return new ArticlePresenter($this);
    }
}

class ArticlePresenter extends Presenter {

    public function getTaiwaneseDateTime(){/*...*/}

    public function getWesternDateTime(){/*...*/}

    public function getTaiwaneseDate(){/*...*/}

    public function getWesternDate(){/*...*/}
}

下面是一些实现方案

https://github.com/laracasts/Presenter

https://github.com/robclancy/presenter

https://github.com/laravel-auto-presenter/laravel-auto-presenter

参数验证

最后我们介绍validator

validator的逻辑从model中抽离出来,单独放入一个类中,

use \Prettus\Validator\Contracts\ValidatorInterface;
use \Prettus\Validator\LaravelValidator;

class PostValidator extends LaravelValidator {

    protected $rules = [
        ValidatorInterface::RULE_CREATE => [
            'title' => 'required',
            'text'  => 'min:3',
            'author'=> 'required'
        ],
        ValidatorInterface::RULE_UPDATE => [
            'title' => 'required'
        ]
   ];

}

能够制定create和update操作的时候不同的验证规则。

总结

以上就是repository的全部,文章开头由实际项目中model越来越胖引出如何给model瘦身,接着对model中的功能进行了划分,给出了合理的项目组织方式,接着通过从repository,presenter,validator分析了具体的一些优化方式。

最后本文只是简单的对l5-repository进行了介绍,更详细的功能,更多的实现细节,你都可以clone项目下来,自己好好去看,相信会学到很多。

参考

胖胖Model減重的五個方法

Using Repository Pattern in Laravel 5

胖胖 MODEL 的減重方法:PRESENTER

Laravel 的中大型專案架構

上一篇下一篇

猜你喜欢

热点阅读