Laravel 使用 Enums

原本有時數據庫中會使用enum()來取代 數字 tinyint,這樣更加明顯直觀

enum('low', 'medium', 'high')

不過我比較追求更高效率,以及希望數據庫更小

下面假設用一個 Invoice Model 來分享

以往會在config目錄建立

//config/common.php
<?php

return [
    'invoice_status' => [
        0 => '待批',
        1 => '已批',
        2 => '未付',
        3 => '已付',
    ],
]
//Blade使用
{{ config('common.invoice_status_label')[$data->status] }}

但每次明明是改Invoice的內容,但要去config?

後來發現原來可以這樣做...

為每個Model建立自己的Enums

1. 建立app/Enums/Invoice/Status.php

<?php

namespace App\Enums\Invoice;

enum Status: string
{
    case Pending = '0';  //待批
    case Approved = '1';  //待寄
    case Unpaid = '2';  //未付
    case Paid = '3';  //已付

    public function text(): string
    {
        return match($this) {
            self::Pending => '待批',
            self::Approved => '待寄',
            self::Unpaid => '未付',
            self::Paid => '已付',
        };
    }

    public function color(): string
    {
        return match($this) {
            self::Pending => 'bg-warning',
            self::Approved => 'bg-primary',
            self::Unpaid => 'bg-danger',
            self::Paid => 'bg-success',
        };
    }

    public function label(): string
    {
        return match($this) {
            self::Pending => '<span class="badge badge-warning align-middle">待批</span>',
            self::Approved => '<span class="badge badge-warning align-middle">已批待寄</span>',
            self::Unpaid => '<span class="badge badge-danger align-middle">未付</span>',
            self::Paid => '<span class="badge badge-success align-middle">已付</span>',
        };
    }
}

當然這邊的Pending、Approved 你改為 Status1, Status2 等等也是可以的

上面我分享了比較完整的Enums 一般大部分人你可以只保留 text() 就可以

2. 前往 Model 文件修改


use App\Enums\Invoice\Status;

protected $casts = [
    'status' => Status::class,
];

3. balde顯示

//直接顯示
{{$data->status->text()}}

//用路徑直接Foreach
<select>
    @foreach(\App\Enums\Invoice\Status::cases() as $item)
    <option value="{{$item->value}}">{{ $item->text() }}</option>
    @endforeach
</select>

4. 注意 & 方法2

上面之前這方法是把 $data->status 數一個純數字變成一個 object , 所以你頁面中如果有類似 @if($data->status==1) checked @endif 等判斷會完全失效,如果你想要取獲原本的數值,應該用 $data->status->value

如果你是新開發的系統或者小型系統,修改起來不太難

如果你不喜歡影響原本的$data->status 而產生一個新的物件,不希望大量去改原有系統的,只你想升級優化代碼結果,你可以不用$casts,而自己建立一個function,Model 中改成這樣

    protected $enums = [
        'status' => Status::class,
    ];

    public function __get($key)
    {
        if (str_ends_with($key, '_enum')) {
            $field = str_replace('_enum', '', $key);
            if (isset($this->enums[$field])) {
                return $this->enums[$field]::from($this->attributes[$field]);
            }
        }
        return parent::__get($key);
    }

這個改法,那麼你blade要這樣用

//顯示文字
{{$data->status_enum->text()}}

//顯示值
{{$data->status}}