フレームワークへの依存度を下げるFLUDパターン (3)
CodeIgniter Advent Calendar 2021
目次
- フレームワークへの依存度を下げるFLUDパターン (1) 概要
- フレームワークへの依存度を下げるFLUDパターン (2) Newsの表示
- フレームワークへの依存度を下げるFLUDパターン (3) 個別の記事の表示
- フレームワークへの依存度を下げるFLUDパターン (4) 記事の作成
- フレームワークへの依存度を下げるFLUDパターン (4.5) リファクタリング
- フレームワークへの依存度を下げるFLUDパターン (5) まとめ
フレームワークへの依存度を下げるFLUDパターン (2)
の続きです。
CodeIgniter4のチュートリアルのコードをFLUDパターンに変更しています。
次は、個別の記事の表示を変更します。
ドメイン層
NewsRepositoryInterface
NewsRepositoryInterface
に個別のNewsを取得するメソッドを追加します。
--- a/packages/news/src/Domain/News/NewsRepositoryInterface.php
+++ b/packages/news/src/Domain/News/NewsRepositoryInterface.php
@@ -10,4 +10,6 @@ interface NewsRepositoryInterface
* @return News[]
*/
public function getNewsList(): array;
+
+ public function getNewsBySlug(string $slug): ?News;
}
getNewsBySlug()
メソッドは指定されたslugに対して News
または null
を返します。
ユースケース層
GetNewsItemUseCase
News
を取得するユースケースを追加します。
packages/news/src/UseCase/News/GetNewsItemUseCase.php
<?php
declare(strict_types=1);
namespace Acme\News\UseCase\News;
use Acme\News\Domain\News\News;
use Acme\News\Domain\News\NewsRepositoryInterface;
class GetNewsItemUseCase
{
/**
* @var NewsRepositoryInterface
*/
private $newsRepository;
public function __construct(NewsRepositoryInterface $newsRepositry)
{
$this->newsRepository = $newsRepositry;
}
public function run(string $slug): ?NewsDto
{
/** @var News|null $news */
$news = $this->newsRepository->getNewsBySlug($slug);
if ($news !== null) {
return new NewsDto(
$news->id,
$news->title,
$news->slug,
$news->body
);
}
return null;
}
}
リポジトリから News
を取得した場合、NewsDto
に詰め替えて返しています。
フレームワーク/ライブラリ層
モデル
フレームワークのモデルです。
NewsRepository
NewsRepository
に getNewsBySlug()
メソッドを追加します。
--- a/app/Models/NewsRepository.php
+++ b/app/Models/NewsRepository.php
@@ -31,4 +31,22 @@ class NewsRepository extends Model implements NewsRepositoryInterface
return $newsList;
}
+
+ public function getNewsBySlug(string $slug): ?News
+ {
+ $stdClass = $this->where(['slug' => $slug])->asObject()->first();
+
+ if ($stdClass === null) {
+ return null;
+ }
+
+ $news = new News(
+ $stdClass->id,
+ $stdClass->title,
+ $stdClass->slug,
+ $stdClass->body
+ );
+
+ return $news;
+ }
}
CodeIgniter\Model
の first()
メソッドでデータベースから条件にマッチする最初のレコードを取得し、News
インスタンスに変換して返します。
コントローラ
フレームワークのコントローラです。
Newsコントローラ
view()
メソッドを GetNewsItemUseCase
を使うように変更します。
--- a/app/Controllers/News.php
+++ b/app/Controllers/News.php
@@ -5,6 +5,7 @@ namespace App\Controllers;
use App\Models\NewsRepository;
use Acme\News\UseCase\News\NewsDto;
use Acme\News\UseCase\News\GetNewsListUseCase;
+use Acme\News\UseCase\News\GetNewsItemUseCase;
class News extends BaseController
{
@@ -28,15 +29,16 @@ class News extends BaseController
public function view($slug = null)
{
- $model = model(NewsModel::class);
+ $repository = model(NewsRepository::class);
+ $useCase = new GetNewsItemUseCase($repository);
- $data['news'] = $model->getNews($slug);
+ $data['news'] = $useCase->run($slug);
if (empty($data['news'])) {
throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug);
}
- $data['title'] = $data['news']['title'];
+ $data['title'] = $data['news']->title;
echo view('templates/header', $data);
echo view('news/view', $data);
GetNewsItemUseCase
を生成し、実行しています。
view()
メソッド全体は以下のようになります。
public function view($slug = null)
{
$repository = model(NewsRepository::class);
$useCase = new GetNewsItemUseCase($repository);
$data['news'] = $useCase->run($slug);
if (empty($data['news'])) {
throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug);
}
$data['title'] = $data['news']->title;
echo view('templates/header', $data);
echo view('news/view', $data);
echo view('templates/footer', $data);
}
ビュー
フレームワークのビューです。
配列だった $news
を NewsDto
インスタンスに変えたため、プロパティを表示するようにコードを変更しています。
--- a/app/Views/news/view.php
+++ b/app/Views/news/view.php
@@ -1,2 +1,2 @@
-<h2><?= esc($news['title']) ?></h2>
-<p><?= esc($news['body']) ?></p>
+<h2><?= esc($news->title) ?></h2>
+<p><?= esc($news->body) ?></p>
これで、個別の記事も表示されるようになりました。
ディレクトリ構成
現状のディレクトリ構成は以下になります。
app/
├── Config
│ ├── Autoload.php
├── Controllers
│ ├── News.php
├── Models
│ └── NewsRepository.php
└── Views
└── news
├── overview.php
└── view.php
packages/
└── news ... Newsパッケージ
└── src
├── Domain ... ドメイン層
│ └── News
│ ├── News.php
│ └── NewsRepositoryInterface.php
└── UseCase ... ユースケース層
└── News
├── GetNewsItemUseCase.php ← 追加
├── GetNewsListUseCase.php
└── NewsDto.php
app/
以下のファイルはモデルのファイル名を変更しただけで配置はそのままにしています。
packages/
以下にドメイン層とユースケース層のコードが追加されています。
フレームワークへの依存度を下げるFLUDパターン (4)
へ続く。
Discussion