[toc]php
倉庫地址:git@github.com:andersao/l5-repository.git
laravel
Repositories
是數據抽象層,它使得咱們的應用維護更加靈活。git
執行如下命令獲取最新安裝包:
composer require prettus/l5-repository
ServiceProvider 會自動發現
在 config/app.php
中 providers
數組末尾添加 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"
和普通添加Model
的方法同樣,建立一個Model
,可是,必定要定義一個可被表單數據批量賦值的屬性$fillable
:
namespace App; class Post extends Eloquent { // or Ardent, Or any other Model Class protected $fillable = [ 'title', 'author', ... ]; ... }
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
此命令能夠生成 Controller
,Validator
,Model
,Repository
,Presenter
和Transformer
類。
它還會生成一個新的服務提供者用來綁定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"
這個命令將會建立一個初始的包含基礎的CRUD
的RESTfull
控制器,所以只須要添加下面一行代碼到routes.php
便可:
Route::resource('cats', CatsController::class);
此命令將會依據你的默認設置自動建立一個包含Repositories
的Entities
文件夾:
以上設置完成之後,你仍須要爲其接口綁定真實的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', ])
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
,你能夠在Repository
的boot
方法中添加一個新的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
接口,並使用CacheableRepository
Trait
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
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
函數是對象的包裝器和呈現器.
安裝 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\Presentable
和 Prettus\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\ModelFractalPresenter
是Models
的默認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();