Fat Controllerから脱しよう!ADRについて学ぶ!【実装編】

こんにちは!ドイです!

前回の記事では、ADRの概念について学びました。
今回は、LaravelでADRの実装をしたいと思います。

tech.arms-soft.co.jp

Action

Action:DomainとResponderの橋渡しを行う。Controllerとは異なり、「1つのクラスに対して、1アクションのみを持つ」。 クラスは増えるが、MVCで問題だったFat Controllerの状態を回避する。

__invoke():PHPのマジックメソッド。関数としてコールしようとした際にコールされる。また、ADRでは一つのメソッドに対して一つのActionが使用される。ルーティングを書く際にメソッド名を省略して記述することが可能。

<?php

namespace App\Http\Actions;

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use App\Domain\TestIndexDomain;
use App\Http\Responders\TestIndexResponder;

class TestIndexAction extends Controller
{
    protected $Domain;
    protected $Responder;

    public function __construct(TestIndexDomain $Domain, TestIndexResponder $Responder)
    {
        $this->Domain     = $Domain;
        $this->Responder  = $Responder;
    }

    /**
     * @param Request $request
     * @return Response
     */
    public function __invoke(Request $request): Response
    {
        return $this->Responder->response(
            $this->Domain->get()
        );
    }
}

Domain

Domain:ビジネスロジック、データの加工を行う。MVCでのModelに相当する。

<?php

namespace App\Domain;

use Illuminate\Support\Collection;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class TestIndexDomain
{
    public function get()
    {
        return [
            'name' => 'doi',
        ];
    }
}

Responder

Responder:Actionから受け取ったデータを、表示のため加工する。

<?php

namespace App\Http\Responders;

use Illuminate\Http\Response;
use Illuminate\Contracts\View\Factory as ViewFactory;

class TestIndexResponder
{
    protected $response;
    protected $view;

    public function __construct(Response $response, ViewFactory $view)
    {
        $this->response = $response;
        $this->view     = $view;
    }

    /**
     * @param $data
     * @return Response
     */
    public function response($data): Response
    {
        $this->response->setContent(
            $this->view->make('test.index', ['data' => $data])
        );
        return $this->response;
    }
}

Routing

Routing:Actionでも触れた通り、__invoke()を使用しているため、メソッド名を省略して記述する。

<?php

use Illuminate\Support\Facades\Route;

Route::get('/test', \App\Http\Actions\TestIndexAction::class);

確認

Hello!! {{ $data['name'] }}

http://localhost/testにアクセスすると、Domainで渡した値が表示されました。

まとめ

ADRで実装することができました。
小さな案件ではADRで実装するメリットがありませんが、Fat Controllerになりがちな大きな案件の際にADRで実装してみたいなと思います!!