
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、最近はLaravel + Inertia
(React
&Vue 3
)の開発が多くなってきたのですが、やはりInertia
を使うとAPI
開発がすっとばせるので、とても快適に開発できています。
ただ、1点「うーん…」と思うことがありました。
それが・・・・・・
「Enum が JavaScript 側で参照できない」
というものです。
そりゃあ、Enum
はPHP
でセットしているものなので当然なんですが、毎回毎回ビューのパラメータにセットするのがメンドクサイんですよね…
こんなカンジですね。
↓↓↓
Inertia::render('Test', ['enum_values' => $enum_values]);
ちなみに、以前公開した「Laravel + Inertia + React で多言語化する」と同じようにページにアクセスするたびに自動でInertia
へデータを送ってもいいのですが、これも1点だけ「うーん…」なことがあったりします。
それは・・・・・・
「動的にデータ取得しているので、入力補完が効かない」
というものです。
つまり、(私が使っている)phpstorm
でデータを入力する時に毎回「えーっと、あれの値はなんだっけか??」とEnum
ファイルを見にいかないといけなくなってしまうわけです。
(例えば、「Food.」と入力した時点でカレーとかピザとかの候補が出てほしいんです)
そこで
一計を案じて、「Laravel
側のEnum
が自動的にInertia
側に渡されるようにする方法」を考えてみました。しかも入力補完にも対応してます。
ぜひ何かの参考になりましたら嬉しいです。
※ ちなみにPHP
のEnum
は8.1
から使える機能です。お気をつけください!
「神戸の名店ホルモン焼き
めちゃくちゃウマかった
ホルモン1本60円」
開発環境: PHP 8.1、Laravel 10.x、Vite、Inertia.js、React 18
目次 [非表示]
Enum(列挙型)をつくる
では、まずはInertia
側へ渡したいEnum
をつくります。
今回はわかりやすく「食べ物」に関するデータでつくってみましょう。
app/Enums/Food.php
<?php
namespace App\Enums;
enum Food: int
{
case Pizza = 1; // ピザ
case Pasta = 2; // パスタ
case Burger = 3; // ハンバーガー
case Curry = 4; // カレー
case Ramen = 5; // ラーメン
}
ちなみにEnum
とは、シンプルに言うと「定数(変更されないデータ)」をグループで管理できる機能です。
Enum のデータを JavaScript 化する Artisan コマンドをつくる
続いて、先ほどつくったEnum
をJavaScript
でも読み込めるようにするArtisan
コマンドをつくります。
以下のコマンドを実行してください。
php artisan make:command EnumToInertiaCommand
すると、Artisan
コマンド用のファイルが作成されるので中身を以下のように変更します。
app/Console/Commands/EnumToInertiaCommand.php
<?php
namespace App\Console\Commands;
use App\Enums\Food;
use Illuminate\Console\Command;
class EnumToInertiaCommand extends Command
{
protected $signature = 'enum_to_inertia';
protected $description = 'A command to convert enums to JavaScript';
// ここに変換したい Enum を追加する
private $converting_enums = [
Food::class,
];
public function handle(): void
{
$js_code = '';
foreach ($this->converting_enums as $converting_enum) {
$enum_name = last(
explode('\\', $converting_enum)
);
$cases = call_user_func($converting_enum .'::cases');
$js_code .= 'window.'. $enum_name .' = {' . "\n";
foreach ($cases as $case) {
$case_name = $case->name;
$case_value = $case->value;
$js_value = (is_string($case_value)) // 文字列の場合はクォートで囲む
? "'". $case_value ."'"
: $case_value;
$js_code .= ' "'. $case_name .'": '. $js_value .',' . "\n";
}
$js_code .= '};'. "\n";
}
$path = resource_path('js/Constants.js');
file_put_contents($path, $js_code);
$this->info('Done!');
}
}
この中では、$converting_enums
にセットされた全てのEnum
からデータを取得し、JavaScript
のコードを生成。そして、それをファイルConstants.js
へ保存するようにしています。
※ なお、今回はテストなのでkey-value
形式のみですが、JavaScript
ではオブジェクトの順番が保持できない(確約されていない)ので、実際にはコレクション形式のデータも合わせて生成するようにするといいでしょう。
コマンドがビルド時に自動実行されるようにする
では、先ほどのArtisan
コマンドがVite
のビルド時に自動的に実行されるようにします。
package.json
{
"private": true,
"scripts": {
"dev": "vite",
"build": "php artisan enum_to_inertia && vite build"
},
// 省略
ここでは、初期状態では以下のようになっている部分にphp artisan enum_to_inertia &&
を追加しています。
"build": "vite build"
こうすることで、ビルド時に以下2つの流れで実行されるようになります。
- Enum のデータを JavaScript 化
- 通常の Vite のビルド
ちなみに、今回はビルド時だけJavaScript
化されるようにしていますが、dev
でも同じように実行したい場合は以下のようにするといいでしょう。(時間がかかる可能性もあるので今回はビルド時のみにしました)
"dev": "php artisan enum_to_inertia && vite",
これで自動的にEnum
をJavaScript
化することができるようになりました。
定数の読み込み
続いて、先ほどのJavaScript
化した定数ファイルはそのままではVite
で有効になっていないので、app.jsx
へのセットしておきましょう。
import './bootstrap';
import '../css/app.css';
import { createRoot } from 'react-dom/client';
import { createInertiaApp } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import './Constants'; //
ここを追加しました
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
// 省略
さぁ、これで作業は全て完了です。
お疲れ様でした
テストしてみる
では、実際にテストしてみましょう
まずはEnum
の定数の中身を確認するためのページをササッとつくります。
routes/web.php
use Inertia\Inertia;
// 省略
Route::get('constants', fn() => Inertia::render('Constants'));
そして、ビューです。
resources/js/Pages/Constants.jsx
export default function Constants() {
const FoodKeys = Object.keys(Food);
return (
<div className="p-5">
{FoodKeys.map((key) => (
<div key={key}>{key}: {Food[key]}</div>
))}
</div>
);
}
さぁ、これで準備は整いました。
以下のコマンドでVite
のビルドを実行してみましょう。
npm run build
すると・・・・・・
はい
「Enum → JavaScript」化したConstants.js
が作成されました。
まずは成功です
ちなみに中身はこうなっていました。
window.Food = {
"Pizza": 1,
"Pasta": 2,
"Burger": 3,
"Curry": 4,
"Ramen": 5,
};
これで、グローバルな変数としてFood
が使えるようになりますね。
では、先ほどつくったテストページを実行してみましょう
うまくいくでしょうか・・・・・・
はい
うまくEnum
から取得したデータを表示することができました。
では、今回重要な点として冒頭でも書いた「入力補完」がうまくいくかを最後にチェックしてみましょう。
テストページの途中に「Food.」と入力してみます。
すると・・・・・・
はい
Enum
の入力補完がうまく働きました。
すべて成功です
企業様へのご提案
今回のように、PHP
側のデータをJavaScript
化することで、PHP
のデータをJavaScript
(今回はReact
)内で利用することができ、さらに入力補完も効くようにしているので、開発効率もあがること間違いなしです。
もしそういった効率的な開発を行いたい場合はぜひお問い合わせからご相談ください。
お待ちしております!
おわりに
ということで、今回はLaravel
でEnum
をJavaScript
化し、定数としてReact
内から参照できるようにしてみました。
ちなみに、今回はReact
でしたがやり方としては同じなのでVue
やsvelte
でも使えるんじゃないでしょうか。
また、今回のアイデアはうろ覚えなのですが、たしかlaravel-ide-helper
が同じような仕組みで実装してるんじゃなかったっけ…と思ったことが発端でした。(つまり、やり方としてはパクリです。天才たち、いつもありがとう!)
なお、今回の件で一点だけ気をつけていただきたいのが、「外に出してはいけないデータを定数化してしまう」ことです。
例えば、Laravel
のコンフィグにはキーなどが含まれているので安易に定数化することはしないでください。
便利さの裏にはセキュリティ上の懸念も存在するということですね。
ではでは〜
「シャウエッセンに
旨みひろがる香り白だしをかける
…神ですな」