🔥

フレームワークへの依存度を下げるFLUDパターン (4)

2021/12/23に公開

CodeIgniter Advent Calendar 2021

目次

フレームワークへの依存度を下げるFLUDパターン (3)
の続きです。

CodeIgniter4のチュートリアルのコードをFLUDパターンに変更しています。

最後は、記事の作成です。

ドメイン層

NewsRepositoryInterface

NewsRepositoryInterface にNewsを追加するメソッドを追加します。

--- a/packages/news/src/Domain/News/NewsRepositoryInterface.php
+++ b/packages/news/src/Domain/News/NewsRepositoryInterface.php
@@ -12,4 +12,6 @@ interface NewsRepositoryInterface
     public function getNewsList(): array;
 
     public function getNewsBySlug(string $slug): ?News;
+
+    public function addNews(News $news): void;
 }

addNews() メソッドは渡された News をリポジトリに追加(保存)します。

ユースケース層

CreateNewsUseCase

News を作成するユースケースを追加します。

packages/news/src/UseCase/News/CreateNewsUseCase.php

<?php

declare(strict_types=1);

namespace Acme\News\UseCase\News;

use Acme\News\Domain\News\News;
use Acme\News\Domain\News\NewsRepositoryInterface;

class CreateNewsUseCase
{
    /**
     * @var NewsRepositoryInterface
     */
    private $newsRepository;

    public function __construct(NewsRepositoryInterface $newsRepositry)
    {
        $this->newsRepository = $newsRepositry;
    }

    public function run(string $title, string $slug, string $body): void
    {
        $news = new News(
            null,
            $title,
            $slug,
            $body,
        );

        $this->newsRepository->addNews($news);
    }
}

渡されたデータを元に News インスタンスを作成し、リポジトリに保存します。

フレームワーク/ライブラリ層

モデル

フレームワークのモデルです。

NewsRepository

NewsRepositoryaddNews() メソッドを追加します。

--- a/app/Models/NewsRepository.php
+++ b/app/Models/NewsRepository.php
@@ -49,4 +49,17 @@ class NewsRepository extends Model implements NewsRepositoryInterface
 
         return $news;
     }
+
+    public function addNews(News $news): void
+    {
+        $id = $this->insert([
+            'title' => $news->title,
+            'slug' => $news->slug,
+            'body' => $news->body,
+        ]);
+
+        if ($id === false) {
+            throw new RuntimeException('Failed to insert news.');
+        }
+    }
 }

CodeIgniter\Modelinsert() メソッドでテーブルに挿入しています。

コントローラ

フレームワークのコントローラです。

Newsコントローラ

create() メソッドを CreateNewsUseCase を使うように変更します。

--- a/app/Controllers/News.php
+++ b/app/Controllers/News.php
@@ -6,6 +6,7 @@ use App\Models\NewsRepository;
 use Acme\News\UseCase\News\NewsDto;
 use Acme\News\UseCase\News\GetNewsListUseCase;
 use Acme\News\UseCase\News\GetNewsItemUseCase;
+use Acme\News\UseCase\News\CreateNewsUseCase;
 
 class News extends BaseController
 {
@@ -47,17 +48,18 @@ class News extends BaseController
 
     public function create()
     {
-        $model = model(NewsModel::class);
+        $repository = model(NewsRepository::class);
+        $useCase = new CreateNewsUseCase($repository);
 
         if ($this->request->getMethod() === 'post' && $this->validate([
             'title' => 'required|min_length[3]|max_length[255]',
             'body'  => 'required',
         ])) {
-            $model->save([
-                'title' => $this->request->getPost('title'),
-                'slug'  => url_title($this->request->getPost('title'), '-', true),
-                'body'  => $this->request->getPost('body'),
-            ]);
+            $title = $this->request->getPost('title');
+            $slug  = url_title($this->request->getPost('title'), '-', true);
+            $body  = $this->request->getPost('body');
+
+            $useCase->run($title, $slug, $body);
 
             echo view('news/success');
         } else {

CreateNewsUseCase を生成し、実行しています。

create() メソッド全体は以下のようになります。

    public function create()
    {
        $repository = model(NewsRepository::class);
        $useCase = new CreateNewsUseCase($repository);

        if ($this->request->getMethod() === 'post' && $this->validate([
            'title' => 'required|min_length[3]|max_length[255]',
            'body'  => 'required',
        ])) {
            $title = $this->request->getPost('title');
            $slug  = url_title($this->request->getPost('title'), '-', true);
            $body  = $this->request->getPost('body');

            $useCase->run($title, $slug, $body);

            echo view('news/success');
        } else {
            echo view('templates/header', ['title' => 'Create a news item']);
            echo view('news/create');
            echo view('templates/footer');
        }
    }

これで、記事の作成ができるようになりました。

ディレクトリ構成

現状のディレクトリ構成は以下になります。

app/
├── Config
│   ├── Autoload.php
├── Controllers
│   ├── News.php
├── Models
│   └── NewsRepository.php
└── Views
     └── news
          ├── create.php
          ├── overview.php
          ├── success.php
          └── view.php

packages/
└── news ... Newsパッケージ
     └── src
         ├── Domain ... ドメイン層
         │   └── News
         │       ├── News.php
         │       └── NewsRepositoryInterface.php
         └── UseCase ... ユースケース層
             └── News
                 ├── CreateNewsUseCase.php  ← 追加
                 ├── GetNewsItemUseCase.php
                 ├── GetNewsListUseCase.php
                 └── NewsDto.php

app/ 以下のファイルはモデルのファイル名を変更しただけで配置はそのままにしています。

packages/ 以下にドメイン層とユースケース層のコードが追加されています。

フレームワークへの依存度を下げるFLUDパターン (4.5)
へ続く。

参考

Discussion