Laravelでリポジトリーパターンを使う

## 実装

### 基本的なファイルを作成

```bash
# Model, Controller, Migration, Seederファイルを作成 
php artisan make:model [Model名] -crms
```

### Interfaceを作成

```php
// app/Interfaces/TaskInterface.php

namespace App\Interfaces;

interface TaskInterface
{
    public function index();
    public function store(array $data);
    public function show(string $id);
    public function update(string $id, array $data);
    public function destroy(string $id);
}
```

### Serviceを作成

```php
// app/Services/TaskService.php

namespace App\Services;

use App\Interfaces\TaskInterface;

class TaskService
{
	// メンバ変数にセット
  public function __construct(TaskInterface $taskInterface)
  {
    $this->taskInterface = $taskInterface;
  }

  public function index()
  {
	  // インターフェースで定義したメソッドを呼び出す
    return $this->taskInterface->index();
  }
}
```

- `TaskInterface` をコンストラクタに渡してメンバ変数にセット
- 各メソッドでインターフェースで定義したメソッドを呼び出す

### ControllerからServiceを読み込む

```php
// app/Http/Controllers/Task/TaskController.php

namespace App\Http\Controllers\Task;

use App\Http\Controllers\Controller;
use App\Models\Task\Task;
use App\Services\TaskService;
use Illuminate\Http\Request;

class TaskController extends Controller
{
    public function __construct(TaskService $taskService)
    {
		    // コンストラクタに渡してメンバ変数にセット
        $this->taskService = $taskService;
    }

    public function index()
    {
		    // サービスで定義したメソッドを呼び出す
        return $this->taskService->index();
    }
}
```

- `TaskService` をコンストラクタに渡してメンバ変数にセット
- 各メソッドでサービスで定義したメソッドを呼び出す

### Repositoryを作成

```php
//app/Repositories/TaskRepository.php

namespace App\Repositories;

use App\Interfaces\TaskInterface;
use App\Models\Task\Task;

class TaskRepository implements TaskInterface
{
    public function index()
    {
        return Task::all();
    }
}
```

- `TaskInterface` を元に具体的な処理を実装

### InterfaceとRepositoryを紐付ける

上記コマンドを実行

```php
php artisan make:provider RepositoryServiceProvider
```

コマンドを実行すると 

- `/app/Provider` ディレクトリに `RepositoryServiceProvider.php`ファイルが生成
- `/bootstrap/providers.php` に生成されたプロバイダクラスが読み込まれる

```php
// bootstrap/providers.php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\AuthServiceProvider::class,
    App\Providers\RepositoryServiceProvider::class, // 追加される
];
```

生成された `RepositoryServiceProvider.php`ファイルの `register` メソッドに追記する

```php
// app/ProviderRepositoryServiceProvider.php

namespace App\Providers;

use App\Interfaces\TaskInterface;
use App\Repositories\TaskRepository;
use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        // 追加（InterfaceとRepositoryを紐付け）
        $this->app->bind(TaskInterface::class, TaskRepository::class);
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        //
    }
}
```

一応オートロードしといたほうがいいかも

```php
composer dump-autoload
```

## 考察
- 仮にDBの保存先をMySQLからFirestoreへ変更になったとしても、レポジトリファイルを作成 + プロバイダでバインドするクラスを書き換えれば対応が可能になる
- ビジネスロジックやユースケースのコードを修正する必要がなくなる
- よって保守性・拡張性の高いコードになると感じた

## 参考
 [Laravel - The PHP Framework For Web Artisans](https://laravel.com/docs/11.x/providers)

[Laravelアプリケーションでリポジトリパターンを使う方法](https://www.twilio.com/ja-jp/blog/repository-pattern-in-laravel-application-jp)

[akippaで採用しているLaravelのデザインパターンのお話：後編｜村上 健一郎](https://note.com/akippa_murakami/n/n8a342ab86e09)