1. smith-30

    Posted

    smith-30
Changes in title
+l5-repositoryで統一されたrepositoryが作れそうか
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,314 @@
+# 表題のl5-repositoryとは
+
+repositoryに統一されたインターフェースを持たせられそうなplugin
+githubのスター数: 1191
+対応laravel < 5.2 (リポジトリのコメントみる限り)
+
+https://github.com/andersao/l5-repository
+
+## 実行環境
+
+- laravel5.1.*
+- php7.1.0
+
+## なぜl5-repositoryを使ってみようと思ったか
+
+チーム開発においてデータベースへのアクセスを
+repositoryに任せるのはいいがメソッドの書き方が属人的に
+なるので統一された命名規則を使いたいと思った。
+
+repositoryに実装されているのは本当にそのモデルに
+依存しているものだけにしてあとは強制的に継承先のものを使う。
+
+## 使ってみる
+
+### 準備
+
+インストール
+
+```bash
+$ composer require prettus/l5-repository
+```
+
+サービスプロバイダに登録
+
+```php
+'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
+<?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を使っているとします
+
+```php
+//全データを取得
+$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:UserCriteria.php
+<?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のユーザーをとってくる
+
+```php:UserCriteria.php
+/**
+ * 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;
+ }
+}
+```
+
+
+__実行側__
+
+```php
+//Criteria適用
+$this->userRepository->pushCriteria(UserCriteria::class);
+dd($this->userRepository->all());
+```
+
+またはこんな書き方
+
+```php
+$this->userRepository->getByCriteria(new UserCriteria());
+```
+
+__Repository内にデフォで使用する場合は設定しておける__
+
+```php
+<?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);
+ }
+
+}
+```
+
+__いやいや、デフォで設定してあるけどこの時はデフォの条件使いたくない。。__
+
+スキップしましょう
+
+```php
+$this->repository->skipCriteria()->all();
+```
+
+削除もできるみたいですが用途は如何に。。
+
+```php
+$this->repository->popCriteria(Criteria1::class);
+```
+
+### まとめ
+
+チームにrepositoryを使う上での制約をもたらすには十分なのではないでしょうか
+
+簡単なクエリでrepositoryが変に膨らむこともないだろうし
+こちらで共通の処理を行う抽象的なメソッドを再発明しなくて
+済むのもいいですね。
+
+次回のプロジェクトではこいつ使ってみたいと思います。
+
+__RequestCriteriaやPresenters(オブジェクト出力のラッパー)
+Validatorなども便利なものがあるようですが今回は割愛__
+だってFormRequest今のところ便利だし。。笑
+
+### Model周りの疑問
+laravelはディレクトリ構成に自由が効くのでCriteriaなど
+どう運用していってるのか既にプラクティスがある方いれば
+是非教えていただきたいです。
+
+自分的にはrepositoryでsaveなど任せるのは
+違和感あるのでそこはmodelにやらせてました。
+ただ、modelを注入したサービスクラスを別に作るべきなのかとも思っています。
+みなさんどうしてるんでしょうか。笑
+
+
+
+
+
+
+
+
+
+
+