🐘

[PHP][Laravel]Repositoryパターン適用例

2020/10/01に公開

published_at: 2019-04-23 07:59


これはなに?

  • Laravel での Repository パターンの実装例について記述したものです
  • Repository パターンそのものについては説明してません

情報

検証環境

  • macOS Mojave 10.14.4
  • Docker version 18.09.2, build 6247962
  • docker-compose version 1.23.2, build 1110ad01
  • PHP 7.3.3 (cli) (built: Mar 27 2019 01:21:44) ( NTS )
  • Laravel Framework 5.8.7

適用方法

(事前準備)検証用DB整備

  • Modified Files
    1. .env.example
      • DBコンテナ(db-host)に接続するように調整
      • ln -snf .env.example .env でシンボリックリンクにして .env を整備
  • Added Files
    1. server/database/migrations/2019_04_19_032013_create_fruits_table.php
      • マイグレーションコード
    2. server/database/seeds/FruitsTableSeeder.php
      • データシーダー
    3. server/app/Models/Fruit.php
      • モデルクラス
  • データ適用
    ❯ docker exec -it php bash
    
    root@3e0a1cbf0ad1:/var/www# php artisan migrate
    Migrating: 2019_04_19_032013_create_fruits_table
    Migrated:  2019_04_19_032013_create_fruits_table
    
    root@3e0a1cbf0ad1:/var/www# php artisan db:seed --class=FruitsTableSeeder
    Database seeding completed successfully.
    
    root@3e0a1cbf0ad1:/var/www# exit
    exit
    

実装調整

app/Providers

  • ServiceProvider追加
    • server/app/Providers/RepositoryServiceProvider.php
      • register メソッドに以下のような定義を追加
        // Fruit
        $this->app->bind(
            FruitRepositoryInterface::class,    //<- インターフェース
            FruitDbRepository::class            //<- 実体クラス:切り替えるならここを変える
        );
        
  • ServiceProviderのファイルを追加した場合、定義の追加が必要
    • server/config/app.php
      • providers に追加
            'providers' => [
                ・・・
                /*
                 * Application Service Providers...
                 */
                ・・・
                App\Providers\RepositoryServiceProvider::class,     //<- コレ
        

app/Repositories/Fruit

  • インターフェース
    • server/app/Repositories/Fruit/FruitRepositoryInterface.php
      • 必要なメソッドの定義のみ列挙
  • 実体クラス
    • server/app/Repositories/Fruit/FruitDbRepository.php
      • implements でインターフェースの実体クラスであることを宣言
      • インターフェースで定義したメソッドを全て実装
      • (わざわざ Fruit クラス(Model) を extends したが、 Fruit クラスを実体クラスにするのもありかもしれない)

ルーティング・コントローラー周り

  • ルーティング
    • server/routes/api.php
      • 呼び出すコントローラーへのエントリを追加
  • コントローラー
    • server/app/Http/Controllers/FruitController.php
      • index メソッドに、リポジトリパターンを使用せずにモデルクラスでDB内のデータを取得するメソッドを実装
        • see http://localhost/api/fruit/all
      • show メソッドに、リポジトリパターンを使用してDBからデータを取得するメソッドを実装
        • see http://localhost/api/fruit/[0|1|2|3]

今後の展開など

  • 例えば server/app/Repositories/Fruit/ に FruitCsvRepository.php のようなクラスを作成して、
    以下のように変更することで実体クラスを切り替えられるのではないかと思う。
    • データ処理メソッドを実装し、
      • implements FruitRepositoryInterface を FruitDbRepository から移動
      • FruitController のコンストラクタで new するのを FruitCsvRepository に変更
    • server/app/Providers/RepositoryServiceProvider.php で 実体クラスを FruitCsvRepository::class に切り替え
  • これを利用した安全なデータ運用ができそう、かと。
    • DB なくても CSV で、とか。(読み込み処理とか作成の必要ありますが)
    • 他にも、最終的には SSO にするシステムなんだけど、当面は手元の User テーブルで動作を試す場合などにも。

留意事項

  • autoloader がおかしい感じになったらコンテナに入って composer dump-autoload するなどが時には必要。
  • provider コードの生成は php artisan make:provider RepositoryServiceProvider で行うのが良さそう。

Discussion