本文目录导读:

- PHP 8.1+ 原生枚举 (推荐)
- 使用数据库原生 ENUM 类型
- 使用包:Spatie Enum Laravel
- 使用自定义 Model Casts
- 查询构建器中使用枚举
- 表单验证中的枚举支持
- Blade 模板中的渲染
- API 资源中的格式化
- 最佳实践建议
在 Laravel 项目中实现枚举类型的数据库支持,有几种不同的方案,以下是详细的实现方法和最佳实践:
PHP 8.1+ 原生枚举 (推荐)
定义枚举类
<?php
// app/Enums/UserRole.php
namespace App\Enums;
enum UserRole: string
{
case Admin = 'admin';
case User = 'user';
case Guest = 'guest';
// 添加额外方法
public function label(): string
{
return match($this) {
self::Admin => '管理员',
self::User => '普通用户',
self::Guest => '访客',
};
}
// 获取所有值
public static function values(): array
{
return array_column(self::cases(), 'value');
}
}
数据库迁移
<?php
// database/migrations/xxxx_create_users_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Enums\UserRole;
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->enum('role', UserRole::values())->default(UserRole::User);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
};
Model 使用
<?php
// app/Models/User.php
namespace App\Models;
use App\Enums\UserRole;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $casts = [
'role' => UserRole::class,
];
// 可选:添加查询作用域
public function scopeAdmins($query)
{
return $query->where('role', UserRole::Admin);
}
}
使用数据库原生 ENUM 类型
仅 MySQL/PostgreSQL 支持的迁移
<?php
// database/migrations/xxxx_create_orders_table.php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
public function up(): void
{
Schema::create('orders', function (Blueprint $table) {
$table->id();
// 原生 ENUM 类型(仅 MySQL)
$table->enum('status', ['pending', 'processing', 'completed', 'cancelled']);
// PostgreSQL 使用的 CHECK 约束
// $table->string('status')->default('pending');
// $table->check("status IN ('pending', 'processing', 'completed', 'cancelled')");
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('orders');
}
};
使用包:Spatie Enum Laravel
安装
composer require spatie/enum-laravel
创建枚举
php artisan make:enum StatusEnum
定义枚举
<?php
// app/Enums/StatusEnum.php
namespace App\Enums;
use Spatie\Enum\Laravel\Enum;
/**
* @method static self pending()
* @method static self processing()
* @method static self completed()
*/
final class StatusEnum extends Enum
{
protected static function values(): array
{
return [
'pending' => 'pending',
'processing' => 'processing',
'completed' => 'completed',
];
}
protected static function labels(): array
{
return [
'pending' => '待处理',
'processing' => '处理中',
'completed' => '已完成',
];
}
}
使用自定义 Model Casts
<?php
// app/Casts/EnumCast.php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use InvalidArgumentException;
class EnumCast implements CastsAttributes
{
protected $enumClass;
public function __construct(string $enumClass)
{
$this->enumClass = $enumClass;
}
public function get($model, string $key, $value, array $attributes)
{
return $this->enumClass::from($value);
}
public function set($model, string $key, $value, array $attributes)
{
if ($value instanceof $this->enumClass) {
return $value->value;
}
if (in_array($value, $this->enumClass::values())) {
return $value;
}
throw new InvalidArgumentException("Invalid value for enum {$this->enumClass}");
}
}
查询构建器中使用枚举
<?php
use App\Enums\UserRole;
use App\Models\User;
// 查询所有管理员
$admins = User::where('role', UserRole::Admin)->get();
// 使用作用域
$admins = User::admins()->get();
// 批量更新
User::where('role', UserRole::Guest)
->update(['role' => UserRole::User]);
// 比较枚举
$user = User::find(1);
if ($user->role === UserRole::Admin) {
// 执行管理员逻辑
}
表单验证中的枚举支持
<?php
// app/Http/Requests/UserRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Enums\UserRole;
use Illuminate\Validation\Rules\Enum;
class UserRequest extends FormRequest
{
public function rules(): array
{
return [
'role' => ['required', new Enum(UserRole::class)],
];
}
}
Blade 模板中的渲染
{{-- resources/views/users/show.blade.php --}}
@php
$user = \App\Models\User::find(1);
@endphp
用户角色:{{ $user->role->label() }}
{{-- 下拉选择框 --}}
<select name="role">
@foreach(\App\Enums\UserRole::cases() as $role)
<option value="{{ $role->value }}"
@selected($user->role === $role)>
{{ $role->label() }}
</option>
@endforeach
</select>
API 资源中的格式化
<?php
// app/Http/Resources/UserResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'role' => [
'value' => $this->role->value,
'label' => $this->role->label(),
],
];
}
}
最佳实践建议
- 使用 PHP 8.1+ 原生枚举,避免额外依赖
- 数据库层面使用 VARCHAR 而非原生 ENUM,便于迁移
- 总是使用枚举的 values() 方法 生成数据库约束
- 在 Model 中启用 casting,自动转换类型
- 为枚举添加标签方法,便于 UI 展示
- 使用 Laravel 9+ 的枚举验证规则
这种方法既保持了代码的可读性,又确保了数据库层面的数据完整性。