andersao/l5-repository官方文檔(譯)

[toc]php

Laravel 5 Repositories (Laravel倉庫)

倉庫地址:git@github.com:andersao/l5-repository.gitlaravel

Repositories 是數據抽象層,它使得咱們的應用維護更加靈活。git

目錄

安裝

Composer

執行如下命令獲取最新安裝包:

composer require prettus/l5-repository

Laravel

>= laravel5.5

ServiceProvider 會自動發現

Other

config/app.phpproviders數組末尾添加 Prettus\Repository\Providers\RepositoryServiceProvider::class :

'providers' => [
    ...
    Prettus\Repository\Providers\RepositoryServiceProvider::class,
],

若是你的框架是 Lumen,請註冊該服務:

$app->register(Prettus\Repository\Providers\LumenRepositoryServiceProvider::class);

發佈配置文件:

php artisan vendor:publish --provider "Prettus\Repository\Providers\RepositoryServiceProvider"

方法

PrettusRepositoryContractsRepositoryInterface

  • all($columns = array('*'))
  • first($columns = array('*'))
  • paginate($limit = null, $columns = ['*'])
  • find($id, $columns = ['*'])
  • findByField($field, $value, $columns = ['*'])
  • findWhere(array $where, $columns = ['*'])
  • findWhereIn($field, array $where, $columns = [*])
  • findWhereNotIn($field, array $where, $columns = [*])
  • findWhereBetween($field, array $where, $columns = [*])
  • create(array $attributes)
  • update(array $attributes, $id)
  • updateOrCreate(array $attributes, array $values = [])
  • delete($id)
  • deleteWhere(array $where)
  • orderBy($column, $direction = 'asc');
  • with(array $relations);
  • has(string $relation);
  • whereHas(string $relation, closure $closure);
  • hidden(array $fields);
  • visible(array $fields);
  • scopeQuery(Closure $scope);
  • getFieldsSearchable();
  • setPresenter($presenter);
  • skipPresenter($status = true);

PrettusRepositoryContractsRepositoryCriteriaInterface

  • pushCriteria($criteria)
  • popCriteria($criteria)
  • getCriteria()
  • getByCriteria(CriteriaInterface $criteria)
  • skipCriteria($status = true)
  • getFieldsSearchable()

PrettusRepositoryContractsCacheableInterface

  • setCacheRepository(CacheRepository $repository)
  • getCacheRepository()
  • getCacheKey($method, $args = null)
  • getCacheMinutes()
  • skipCache($status = true)

PrettusRepositoryContractsPresenterInterface

  • present($data);

PrettusRepositoryContractsPresentable

  • setPresenter(PresenterInterface $presenter);
  • presenter();

PrettusRepositoryContractsCriteriaInterface

  • apply($model, RepositoryInterface $repository);

PrettusRepositoryContractsTransformable

  • transform();

用法

建立 Model

和普通添加Model的方法同樣,建立一個Model,可是,必定要定義一個可被表單數據批量賦值的屬性$fillable:

namespace App;

class Post extends Eloquent { // or Ardent, Or any other Model Class

    protected $fillable = [
        'title',
        'author',
        ...
     ];

     ...
}

建立 Repository

namespace App;

use Prettus\Repository\Eloquent\BaseRepository;

class PostRepository extends BaseRepository {

    /**
     * Specify Model class name
     *
     * @return string
     */
    function model()
    {
        return "App\\Post";
    }
}

生成器

經過生成器能夠輕鬆生成你的 Repository

配置

首先,你必須配置你的Repository文件的存儲位置。默認存放位置是app文件夾下,命名空間是App。請注意,paths數組裏的各項配置值實際上既是命名空間,又是文件路徑。不過,別擔憂,正斜槓和反斜槓都是在生成過程當中自動處理的。

...
    'generator'=>[
        'basePath'=>app()->path(),
        'rootNamespace'=>'App\\',
        'paths'=>[
            'models'       => 'Entities',
            'repositories' => 'Repositories',
            'interfaces'   => 'Repositories',
            'transformers' => 'Transformers',
            'presenters'   => 'Presenters',
            'validators'   => 'Validators',
            'controllers'  => 'Http/Controllers',
            'provider'     => 'RepositoryServiceProvider',
            'criteria'     => 'Criteria',
        ]
    ]

可能你想將你的項目保存在app文件夾外邊,而且添加其餘命名空間,好比:

...
     'generator'=>[
        'basePath'      => base_path('src/Lorem'),
        'rootNamespace' => 'Lorem\\'
    ]

另外,您可能但願自定義生成的類最終保存的位置。你能夠經過編輯paths來實現。好比:

'generator'=>[
        'basePath'=>app()->path(),
        'rootNamespace'=>'App\\',
        'paths'=>[
            'models'=>'Models',
            'repositories'=>'Repositories\\Eloquent',
            'interfaces'=>'Contracts\\Repositories',
            'transformers'=>'Transformers',
            'presenters'=>'Presenters'
            'validators'   => 'Validators',
            'controllers'  => 'Http/Controllers',
            'provider'     => 'RepositoryServiceProvider',
            'criteria'     => 'Criteria',
        ]
    ]

命令

運行如下命令,你能夠生成任何你想要的Model:

php artisan make:entity Post

此命令能夠生成 ControllerValidatorModelRepositoryPresenterTransformer類。
它還會生成一個新的服務提供者用來綁定Repository Interface及其相應的實現Eloquent Repository
將其添加到AppServiceProvider@register方法便可加載它:

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

你還能夠爲它配置repository命令選項,由於這個命令僅僅只是一個包裝器而已。
爲你的Post model生成一個repository層,使用以下命令:

php artisan make:repository Post

使用Blog命名空間,爲Post model生成一個repository層,使用以下命令:

php artisan make:repository "Blog\Post"

爲其添加可填充字段:

php artisan make:repository "Blog\Post" --fillable="title,content"

若是想要經過命令直接添加驗證規則,須要添加--rules選項而且同時建立遷移:

php artisan make:entity Cat --fillable="title:string,content:text" --rules="title=>required|min:2, content=>sometimes|min:10"

這個命令將會建立一個初始的包含基礎的CRUDRESTfull控制器,所以只須要添加下面一行代碼到routes.php便可:

Route::resource('cats', CatsController::class);

此命令將會依據你的默認設置自動建立一個包含RepositoriesEntities文件夾:

以上設置完成之後,你仍須要爲其接口綁定真實的repository實現類,好比在Repositories Service Provider中。

App::bind('{YOUR_NAMESPACE}Repositories\PostRepository', '{YOUR_NAMESPACE}Repositories\PostRepositoryEloquent');

而且使用:

public function __construct({YOUR_NAMESPACE}Repositories\PostRepository $repository){
    $this->repository = $repository;
}

另外,也能夠用artisan命令來綁定:

php artisan make:bindings Cats

使用方法

namespace App\Http\Controllers;

use App\PostRepository;

class PostsController extends BaseController {

    /**
     * @var PostRepository
     */
    protected $repository;

    public function __construct(PostRepository $repository){
        $this->repository = $repository;
    }

    ....
}

經過Repository獲取全部結果:

$posts = $this->repository->all();

經過Repository獲取分頁結果:

$posts = $this->repository->paginate($limit = null, $columns = ['*']);

經過id獲取結果:

$post = $this->repository->find($id);

隱藏Model的屬性:

$post = $this->repository->hidden(['country_id'])->find($id);

顯示Model指定屬性:

$post = $this->repository->visible(['id', 'state_id'])->find($id);

加載Model關聯關係:

$post = $this->repository->with(['state'])->find($id);

根據字段名稱獲取結果:

$posts = $this->repository->findByField('country_id','15');

根據多個字段獲取結果:

$posts = $this->repository->findWhere([
    //Default Condition =
    'state_id'=>'10',
    'country_id'=>'15',
    //Custom Condition
    ['columnName','>','10']
]);

根據某一字段的多個值獲取結果:

$posts = $this->repository->findWhereIn('id', [1,2,3,4,5]);

Find by result by excluding multiple values in one field
獲取不包含某一字段的指定值的結果:

$posts = $this->repository->findWhereNotIn('id', [6,7,8,9,10]);

經過自定義scope獲取結果:

$posts = $this->repository->scopeQuery(function($query){
    return $query->orderBy('sort_order','asc');
})->all();

Repository中建立數據:

$post = $this->repository->create( Input::all() );

Repository中更新數據:

$post = $this->repository->update( Input::all(), $id );

Repository中刪除數據:

$this->repository->delete($id)

Repository中經過多字段刪除數據:

$this->repository->deleteWhere([
    //Default Condition =
    'state_id'=>'10',
    'country_id'=>'15',
])

建立Criteria(條件)

使用命令

php artisan make:criteria My

Criteria是一種根據須要,運用特定條件改變repository層查詢的一種方式。你能夠在repository層添加多個criteria

use Prettus\Repository\Contracts\RepositoryInterface;
use Prettus\Repository\Contracts\CriteriaInterface;

class MyCriteria implements CriteriaInterface {

    public function apply($model, RepositoryInterface $repository)
    {
        $model = $model->where('user_id','=', Auth::user()->id );
        return $model;
    }
}

在控制器中使用Criteria

namespace App\Http\Controllers;

use App\PostRepository;

class PostsController extends BaseController {

    /**
     * @var PostRepository
     */
    protected $repository;

    public function __construct(PostRepository $repository){
        $this->repository = $repository;
    }


    public function index()
    {
        $this->repository->pushCriteria(new MyCriteria1());
        $this->repository->pushCriteria(MyCriteria2::class);
        $posts = $this->repository->all();
        ...
    }

}

經過Criteria獲取結果:

$posts = $this->repository->getByCriteria(new MyCriteria());

Repository中設置默認Criteria

use Prettus\Repository\Eloquent\BaseRepository;

class PostRepository extends BaseRepository {

    public function boot(){
        $this->pushCriteria(new MyCriteria());
        // or
        $this->pushCriteria(AnotherCriteria::class);
        ...
    }

    function model(){
       return "App\\Post";
    }
}

跳過在 repository中設置的criteria :

在任何其餘方法鏈前使用skipCriteria

$posts = $this->repository->skipCriteria()->all();

移除criteria

使用popCriteria移除criteria

$this->repository->popCriteria(new Criteria1());
// or
$this->repository->popCriteria(Criteria1::class);

使用RequestCriteria

RequestCriteria是一個標準的Criteria的實現類。它容許過濾器根據請求中發送的參數在Repository中執行。
你能夠用它來執行一個動態搜索,過濾數據,而且還能夠自定義一個查詢。要在Repository中使用Criteria,你能夠在Repositoryboot方法中添加一個新的criteria;若是僅僅想要過濾一個新的請求,你能夠直接在控制器中使用;

Repository中使用

use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;


class PostRepository extends BaseRepository {

    /**
     * @var array
     */
    protected $fieldSearchable = [
        'name',
        'email'
    ];

    public function boot(){
        $this->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
        ...
    }

    function model(){
       return "App\\Post";
    }
}

記住,你須要定義哪些Model字段可被搜索;
在你的repository裏經過設置$fieldSearchable可被搜索的字段名或字段的關聯關係;

protected $fieldSearchable = [
    'name',
    'email',
    'product.name'
];

你能夠設置執行查詢時的條件類型,默認條件是 "="

protected $fieldSearchable = [
    'name'=>'like',
    'email', // Default Condition "="
    'your_field'=>'condition'
];

Controller中使用

public function index()
    {
        $this->repository->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
        $posts = $this->repository->all();
        ...
    }

Criteria舉例

經過request請求全部數據:

http://prettus.local/users

[
    {
        "id": 1,
        "name": "John Doe",
        "email": "john@gmail.com",
        "created_at": "-0001-11-30 00:00:00",
        "updated_at": "-0001-11-30 00:00:00"
    },
    {
        "id": 2,
        "name": "Lorem Ipsum",
        "email": "lorem@ipsum.com",
        "created_at": "-0001-11-30 00:00:00",
        "updated_at": "-0001-11-30 00:00:00"
    },
    {
        "id": 3,
        "name": "Laravel",
        "email": "laravel@gmail.com",
        "created_at": "-0001-11-30 00:00:00",
        "updated_at": "-0001-11-30 00:00:00"
    }
]

repository中探究:

http://prettus.local/users?search=John%20Doe

或者

http://prettus.local/users?search=John&searchFields=name:like

或者

http://prettus.local/users?search=john@gmail.com&searchFields=email:=

或者

http://prettus.local/users?search=name:John Doe;email:john@gmail.com

or

http://prettus.local/users?search=name:John;email:john@gmail.com&searchFields=name:like;email:=

[
    {
        "id": 1,
        "name": "John Doe",
        "email": "john@gmail.com",
        "created_at": "-0001-11-30 00:00:00",
        "updated_at": "-0001-11-30 00:00:00"
    }
]

默認狀況下,RequestCriteria經過or比較操做符對每一個查詢參數進行查詢:

http://prettus.local/users?search=age:17;email:john@gmail.com

以上例子將會執行如下查詢:

SELECT * FROM users WHERE age = 17 OR email = 'john@gmail.com';

若是想要使用and進行查詢,能夠傳遞searchJoin參數,以下所示:

http://prettus.local/users?search=age:17;email:john@gmail.com&searchJoin=and

過濾字段:

http://prettus.local/users?filter=id;name

[
    {
        "id": 1,
        "name": "John Doe"
    },
    {
        "id": 2,
        "name": "Lorem Ipsum"
    },
    {
        "id": 3,
        "name": "Laravel"
    }
]

結果排序:

http://prettus.local/users?filter=id;name&orderBy=id&sortedBy=desc

[
    {
        "id": 3,
        "name": "Laravel"
    },
    {
        "id": 2,
        "name": "Lorem Ipsum"
    },
    {
        "id": 1,
        "name": "John Doe"
    }
]

經過關聯表進行排序:

http://prettus.local/users?orderBy=posts|title&sortedBy=desc

查詢操做將會按照以下sql執行:

...
INNER JOIN posts ON users.post_id = posts.id
...
ORDER BY title
...

http://prettus.local/users?orderBy=posts:custom_id|posts.title&sortedBy=desc

查詢操做將會按照以下sql執行:

...
INNER JOIN posts ON users.custom_id = posts.id
...
ORDER BY posts.title
...

添加關聯關係:

http://prettus.local/users?with=groups

修改參數名

你能夠在配置文件config/repository.php中修改參數名

緩存

repository中輕鬆添加緩存層

緩存用法

繼承CacheableInterface接口,並使用CacheableRepositoryTrait

use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Contracts\CacheableInterface;
use Prettus\Repository\Traits\CacheableRepository;

class PostRepository extends BaseRepository implements CacheableInterface {

    use CacheableRepository;

    ...
}

好了,這樣你的repository就能夠緩存了,而且,當你建立、修改、刪除一個item時,repository緩存將會被清除。

緩存配置

你能夠在config/repository.php中修改緩存設置,也能夠直接在repository中修改。

config/repository.php

'cache'=>[
    //Enable or disable cache repositories
    'enabled'   => true,

    //Lifetime of cache
    'minutes'   => 30,

    //Repository Cache, implementation Illuminate\Contracts\Cache\Repository
    'repository'=> 'cache',

    //Sets clearing the cache
    'clean'     => [
        //Enable, disable clearing the cache on changes
        'enabled' => true,

        'on' => [
            //Enable, disable clearing the cache when you create an item
            'create'=>true,

            //Enable, disable clearing the cache when upgrading an item
            'update'=>true,

            //Enable, disable clearing the cache when you delete an item
            'delete'=>true,
        ]
    ],
    'params' => [
        //Request parameter that will be used to bypass the cache repository
        'skipCache'=>'skipCache'
    ],
    'allowed'=>[
        //Allow caching only for some methods
        'only'  =>null,

        //Allow caching for all available methods, except
        'except'=>null
    ],
],

能夠在repository中直接覆蓋以上設置:

use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Contracts\CacheableInterface;
use Prettus\Repository\Traits\CacheableRepository;

class PostRepository extends BaseRepository implements CacheableInterface {

    // Setting the lifetime of the cache to a repository specifically
    protected $cacheMinutes = 90;

    protected $cacheOnly = ['all', ...];
    //or
    protected $cacheExcept = ['find', ...];

    use CacheableRepository;

    ...
}

可緩存的方法有 : all, paginate, find, findByField, findWhere, getByCriteria

驗證器

安裝 prettus/laravel-validator.

composer require prettus/laravel-validator

輕鬆經過 prettus/laravel-validator進行驗證

更多詳情點擊此處

使用驗證類

建立驗證器

在下面的例子中,咱們定義一些建立和編輯的規則:

use \Prettus\Validator\LaravelValidator;

class PostValidator extends LaravelValidator {

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

}

按以下所示,定義指定規則:

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'
        ]
   ];

}
Repository中使用驗證器
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;

class PostRepository extends BaseRepository {

    /**
     * Specify Model class name
     *
     * @return mixed
     */
    function model(){
       return "App\\Post";
    }

    /**
     * Specify Validator class name
     *
     * @return mixed
     */
    public function validator()
    {
        return "App\\PostValidator";
    }
}

Repository中定義規則

另外,除了使用class來定義驗證規則以外,還能夠直接在repository屬性中直接設置,這和在class中定義驗證規則效果同樣:

use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;
use Prettus\Validator\Contracts\ValidatorInterface;

class PostRepository extends BaseRepository {

    /**
     * Specify Validator Rules
     * @var array
     */
     protected $rules = [
        ValidatorInterface::RULE_CREATE => [
            'title' => 'required',
            'text'  => 'min:3',
            'author'=> 'required'
        ],
        ValidatorInterface::RULE_UPDATE => [
            'title' => 'required'
        ]
   ];

    /**
     * Specify Model class name
     *
     * @return mixed
     */
    function model(){
       return "App\\Post";
    }

}

驗證器如今就已經準備好了。若是驗證失敗,將拋出該類型的異常:Prettus\Validator\Exceptions\ValidatorException

呈現器(Presenters)

Presenters 函數是對象的包裝器和呈現器.

Fractal 呈現器

安裝 Fractal.

composer require league/fractal

實現Presenter有兩個方法:

第一種方式:
建立一個TransformerAbstract,並如建立Transformer中所描述的那樣,使用Presenter類設置它;

第二種方式:
讓你的model實現Transformable接口,並使用默認的Presenter ModelFractarPresenter,它們具備一樣的效果;

Transformer
使用命令建立Transformer
php artisan make:transformer Post

這將會生成下面的類

建立Transformer
use League\Fractal\TransformerAbstract;

class PostTransformer extends TransformerAbstract
{
    public function transform(\Post $post)
    {
        return [
            'id'      => (int) $post->id,
            'title'   => $post->title,
            'content' => $post->content
        ];
    }
}
使用命令建立Presenter呈現器
php artisan make:presenter Post

若是你尚未建立Transformer轉換器,這個命令將會提示你也建立一個Transformer

建立Presenter
use Prettus\Repository\Presenter\FractalPresenter;

class PostPresenter extends FractalPresenter {

    /**
     * Prepare data to present
     *
     * @return \League\Fractal\TransformerAbstract
     */
    public function getTransformer()
    {
        return new PostTransformer();
    }
}
Repository中使用Presenter
use Prettus\Repository\Eloquent\BaseRepository;

class PostRepository extends BaseRepository {

    ...

    public function presenter()
    {
        return "App\\Presenter\\PostPresenter";
    }
}

或者經過以下所示在Controller中使用Presenter

$this->repository->setPresenter("App\\Presenter\\PostPresenter");
Model後使用 Presenter

若是你記錄了一個presenter,而且有時候使用了skipPresenter()方法,或者只是不想讓presenter自動改變結果。你能夠在你的model中實現Presentable接口,這樣,你能夠在任什麼時候候顯示你的model。見下文:

在你的model裏,實現接口Prettus\Repository\Contracts\PresentablePrettus\Repository\Traits\PresentableTrait

namespace App;

use Prettus\Repository\Contracts\Presentable;
use Prettus\Repository\Traits\PresentableTrait;

class Post extends Eloquent implements Presentable {

    use PresentableTrait;

    protected $fillable = [
        'title',
        'author',
        ...
     ];

     ...
}

在那裏,你能夠單獨提交你的model,看一個例子:

$repository = app('App\PostRepository');
$repository->setPresenter("Prettus\\Repository\\Presenter\\ModelFractalPresenter");

//Getting the result transformed by the presenter directly in the search
$post = $repository->find(1);

print_r( $post ); //It produces an output as array

...

//Skip presenter and bringing the original result of the Model
$post = $repository->skipPresenter()->find(1);

print_r( $post ); //It produces an output as a Model object
print_r( $post->presenter() ); //It produces an output as array

若是,你想根據須要直接在model中使用presenter,你能夠在你的repository中將$skipPresenter屬性設置爲true,這樣,每一次請求將會跳過presenter

use Prettus\Repository\Eloquent\BaseRepository;

class PostRepository extends BaseRepository {

    /**
    * @var bool
    */
    protected $skipPresenter = true;

    public function presenter()
    {
        return "App\\Presenter\\PostPresenter";
    }
}
Model
實現接口
namespace App;

use Prettus\Repository\Contracts\Transformable;

class Post extends Eloquent implements Transformable {
     ...
     /**
      * @return array
      */
     public function transform()
     {
         return [
             'id'      => (int) $this->id,
             'title'   => $this->title,
             'content' => $this->content
         ];
     }
}
Repository中使用

Prettus\Repository\Presenter\ModelFractalPresenterModels的默認Presenter呈現器,它實現了Transformable接口

use Prettus\Repository\Eloquent\BaseRepository;

class PostRepository extends BaseRepository {

    ...

    public function presenter()
    {
        return "Prettus\\Repository\\Presenter\\ModelFractalPresenter";
    }
}
或者在controller中使用:
$this->repository->setPresenter("Prettus\\Repository\\Presenter\\ModelFractalPresenter");

repository中跳過已定義的Presenter

在任何一個方法鏈前,使用skipPresenter方法

$posts = $this->repository->skipPresenter()->all();

或者

$this->repository->skipPresenter();

$posts = $this->repository->all();
相關文章
相關標籤/搜索