はじめに
こんにちは。Laravelでenumを使いたい時、PHPやLaravel本体ではサポートされていないのでComposer経由でパッケージを入れることになります。
今は
bensampo/laravel-enum
を使っており、とりあえず不自由ない感じなので、紹介しようと思います。
enumについて
railsで初めてenumを知ったのですが、C言語の時点で既にあったのですね。
私は「限られた値しか持てないデータ型」と認識してます。
例えば注文情報テーブルに支払方法を保存する時、データベースの
orders
テーブルに
payment_type
カラムを持たせるとします。
card, transfer, cash
など支払方法名だけが
orders.payment_type
に入るようにしつつ、表示時は「クレジットカード」や「銀行振込」といった文字列で扱いたい…なんてケースはよくあると思いますが、こういう場合に便利です。
環境
- PHP 7.3.3
- Laravel 5.8
- laravel-enum 1.9
導入
composerコマンドでさくっとインストール完了です。
1 2 3 4 5 6 7 8 9 10 | $ composer require bensampo/laravel-enum Using version ^1.19 for bensampo/laravel-enum ./composer.json has been created Loading composer repositories with package information ... ... ... Writing lock file Generating autoload files |
enumクラス
生成
マイグレーションはenumクラスの後に作った方が(多分)効率が良いので、まずはenumクラスを生成します。
1 2 | $ php artisan make:enum PaymentType Enum created successfully. |
なおデフォルトでは
app/Enums
ディレクトリが生成され、その中にPHPファイルが自動生成されます。ディレクトリを切り分けたい場合、例えば
app/Enums/Order
に作りたいのであれば
Order/PaymentType
となります。
このパラメータ、
app/Enums
を起点とした相対パスとして扱われるので、例えば
$ php artisan make:enum ../Models/Enums/TestEnum
と記述すれば、
app/Models/EnumsTestEnum.php
が生成されます。
ディレクトリ構造はプロジェクトによって様々だと思いますので、お好みで。
enumクラス編集
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php // app/Enums/PaymentType.php namespace App\Enums; use BenSampo\Enum\Contracts\LocalizedEnum; use BenSampo\Enum\Enum; final class PaymentType extends Enum implements LocalizedEnum { const CREDIT_CARD = 'credit_card'; const TRANSFER = 'transfer'; const CASH = 'cash'; } |
日本語化
続いて公式の方法に従って
resources/lang/ja/enums.php
を作成し、以下のように記述します。フレームワークのlocale設定に従った
enums.php
を読みに行きますので、
config/app.php
の
locale
を日本(ja)に設定しておきましょう。
1 2 3 4 5 6 7 8 9 | <?php // config/app.php return [ // 中略 'locale' => 'ja', // 中略 ]; |
1 2 3 4 5 6 7 8 9 10 11 | <?php // resources/lang/ja/enums.php use App\Enums\PaymentType; return [ PaymentType::class => [ PaymentType::CREDIT_CARD => 'クレジットカード', PaymentType::TRANSFER => '銀行振込', PaymentType::CASH => '現金', ], ]; |
マイグレーション
生成
orders
テーブルに
payment_type
というenum型のカラムを追加します。
1 2 | $ php artisan make:migration add_column_payment_type --table=orders Created Migration: 2019_05_**_******_add_column_payment_type |
編集
$table->enum()
はLaravel 5.8から使用できます。直接指定できるのはいいですね。
また「マイグレーションはクラス作成の後で」と前述したのは、enum型カラムの定義にenumクラスの値を適用できるためです。もちろん配列をべた書きしてもいいのですが、この方がすっきり分かりやすいかなと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php // database/migrations/2019_05_**_******_add_column_payment_type.php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; use App\Enums\PaymentType; class AddColumnPaymentType extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('orders', function (Blueprint $table) { $table->enum('payment_type', PaymentType::getValues()) ->default(PaymentType::CREDIT_CARD) ->after('id'); }); } } |
プロパティのキャスト
Eloquent
ではモデルクラスのプロパティに定義することで、インスタンス生成時に別の型に自動キャストしてくれる機能があります。
protected $dates = [];
に入れておけば自動で
Carbon
にキャストしてくれるとか、そういうやつです。
laravel-enum
でも 同様の機能があり、以下のコードで自動キャストが可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php namespace App; use App\Enums\PaymentType; use Illuminate\Database\Eloquent\Model; class Order extends Model { protected $dates = [ 'created_at', 'updated_at' ]; protected $enumCasts = [ 'payment_type' => PaymentType::class, ]; } |
こうしておくことで何が嬉しいのかと言うと、以下のようにbladeでの記述が減ります。
1 2 3 4 5 | // 自動キャストしない場合 <span>{{PaymentType::getDescription($order->payment_type)}}</span> // 自動キャストする場合 <span>{{$order->payment_type->description}}</span> |
当初は自動キャストせず前者のように書いてたのですが
- 「いちいちstaticメソッド呼ぶのかったるいよね?」
- 「ていうかbladeでこの書き方はイマイチなのでは?」
- 「何かもっとスマートな書き方ないの?あるよね?」
と思い至り、調べた結果見つけた方法でした。
地味ですが少しでもコード量は減らしたいので!
さいごに
enum、いいですね。昔はこういった実装をする際、DBにマスターテーブル作ってconst.phpとか作って定数を列挙して…みたいなことをしてましたが、大抵const.phpが肥大化して管理が億劫になってました。定義がコード化されて気分がいいです。