表題のl5-repositoryとは
repositoryに統一されたインターフェースを持たせられそうなplugin
githubのスター数: 1191
対応laravel < 5.2 (リポジトリのコメントみる限り)
実行環境
- laravel5.1.*
- php7.1.0
なぜl5-repositoryを使ってみようと思ったか
チーム開発においてデータベースへのアクセスを
repositoryに任せるのはいいがメソッドの書き方が属人的に
なるので統一された命名規則を使いたいと思った。
repositoryに実装されているのは本当にそのモデルに
依存しているものだけにしてあとは強制的に継承先のものを使う。
使ってみる
準備
インストール
$ composer require prettus/l5-repository
サービスプロバイダに登録
'providers' => [
...
Prettus\Repository\Providers\RepositoryServiceProvider::class,
],
l5-repositoryのconfigファイルを生成
$ php artisan vendor:publish
Copied File [/vendor/prettus/l5-repository/src/resources/config/repository.php] To [/config/repository.php]
Repositroyを作る
<?php
namespace App\Repositories;
use Prettus\Repository\Eloquent\BaseRepository;
use App\Models\User;
class UserRepository extends BaseRepository
{
/**
* このリポジトリーで使うモデルのパスを返す
* BaseRepository内で$this->app->make($this->model())
* として渡される
*
* @return string
*/
function model()
{
return User::class;
}
}
model()は継承しているBaseRepositoryのabstractで
定義されているので実装必須。
ちなみに上記インストールにて/config/repository.phpを作成している場合
下記コマンドにてrepositoryの雛形は作ってくれる
php artisan make:repository [Model]
BaseRepositoryに実装されているもの
userRepositoryを使っているとします
//全データを取得
$this->userRepository->all();
//idで検索
$this->userRepository->find($id);
/**
* リレーション先のモデルを指定して取得
* Userモデルにpost()でリレーションが定義されている前提
*/
$this->userRepository->with(['post'])->find($id);
//フィールド名を指定してデータを取得
$this->userRepository->findByField('name', 'root');
//複数条件を指定してデータを取得
$this->userRepository->findWhere([
//Default Condition =
'name' => 'root',
//Custom Condition
['created_at', '>', '2016-01-01 00:00:00']
]);
//1つのフィールドに対し、複数の値から検索
$this->userRepository->findWhereIn('id', [1, 2, 3, 4]);
// 上記の逆も用意されている
$this->userRepository->findWhereNotIn('id', [6, 7, 8, 9]);
/**
* 条件をクロージャでも渡せる
*
* 各メソッドにて$this->applyScope()が呼ばれていて
* そこで指定した条件は追加される
*/
$this->userRepository->scopeQuery(function($query){
return $query->orderBy('updated_at', 'asc');
})->all();
/**
* 一件取得
* ただ、これは引数に条件は渡せないので、scopeQueryや
* 後述のCriteriaを使う前提での実装
*/
$this->userRepository->first($columns);
/**
* create, update, deleteも実装されている(ラッパーみたいな感じ)
*/
$this->userRepository->create(Input::all());
$this->userRepository->update(Input::all(), $id);
$this->userRepos
Criteria
必要に応じてCriteriaで定義した条件をRepositoryに適用させ
クエリを変えることができるようになる
Criteria作成
php artisan make:criteria User
今回はUserRepositoryに関するCriteriaを作るので
Userを指定しました。命名規則はないと思います。
デフォルトでは、app/Criteria/にUserCriteriaが作られました。
中身はこんな感じ
<?php
namespace App\Criteria;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
/**
* Class UserCriteria
* @package namespace App\Criteria;
*/
class UserCriteria implements CriteriaInterface
{
/**
* Apply criteria in query repository
*
* @param $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
return $model;
}
}
使用例
emailがgmailのユーザーをとってくる
/**
* Class UserCriteria
* @package namespace App\Criteria;
*/
class UserCriteria implements CriteriaInterface
{
/**
* Apply criteria in query repository
*
* @param $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
$model = $model->where('email', 'like', '%@gmail%');
return $model;
}
}
実行側
//Criteria適用
$this->userRepository->pushCriteria(UserCriteria::class);
dd($this->userRepository->all());
またはこんな書き方
$this->userRepository->getByCriteria(new UserCriteria());
Repository内にデフォで使用する場合は設定しておける
<?php
namespace App\Repositories;
use Prettus\Repository\Eloquent\BaseRepository;
use App\Models\User;
use App\Criteria\UserCriteria;
class UserRepository extends BaseRepository
{
/**
*
*/
/**
* defaultで使用するCriteriaがある場合は設定できる
*/
public function boot(){
$this->pushCriteria(UserCriteria::class);
}
}
いやいや、デフォで設定してあるけどこの時はデフォの条件使いたくない。。
スキップしましょう
$this->repository->skipCriteria()->all();
削除もできるみたいですが用途は如何に。。
$this->repository->popCriteria(Criteria1::class);
まとめ
チームにrepositoryを使う上での制約をもたらすには十分なのではないでしょうか
簡単なクエリでrepositoryが変に膨らむこともないだろうし
こちらで共通の処理を行う抽象的なメソッドを再発明しなくて
済むのもいいですね。
次回のプロジェクトではこいつ使ってみたいと思います。
RequestCriteriaやPresenters(オブジェクト出力のラッパー)
Validatorなども便利なものがあるようですが今回は割愛
だってFormRequest今のところ便利だし。。笑
Model周りの疑問
laravelはディレクトリ構成に自由が効くのでCriteriaなど
どう運用していってるのか既にプラクティスがある方いれば
是非教えていただきたいです。
自分的にはrepositoryでsaveなど任せるのは
違和感あるのでそこはmodelにやらせてました。
ただ、modelを注入したサービスクラスを別に作るべきなのかとも思っています。
みなさんどうしてるんでしょうか。笑