【Laravel】 Repositoryを活用する

えびさん

Laravelにて、Controller側に直接書いてたModel処理をRepositoryに移動した

メリット
  • 各ファイルから呼び出すDB操作 (取得・追加・更新・削除)を共通化できる
  • DB操作に関するロジックをControllerのビジネスロジックから切り離すことで、
    メソッドがシンプルになり、処理の流れが読みやすくなる & 保守・拡張性が高まる
  • Repositoryのインターフェースで型指定をすることで、バグ防止にも繋がる
ざっくりとした流れ
  1. リポジトリディレクトリ&ファイルを作成
  2. ServiceProviderに登録し、config/app.phpに設定を追記
  3. Controller改修

まず、参考までに移動前のControllerを置いておく

  • ProjectController.php
<?php
namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Project;

class ProjectController extends Controller
{
    /**
     * @var App\Models\Project
     */
    private $project;

    public function __construct(Project $project) {
        $this->project = $project;
    }

    /**
     * 一覧
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function index()
    {
        $projects = $this->project->get()->orderBy('updated_at', 'desc');
        return response()->json(['projects' => $projects], 200, [], JSON_PRETTY_PRINT);
    }

    /**
     * 新規作成
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function store(Request $request)
    {
        $data = $request->all();
        $project = $this->project->create($data);
        $this->updateLabels($project, $data);

        return response()->json(['project' => $project], 200, [], JSON_PRETTY_PRINT);
    }

    protected function updateLabels(Project $project, array $data)
    {
      // ...省略
    }

これを切り分けるためにリポジトリ実装していく

1. リポジトリを入れるディレクトリを作成

mkdir app/Repositories
mkdir app/Repositories/Project

app/Repositoriesに全ファイル入れてもいいけど、
ファイルが増えてくるとみづらくなるため対象テーブルごとにディレクトリを分けてる

リポジトリファイル作成

  • インターフェースを生成: app/Repositories/Project/ProjectRepositoryInterface.php
<?php
namespace App\Repositories\Project;

use App\Models\Project;
use Illuminate\Database\Eloquent\Collection;

interface ProjectRepositoryInterface
{
    public function getAll(): Collection;
    public function store(array $data): Project;
}
  • ロジックファイルを生成: app/Repositories/Project/ProjectRepository.php
<?php
namespace App\Repositories\Project;

use App\Models\Project;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;

class ProjectRepository implements ProjectRepositoryInterface
{
    /**
     * @var App\Models\Project
     */
    private $project;

    public function __construct(Project $project) {
        $this->project = $project;
    }

    /**
     * 案件を全件取得する
     *
     * @return Collection
     */
    public function getAll(): Collection
    {
        return $this->project->get()->orderBy('updated_at', 'desc');
    }

    /**
     * 案件を登録する
     *
     * @param array $data
     * @return Project
     */
    public function store(array $data): Project
    {
        // 案件登録
        $project = $this->project->create($data);
        // ラベル更新
        $this->updateLabels($project, $data);

        return $project;
    }

    protected function updateLabels(Project $project, array $data)
    {
      // ...省略
    }
}

ServiceProviderに登録

わかりやすいように
Repository用のServiceProviderを新規作成する

php artisan make:provider RepositoryServiceProvider

register関数に作成したRepositoryファイルを追加していく

  • RepositoryServiceProvider.php
<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(
            \App\Repositories\Project\ProjectRepositoryInterface::class,
            \App\Repositories\Project\ProjectRepository::class
        );
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

作成したRepositoryServiceProviderを設定に追加

config/app.php
上記で作成したRepositoryServiceProviderを追加して読み込ませる

  • config.app.php
'providers' => [
// 省略
App\Providers\RepositoryServiceProvider::class, // 末尾に追加
]

新しく生まれ変わったControllerさん

  • ProjectController.php
<?php
namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Repositories\Project\ProjectRepositoryInterface as ProjectRepository;

class ProjectController extends Controller
{
    /**
     * @var ProjectRepository
     */
    private $projectRepository;

    public function __construct(ProjectRepository $projectRepository) {
        $this->projectRepository = $projectRepository;
    }

    /**
     * 一覧
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function index()
    {
       $projects = $this->projectRepository->getAll();
        return response()->json(['projects' => $projects], 200, [], JSON_PRETTY_PRINT);
    }

    /**
     * 新規作成
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function store(Request $request)
    {
        $project = $this->projectRepository->store($request->all());
        return response()->json(['project' => $project], 200, [], JSON_PRETTY_PRINT);
    }