概要
LaravelでService層以外にRepositoryを導入している記事をいくつか見かけたので、実際にプロジェクトに導入してみました。
そもそも何か
ちゃっと 「Laravel Repository」と調べると色々出てきます。
デザパタのRepositoryパターンをLaravelで取り入れてみましょうみたいな内容
最初に結論、Eloquentモデルを活用したいなら取り入れない方がいい
public function hoge(User $user)
{
//処理
}
Userモデルの型としてcontrollerなどから受け取ったり、定義した場合Userモデルに依存する形になるのでRepositoryの
データの取得先がDBであっても外部のAPIであっても、それを意識することなくデータ操作を行うことが出来る
というRepositoryのメリットがまず死にます。
$user->hogehoge()
とかも勿論ダメ
Repositoryパターンを導入するという事は、Eloquentモデル関連の便利な機能を使わないという事でもあります。
例えば、ルートモデルバインディングとかも
自分は以下のようになんちゃってRepositoryを取り入れてみました。そして後悔しました。
定めたルール
- コントローラー、またはlivewireコンポーネントにはビジネスロジックを書かない
-
Modelクラス
には定義のみを書く - ビジネスロジックは
Serviceクラス
に書く - DB処理は
Repositoryクラス
に書く
処理の流れ
NG
NG
OK
Repositoryについて
Repository が永続化を担う対象は Entity(より厳密には集約)。
例えば、ユーザーの情報と、ユーザーのプロフィール画像(複数)がある場合、
1モデル1リポジトリで作成すると
- UserRepository
- UserImagesRepository
となるが、ユーザーのプロフィールはユーザーに集約出来る為
- UserRepository
の中にユーザーの画像取得や更新処理を書く。
Modelオブジェクトを使用しつつ治安維持、処理置き場としての目的※やめましょう
本来あるべきRepositoryパターンは出来ない(Eloquentと離れたくない)ので、「集約」 としての役割で使用しようと試みました。
- Userテーブル
- UserImageテーブル
- UserSettingテーブル
全てUserというドメインとして扱いたい為、各モデルに書く静的メソッド(Hoge::getHogeById()など)をUserRepositoryに全て集約させる。
モデルオブジェクトにはリレーションの定義などだけ記述する
=> モデル貧血症ポイント
Repositoryクラス外ではModelをデータとしてだけ扱い、Repositoryはデータベースアクセスの役割で扱う
=> ActiveRecordを無視する事になる
はい、思いついた時は良さそうと思ったんですが上記のルールはクソです。
Modelの振る舞いにデータベースアクセス系のメソッドがあるので役割がグチャグチャになります。
お気持ち
- ServiceからServiceの呼び出しを禁止にしたら流れが綺麗になると思った
- 綺麗になったのは流れだけ。
- Repositoryは必ずServiceクラスから呼ぶ
- ただの橋渡し処理が増えた、開発がしにくくなった。
- Serviceクラスは適切に分けないとあまり恩恵を感じない
ちゃんと取り入れようとしたらコストがめちゃかかる
中途半端に使うぐらいなら取り入れない方が良い。
本来あるべきRepositoryパターンを使いたければEloquent禁をしてまでやるメリットがあるかどうか考えましょう。
後工数がめちゃかかります。
どうしても使いたいなら・・・・
symphonyで使われているORマッパーです。
集約という目的は果たせます