私のLaravel実装構成の話

Laravelの実装って自由に構築できますが、ちゃんと決めて事をしないとソースがこんがらがります。
なので私流の構成をメモっておきます。
フレームワークとかたいそうなものではなく、こんな感じのルールで書いていますよって程度です

基本構成図

基本的な構成は以下で構成しています。

  • Controller
  • ControllerService
  • Service
  • Repository
  • Model

構成要素

ポイントは、LaravelオリジナルであるControllerとModelにはロジックを書きません!

  • Controller : Laravelがroute.apiとバインドさせている標準のやつ
    namespace : App\Http\Controllers
  • Model : Laravelでmake:modelで作成するDBアクセスエンティティ(にしている)
    namespace : App\Models

その代わりに、ロジックを書くのは私オリジナルであるControllerServiceとServiceとRepositoryに書きます。

  • ControllerService : Controllerでの処理を書きます。
    Controllerとは1:1です。
  • Repository : Modelへのアクセスはここでしか行いません。
    返却・引き渡し型はModelクラスを使うのではなく内部のオリジナルクラスを利用します
  • Service:何らかの処理を行います。

ルール

それぞれの要素でのルールをまとめておきます。

  • Contollerは自分専用のControllerServiceのみアクセスできます。
    Service / Repository / Modelにはアクセスできません。
  • ControllerServiceはControllerとServiceにアクセスできます。
    別のControllerServiceへはアクセスできません。
    別ControllerServiceにアクセスしたい場合は、その処理をServiceに昇華してください
  • Repository : Modelへのアクセスに専念ください。
    Serviceへの参照は基本しないでください
  • Controller : HTTPリクエストをそのままControllerServiceには渡さないでください。
    必ず独自のリクエストクラスに入れてください。
  • Repository : Modelクラスをそのまま引き回さないでください。
    IOはオリジナルクラスにしてください。

別サービスへのアクセス

  • 外部WebサービスなどへのアクセスはServiceに専用を作ってください。
    内部に組み込まれると試験がめんどくさいです。

IOをオリジナルクラスにする理由

ControllerにはRequestとViewなど、RepositoryにはModelがそれぞれ入出力されます。
しかし、これをそのままは使わず、
Requestクラスではなくリクエストを解析した後のクラスを作成します
Modelではなく内部のクラスにそれぞれ入れ替えます
理由としては入出力がオリジナルクラスにすることで仕様とクラスが一致する。
直接触れなくすることでDBアクセスなどの処理が散在することを防ぎます。

そもそも他人の家(Laravelオリジナル)には動作不明な点があるので…

関係図

多数の関係を書くとこの様になります。

Serviceはそれぞれの中間に位置して、Service – Service間の関係などもあります
ControllerにはControllerServiceを一つ
Modelには Repositoryが一つとなっています

Controllerをページと考えても問題ないかな?
Modelをテーブルと一致しているかな。

一番下のサービスは外部サービスを参照しているイメージです

流れなど

ばばばっと流れをまとめますと、以下の様なシーケンスになります。

赤札に書いている部分が型です。

ユーザとの境界線はilluminateなどLaravel提供のクラスです。
Controllerで内部用リクエストに変換することでService以降ではRequestをさわれません。
Model以降ではSQLでしょうが、それ以前にもRepositoryにラップすることにより、先の通り直接さわれなくしています

なぜそうするか。

もちろん不用意な改修をさせないのと、Unit試験のためです。
ControllerはFeature試験で確認しますが、Serviceだけを試験する時に責任範囲外のLaravelオリジナルクラスをいぢるのはちょい責任が持てません
同じことがModelでも言えます。Seeder使えば… とか思いますが、それはFeature試験だと思っています。

Unit試験でServiceを試験するにはMockでRepositoryを作って差し込んでするべきかと考えております。

終いに

私は結構この構成で作っています。
本来のLaravel利用者なら、Providerは?と思いますが…
なんとなく私がオリジナルで作ったServiceにしていますw
私の今後の学習範囲ですね。