はじめに
この記事では、Laravel内でコントローラーからビジネスロジックを切り離す方法について書く。具体的には、ビジネスロジックの分離にUsecaseというアプローチを導入する。
ちびキャラパレットのトップページを例に取り上げ、バックエンドから取得した最新の20件とランダムな20件の投稿をフロントエンドに表示する機能を改善した。
対象となる画面
ちびキャラパレットのトップページ
修正前のコード
app/Http/Controllers/TopController.php
class TopController extends Controller
{
public function index()
{
$latestPosts = Post::with('user', 'user.avatars')
->latest()
->limit(20)
->get();
$latestPostIds = $latestPosts->pluck('id')->toArray();
$randomPosts = Post::with('user', 'user.avatars')
->whereNotIn('id', $latestPostIds) // 最新20件のIDを除外する
->inRandomOrder()
->limit(20)
->get();
return view('top.index', [
'latestPosts' => $latestPosts,
'randomPosts' => $randomPosts,
]);
}
}
修正方針
改善すべき点
- ビジネスロジックをコントローラーから分離する
- DBからデータを取得する処理はModel層に実装し、ビジネスロジックとDBアクセスを分離する
ディレクトリ構造
app/
├── Http/
│ └── Controllers/
│ └── TopController.php
├── Models/
│ └── Post.php
└── Usecase/
└── Top/
└── IndexAction.php
修正後のコード
app/Http/Controllers/TopController.php
class TopController extends Controller
{
public function index(IndexAction $action): View
{
$posts = $action();
return view('top.index', [
'latestPosts' => $posts['latestPosts'],
'randomPosts' => $posts['randomPosts'],
]);
}
}
app/Models/Post.php
public static function getLatestPosts()
{
return static::with('user', 'user.avatars')
->latest()
->limit(20)
->get();
}
public static function getRandomPostsExcluding($postIds)
{
return static::with('user', 'user.avatars')
->whereNotIn('id', $postIds)
->inRandomOrder()
->limit(20)
->get();
}
app/Usecase/Top/IndexAction.php
class IndexAction
{
public function __invoke()
{
$latestPosts = Post::getLatestPosts();
$latestPostIds = $latestPosts->pluck('id')->toArray();
$randomPosts = Post::getRandomPostsExcluding($latestPostIds);
return [
'latestPosts' => $latestPosts,
'randomPosts' => $randomPosts,
];
}
}