UseCaseクラスを用いてFatControllerを解消する
更新:2021/05/09 作成:2021/05/07
Fat Controller Laravel toutounode開発記録 Usecase
概要
MVCでアプリケーションを作ってるいると、Controller部分のコードが肥大化してしまうことがあります。ここではContollerではデータの処理などを行わずに、UseCaseクラスに処理を任せる例を紹介します。
Controllerでの処理をUseCaseクラスに任せる
ここでは例として、記事に紐づくタグの更新処理をUseCaseクラスに任せます。
Usecaseクラス導入前のコントローラ内の関数
関数内に記事に紐づくタグの更新処理が記述されていてスッキリしません。
public function update(Request $request, Article $article)
{
$article->fill($request->only('title', 'body', 'mdbody', 'state'))->save();
$article_id = $article->id;
$pre_tag_names = $article->tags()->pluck('name')->toArray();
$new_tag_names = $request->tags[0] == null ? [] : $request->tags;
//create Tag
foreach ($new_tag_names as $tag_name) {
Tag::firstOrCreate(['name' => $tag_name]);
}
//update articletag
$add_tag_names = array_diff($new_tag_names, $pre_tag_names);
$add_tag_ids = Tag::whereIn('name', $add_tag_names)->pluck('id');
foreach ($add_tag_ids as $tag_id) {
ArticleTag::firstOrCreate(['article_id' => $article_id, 'tag_id' => $tag_id]);
}
$delete_tag_names = array_diff($pre_tag_names, $new_tag_names);
$delete_tag_ids = Tag::whereIn('name', $delete_tag_names)->pluck('id');
ArticleTag::where('article_id', $article_id)->whereIn('tag_id', $delete_tag_ids)->delete();
return redirect(route('admin.article.manage'));
}
Usecaseクラスでのタグの更新処理
新たにapp\Usecases\Tag\UpdateArticleTags.php
を作成し、タグの更新処理を記述します。作成時にはpsr-4に従って、composer.json
でautoloadを登録していないApp
以外は、ファイルパスとnamespaseを大文字小文字も含めて一致させてください。
また、phpのマジックメソッドである __invokeメソッドはオブジェクトを関数として呼び出した際に呼び出される関数です。
<?php
namespace App\Usecases\Tag;
use App\ArticleTag;
use App\Tag;
class UpdateArticleTags
{
public function __invoke($article_id = null, $pre_tag_names = [], $new_tag_names = [])
{
//create Tag
foreach ($new_tag_names as $tag_name) {
Tag::firstOrCreate(['name' => $tag_name]);
}
//update articletag
$add_tag_names = array_diff($new_tag_names, $pre_tag_names);
$add_tag_ids = Tag::whereIn('name', $add_tag_names)->pluck('id');
foreach ($add_tag_ids as $tag_id) {
ArticleTag::firstOrCreate(['article_id' => $article_id, 'tag_id' => $tag_id]);
}
$delete_tag_names = array_diff($pre_tag_names, $new_tag_names);
$delete_tag_ids = Tag::whereIn('name', $delete_tag_names)->pluck('id');
ArticleTag::where('article_id', $article_id)->whereIn('tag_id', $delete_tag_ids)->delete();
return true;
}
}
上のコードだと、
$obj = new UpdateArticleTags;
$obj($article_id,$pre_tag_names,$new_tag_names);
でUsecaseの__invoke関数を呼び出せます。
Controller内でUsecaseクラスを利用
タグの更新処理が一行になったので大分スッキリしました。
use App\Article;
use Illuminate\Http\Request;
use App\Usecases\Tag\UpdateArticleTags;
~~~
public function update(Request $request, Article $article, UpdateArticleTags $updateTag)
{
$article->fill($request->only('title', 'body', 'mdbody', 'state'))->save();
$updateTag($article->id, $article->tags()->pluck('name')->toArray(), $request->tags[0] == null ? [] : $request->tags);
return redirect(route('admin.article.manage'));
}