くずきのblog

技術とか色々

Laravelでリポジトリーパターンを実装して見た感想

どうも、くずき(@kzkohashi)です。
Laravelを使い始めて1年くらいたちそうなので、いくつか試している実装パターンの感想でも書こうと思う。
今回は、Repositoryパターンについて書く。

Repositoryパターンとは?

Repositoryパターンとはビジネスロジックとデータ操作のロジックを分離し、データ操作のロジックを抽象化するパターンと認識してる。
例えばユーザーが新規登録したとして、今までだと

View -> UserController -> UserSerive(ビジネスロジック/データ操作)

Viewから受け取ったフォームデータをコントローラーで受け、サービス層で登録処理などをやっていたと思う。

それをRepositoryパターンにおきかえると

View -> UserController -> UserSerive(ビジネスロジック) -> UserRepository(データ操作)

このようになり、データ操作のロジックとビジネスロジックを分離する。
Repositoryパターンのほうの実装を簡単に書くと(Controllerは省略)

<?php

interface UserRepository
{

  public function create($name, $email, $password_hash);
  
}


class EloquentUserRepository implements UserRepository
{
  private $user;
  
  public function __construct(User $user)
  {
    $this->user = $user
  }
  
  public fucntion create($name, $email, $password_hash)
  {
    $data = [];
    $data['name'] = $name;
    $data['email'] = $email;
    $data['password] = $password_hash;
    
    return $this->user->create(data);
  }
}
<?php
class UserService
{
  private $user_repo;
  
  public function __construct(UserRepository $user_repo)
  {
    $this->user_repo = $user_repo;
  }
  
  public function regist($name, $email, $password)
  {
    $password_hash = bcrypt($password);
    $user = $user_repo->create($name, $email, $password_hash)
    $user->notify();
    
    return $user;
  }

}

注目すべきところはサービスからUserRepositoryが呼ばれているが、実装はEloquentUserRepositoryで行なっていること。
理由としてはインターフェースを通して実行することで、ORMによる依存を排除し、サービス側は実装の内容を意識しなくて良い。

f:id:kzkohashi:20180225230423p:plain 引用: https://terasolunaorg.github.io/guideline/public_review/ImplementationAtEachLayer/DomainLayer.html#id10

Laravelでの実装

簡単にテストまでの奴を書いた。

github.com

簡単に構成を説明すると、

  • インターフェース: App\Repositories
  • 実装: App\Infrastracture\Repositories
  • サービスコンテナの登録: App\Providers\RepositoryProvider

らへんを見てもらえるとリポジトリーパターンの実装の仕方がわかると思う。
リポジトリの作成は結構手間だけど、aiiroが実装してくれたコマンドを使えば容易に作れる。

php artisan app:make:repository ItemRepository

良かったところ

  • サービス層はデータ操作を除くビジネスロジックに集中できる
    • 何をやりたいかが見やすくなる
    • 永続先に依存するロジックを排除できる
  • DIにしたのでテストかきやすい

悪かったところ(反省点?)

  • Eloquentがサービス層に漏れている
    • 結局返す値がEloquentじゃデータ操作ができてしまう
    • 完璧なリポジトリーパターンを目指すには、Entityでのやりとりなどが必要

今後の改善点

リポジトリーパターンはDDDを行うための実装方法の一つで、実際すべてを行うのはなかなかしんどい。
なので次はEloquentの一部の値をValueObjectに置き換え、DDDに近づけていく。