LaravelでEnumを使ってblade上のマジックナンバーを書き換える。(bensampo/laravel-enum)

どうも、たかふみです

個人で開発中のアプリケーションでEnumを使ってみました。
Enumは業務で携わったプロジェクトでも使っていたので、さらに理解を深めるために個人的にも使ってみようと思ったのがきっかけです。

Ben Sampsonさんの`BenSampo/laravel-enum`で実装を行いました。

### 開発環境

```version.sh
root@ade420a5446f:/work/backend# php artisan --version
Laravel Framework 9.3.1

root@ade420a5446f:/work/backend# php --version
PHP 8.1.1 (cli) (built: Dec 18 2021 00:38:05) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.1, Copyright (c) Zend Technologies
```


## Enumとは
列挙型と呼ばれるデータ型の一つ。
複数の定数を一つのクラスとしてまとめることができる。


## 使用箇所

|id|カテゴリー名|
|-|-|
|1|野菜|
|2|肉|
|3|魚|


DBに「材料のカテゴリー」マスターテーブルがあります。
材料の情報を画面で表示する際に **"その材料がどのカテゴリーなのか"** を判別して該当する画像を表示します

>例)
「にんじん」を表示
にんじん （ingredient_category_id = 1）
→材料カテゴリーのid=1である”野菜”の画像を画面上に表示する

## 対応前の実装

``` blade.php
@if ($recipeIngredients->ingredient_category_id === 1)
	<img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/vegetable.png') }}" alt="vegetable"/>
@elseif ($recipeIngredients->ingredient_category_id === 2)
	<img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/meat.png') }}" alt="meat"/>
@elseif ($recipeIngredients->ingredient_category_id === 3)
	<img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/fish.png') }}" alt="fish"/>
@endif
```

上記実装の問題点は以下2点あります。
・DB内のidを変えたいときにはblade内のidも修正する必要がある
・blade.phpだけを見ても、どのidがどのカテゴリーか分からない。正しい画像が表示されているのか分からない

画面上にマジックナンバーが記載されているのもイマイチですね。これをEnum使って改善していきます。

# Enumのインストール&作成
公式のREADMEい従い、インストール。

```
composer require bensampo/laravel-enum
```

インストールできたら、材料カテゴリーのEnumを記載するファイルを作成。

```
php artisan make:enum IngredientCategory
```

内容をDBの内容に合わせて変更していきます。

```IngredientCategory.php
<?php

declare(strict_types=1);

namespace App\Enums;

use BenSampo\Enum\Enum;

final class IngredientCategory extends Enum
{
    const VEGETABLE = 1;
    const MEAT = 2;
    const FISH = 3;

		/*
     * @param int $id 材料カテゴリーID
     * @return stirng 材料カテゴリー名
	  */
    public static function getIngredientCategoryName(int $id = null)
    {
        if ($id === self::VEGETABLE) {
            return '野菜';
        }

        if ($id === self::MEAT) {
            return '肉';
        }

        if ($id === self::FISH) {
            return '魚';
        }
    }
}
```

Enumファイルができたので、早速他のファイルに書いていきましょう。

# 他ファイルの対応

### InitialDatabaseSeeder.php

まずは、DBにマスターデータを入れるSeederをEnumを使って書き換えます。

``` 変更前.php
// 材料カテゴリーのマスターデータ作成
$ingredientCategories = [
    [
        // id = 1
        'ingredient_category_name' => '野菜',
    ],
    [
        // id = 2
        'ingredient_category_name' => '肉',
    ],
    [
        // id = 3
        'ingredient_category_name' => '魚',
    ],
];

DB::table('ingredient_categories')
    ->insert($ingredientCategories);
```

↓

```変更後.php
// 材料カテゴリーのマスターデータ作成
$ingredientCategories = [];
for ($i=1; $i<=3; ++$i) {
    $ingredientCategories[] = [
        'ingredient_category_name' => IngredientCategory::getIngredientCategoryName($i),
    ];
}

DB::table('ingredient_categories')
    ->insert($ingredientCategories);
```

### blade.php

画面上の画像表示仕分けも書き換えていきます。

``` 変更前.php
@if ($recipeIngredients->ingredient_category_id === 1)
	<img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/vegetable.png') }}" alt="vegetable"/>
@elseif ($recipeIngredients->ingredient_category_id === 2)
	<img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/meat.png') }}" alt="meat"/>
@elseif ($recipeIngredients->ingredient_category_id === 3)
	<img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/fish.png') }}" alt="fish"/>
@endif
```

↓

```変更後.php
@if ($recipeIngredients->ingredient_category_id === App\Enums\IngredientCategory::VEGETABLE)
    <img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/vegetable.png') }}" alt="vegetable"/>
@elseif ($recipeIngredients->ingredient_category_id === App\Enums\IngredientCategory::MEAT)
    <img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/meat.png') }}" alt="meat"/>
@elseif ($recipeIngredients->ingredient_category_id === App\Enums\IngredientCategory::FISH)
    <img class="detailIngredientItemImage" src="{{ asset('images/ingredientCategory/fish.png') }}" alt="fish"/>
@endif
```

マジックナンバー直書きの箇所をEnumを使って書き換えました。
プロパティ名と画像名を関連づけられるので画像間違いの実装は無くなりそうです。

ただ、blade上にクラス名を記載するのはどうなんですかね...？
調べた限りだと良い方法が無かったので妥協案として実装しましたが、他に綺麗な書き方が合えればコメントいただきたいです。


個人的には、以下の状態にできたのでEnum使って良かったなと思っています。
>・Enumについての処理を加えたいならEnumのファイルへ追記する
・blade上にマジックナンバーを直書きしていない
・材料カテゴリーマスターの情報はEnumファイルを見れば良い

それでは！

>参考サイト
・BenSampo/laravel-enum
https://github.com/BenSampo/laravel-enum