九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、「プログラミング言語」と一口に言っても世の中にはPHP以外にもPyhonやJavaなどたくさんのものが存在しています。
そして、そんな他の言語を使ったことがある人なら、(きっと)思うこと。
それは・・・・・・
あっちの言語だったらできたのにな…😅
です。
結構前ですが、私はAndroidアプリを開発していたのですが、そのとき「これ便利だな」と感じていたのが今回テーマの
Enum(いーなむ)
です。
Enumとは、簡単にいうと「先にグループのメンバーを決めておく」仕組みです。
例えば、十二支で見てみましょう。
- 子
- 丑
- 寅
- 卯
- 辰
- 巳
- 午
- 未
- 申
- 酉
- 戌
- 亥
もちろんですが、この中には「パンダ」や「カモノハシ」は入ることはできません。もうグループ・メンバーが決定しているからです。
では、なぜグループ化するのかというと「予期せぬ値を扱わないようにできる」というメリットがあるからですね。
そして、長らくPHPにはこのEnumの機能がついていなかったのですが、実は次期バージョン8.1(2021.11.25 リリース予定)から使えるようになります。
そこで❗
今回は、Laravel + Enumでセレクトボックスをつくり、さらに、それを送信したときのバリデーションまで実装してみることにしました。
ぜひ何かの参考になりましたら嬉しいです。
※ なお、PHP 8.1のリリースの関係で記事公開の順番を変更させていただきました。「Laravel + Leaflet 地図で駅名検索できるようにする」は来週公開させていただきます。もし楽しみにしていただいていたらゴメンナサイ。m(_ _)m
「もうすぐ8.1リリースですよ👍」
開発環境: PHP 8.1.0(RC6)、Laravel 8.70
目次
選択肢について
今回Enumでつくる選択肢は「書籍のカテゴリ」で、以下のとおりです。
- 本
- 雑誌
- 新聞
では実際に作業を進めていきましょう❗
Enumをつくる
では、早速Enumをつくりましょう。
とはいっても、Enumはよく開発でもつかう「クラス」をもっとシンプルにしたものと考えて問題ないので、そんなに複雑ではありません。
実際のコードはこうなります。
app/Enums/Category.php
<?php
namespace App\Enums;
enum Category: int
{
// 基本情報
case Book = 1;
case Magazine = 2;
case Newspaper = 3;
// 日本語を追加
public function label(): string
{
return match($this)
{
Category::Book => '本',
Category::Magazine => '雑誌',
Category::Newspaper => '新聞',
};
}
}
まず、Enumで必ず必要になってくるのが「名前」で、今回では以下の3つになります。
- Book
- Magazine
- Newspaper
これだけでもEnumとしては使えるのですが、category_idとしてデータベースに保存することを想定しているので、今回はそれぞれ1〜3のIDを追加しています。
なお、
enum Category: int
と書いているのは、このIDが数値だからです。もし文字列を使いたい場合はstringになりますので、気をつけてください。(enumでは、TypeScriptみたいに型が重要になってきます)
そして、日本語環境ではセレクトボックスの選択肢に「Book」や「Magazine」と表示されるのはあまり使い勝手がいいとはいえません。
そのため、それぞれ日本語名を追加します。
それが、label()の部分です。(なお、labelという名前は好きに変更してOKですよ👍)
そして、以下のようにすると日本語名を取得できるようになります。
$label = Category::Book->label(); // 本
コントローラーをつくる
では、Enumのテスト用にコントローラーをつくります。
以下のコマンドを実行してください。
php artisan make:controller EnumController
すると、ファイルが作成されるので中身を以下のようにしてください。
app/Http/Controllers/EnumController.php
<?php
namespace App\Http\Controllers;
use App\Enums\Category;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Validation\Rule;
class EnumController extends Controller
{
public function create()
{
$categories = Category::cases();
return view('enum.create', compact('categories'));
}
public function store(Request $request)
{
$categories = Category::cases();
$category_ids = Arr::pluck($categories, 'value');
$request->validate([
'category_id' => ['required', Rule::in($category_ids)]
]);
return 'バリデーション通過しました!';
}
}
まず、create()では、先ほどつくったenumをビューに渡しています。
また、store()では選択されたIDが「事前にセットした3つの中に入っているか?」をチェックしています。
ビューをつくる
では、先ほど指定したビューをつくっていきましょう。
resources/views/enum/create.blade.php
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app" class="p-5">
<h1 class="mb-5">Enum(PHP 8.1 以上) を使って<br>選択肢をつくるサンプル</h1>
<div class="row">
<div class="col-4">
<form action="/enum" method="POST">
@csrf
<select name="category_id" class="form-control">
<option value="">▼ 以下から選択</option>
@foreach($categories as $category)
<option value="{{ $category->value }}">{{ $category->label() }}</option>
@endforeach
</select>
@error('category_id')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
<button type="submit" class="btn btn-primary mt-3">送信する</button>
</form>
</div>
</div>
</div>
</body>
</html>
この中で重要なのが、セレクトボックスをループでつくっているところです。
つまり、今回の場合で言うと、以下のようにすることでそれぞれの値を取得することができます。
- $category->name: Book、Magazine、Newspaper
- $category->value: 1、2、3
- $category->label(): 本、雑誌、新聞
そして、これを使えばJavaScript側にも配列やオブジェクトでEnumの中身を使えるようになるというわけですね。
ルートをつくる
では、コントローラーでつくったメソッドをルートとして登録しておきましょう。
use App\Http\Controllers\EnumController;
// 省略
Route::get('enum/create', [EnumController::class, 'create']);
Route::post('enum', [EnumController::class, 'store']);
これで作業は完了です❗
お疲れ様でした😄✨
ちなみに: JavaScript 側へセットするには
ちなみに、例えばVue 3にEnumの中身をセットする場合は次のようになります。
Vue.createApp({
data() {
return {
categories: [
@foreach($categories as $category)
{
id: {{ $category->value }},
name: '{{ $category->name }}',
label: '{{ $category->label() }}'
},
@endforeach
]
}
},
}).mount('#app');
また、以下のようにkey-value形式のオブジェクトにすることもできます。
Vue.createApp({
data() {
return {
categories: {
@foreach($categories as $category)
{{ $category->value }}: '{{ $category->label() }}',
@endforeach
}
}
},
}).mount('#app');
テストしてみる
では、実際にテストしてみましょう❗
「https://******/enum/create」へブラウザからアクセスしてください。

すると、セレクトボックスが表示されるので、この中から「本」を選択肢、送信してみましょう。

すると・・・・・・
![]()
はい❗
うまくバリデーションを通過できました。
ただ、これだけでは本当にちゃんとEnum以外のものを拒否してくれるのかわからないので、次に選択肢にない「技術書」をわざとセレクトボックスに追加して送信してみましょう。
<select name="category_id" class="form-control">
<option value="">▼ 以下から選択</option>
@foreach($categories as $category)
<option value="{{ $category->value }}">{{ $category->label() }}</option>
@endforeach
<!-- ⚠ これは Enum には入っていない選択肢です! -->
<option value="999">技術書</option>
</select>
では、もう一度リロードして選択しなおします。

どうなったでしょうか・・・・・・

はい❗
バリデーション・メッセージは英語のままですが、うまくエラーを表示してくれました。
成功です😄✨
企業様へのご提案
今回のように、「これしかありえない選択肢」を使うことで、より想定外の出来事が起きにくいコードを書くことができます。
また、Enumは使い回しもしやすいですので、開発の効率化にも役立つかと思います。
もしそういったご依頼がございましたら、お気軽にお問い合わせからご連絡ください。
どうぞよろしくお願いいたします。m(_ _)m
おわりに
ということで、今回はPHP 8.1から使えるようになるEnumをLaravelで使ってみました。
これまでグループ化された定数を使う場合、以下のようにモデルの中に入れるパターンや、Laravelのconfigフォルダの中にセットするパターンが多かったかもしれませんが、これからはEnumを使うのもありじゃないでしょうか。
class Category extends Model
{
use HasFactory;
const BOOK = 1;
const MAGAZINE = 2;
const NEWSPAPER = 3;
const CATEGORIES = [
self::BOOK => '本',
self::MAGAZINE => '雑誌',
self::NEWSPAPER => '新聞',
];
}
ぜひ、みなさんも一度試してみてくださいね。
ではでは〜❗

「この標識に勇気づけられました。
挫折禁止 😂✨」





