閲覧が無い故に良いメモ帳と化したプログラマーブログ

主にphp関連の技術ブログ。閲覧が無い為、マークダウンが使える良いメモ帳と化している。誤ってアカウントパスワードを書いても大丈夫だ。なぜなら誰も閲覧しないからな。安心のブログシステムである。

LaravelでWEBサービスを立ち上げる為のテンプレートを用意する

概要

Laravelを用いてWebサービスを立ち上げる際の基本的な構成を用意する。 最近リポジトリパターンが流行っているようなので、その構成をテンプレート化しておいてすぐに使えるように用意しておく。 この構成にどんな意味があるかは手を動かしながら理解していってほしい。

1.プロジェクト作成 Laravel-Installerでプロジェクトを作成。

$ laravel new SampleProject

2.ディレクトリを追加する DBへのアクセスを担うRepositoriesと、ビジネスロジックを纏めるServicesを置くディレクトリを作成する。基本的にどこに配置してもいいが、よく見るのはappの配下に置くパターン。

├── app
│   ├── Console
│   ├── Exceptions
│   ├── Http
│   ├── Services // 追加
│   ├── Repositories // 追加
│   └── ...
├── bootstrap
├── config
├── ...
...

3.マイグレーションファイルの作成 今回は既存のUserテーブルに加えCompanyテーブルを用意する。下記のコマンドでモデルとマイグレーションファイルがセットで出来上がる。その後はphp artisan migrateでテーブルの作成を行う。

php artisan make:model CompaniesTable --migration
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCompaniesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('companies', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name', 100)->default("");
            $table->string('address', 200)->default("");
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('companies');
    }
}

4.コントローラーの作成 最近はRestApiでの開発がメインになりつつあるので下記でコントローラーを作成する。

php artisan make:controller CompanyController --resource

5.各ファイルの手配 2.で用意したSercices、Repositoriesディレクトリに下記のファイルを用意する。

・CompanyService.php // Servicesディレクトリ内に配置 ・CompanyRepository.php // Repositoriesディレクトリ内に配置 ・CompanyRepositoryInterface.php // Repositoriesディレクトリ内に配置

6.ロジックを組み立てる 下地が整ったので、あとはロジックを組み立てていく。まずはコントローラーにメソッドを記述する。ここでは同時にCompanyServiceを注入している。Companyが不動産関係なら所有物件の有無を確認し...といったビジネスロジックはCompanySrerviceに記述することになるので、コントローラーではCompanyServiceで「何をするか」が分かるように記述する。実際のロジックはCompanyServiceの中で記述すること。

<?php

namespace App\Http\Controllers;

use App\Http\Requests\CompaniesRequest;
use App\Services\CompanyService;

class CompanyController extends Controller
{

    /** @var companyService */
    protected $companyService;

    /**
     * @param CompanyService $companyService
     *
     */
    public function __construct(CompanyService $companyService)
    {
        $this->companyService = $companyService;
    }


    /**
     * Store a newly created resource in storage.
     *
     * @param  CompaniesRequest  $request
     * @return array
     */
    public function store(CompaniesRequest $request)
    {
        $company = $this->companyService->createCompany($request->only(["name", "address"]));

        return response()->json($company, 200);
    }

}

次にCompanyService.phpを作成していく。上で述べたように、ここにコントローラーで使うであろうメソッドを定義していく。上の流れに沿って不動産関係の会社でゴニョゴニョしたいならisEstateCompany()isOwner()など必要なメソッドをコントローラーを意識して用意する。

<?php


namespace App\Services;


use App\Repositories\CompanyRepositoryInterface;

class CompanyService
{
    protected $companyRepository;

    public function __construct(CompanyRepositoryInterface $companyRepository)
    {
        $this->companyRepository = $companyRepository;
    }

    public function createCompany($request)
    {
        return $this->companyRepository->createCompany($request);
    }

}

次にInterfaceを用意する。Interfaceはメソッドを保証する目的で作成する。例えばcreateCompanyはDBに会社を新規登録するメソッドである為、このInterfaceを実装するのはCompanyRepositoryになるが、CompanyRepositoryには必ずcreateCompany()が定義されていなければならない。なぜこのような面倒なことをするか、と言うのはこの後説明する。

<?php


namespace App\Repositories;


interface CompanyRepositoryInterface
{
    public function createCompany($request);

}

ここでAppServiceProvider.phpにこのInterfaceとRepositoryの紐付けを行う。Interfaceを使用する意味はここにある。ここではCompanyRepositoryInterfaceとCompanyRepositoryを紐付けているが、このRepositoryは差し替えが可能である。例えば.envがAPP_ENV=localならばCompanyRepositoryでAPP_ENV=productionならばApiCompanyRepositoryを使用するといったDBの切り替えをここで定義することができる。この他にも、例えば会社登録などほぼ固定化され変わることのないメソッドは必ず用意してくれと言う意味でもInterfaceの存在意味は出てくる。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->app->bind(\App\Repositories\CompanyRepositoryInterface::class, \App\Repositories\CompanyRepository::class);
    }
}

最後にCompanyRepositoryのコーディングを行う。ここではModelのCompany.phpを注入する。Modelにはリレーションやfillableなど基本的な共通事項を定義しておけばRepositoryを複数用意する場合にも便利だろう。

<?php


namespace App\Repositories;


use App\Company;

class CompanyRepository implements CompanyRepositoryInterface
{
    protected $company;

    public function __construct(Company $company)
    {
        $this->company = $company;
    }

    public function createCompany($request)
    {
        return $this->company->create($request);
    }
}

7.まとめ DBへのアクセスロジックはRepositoryへ、ビジネスロジックはServiceへ、コントローラーへは派生先で何が行われるかが見ただけで分かるようにするのが理想である。