PHP项目Laravel枚举类型数据库支持

wen PHP项目 5

本文目录导读:

PHP项目Laravel枚举类型数据库支持

  1. PHP 8.1+ 原生枚举 (推荐)
  2. 使用数据库原生 ENUM 类型
  3. 使用包:Spatie Enum Laravel
  4. 使用自定义 Model Casts
  5. 查询构建器中使用枚举
  6. 表单验证中的枚举支持
  7. Blade 模板中的渲染
  8. API 资源中的格式化
  9. 最佳实践建议

在 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(),
            ],
        ];
    }
}

最佳实践建议

  1. 使用 PHP 8.1+ 原生枚举,避免额外依赖
  2. 数据库层面使用 VARCHAR 而非原生 ENUM,便于迁移
  3. 总是使用枚举的 values() 方法 生成数据库约束
  4. 在 Model 中启用 casting,自动转换类型
  5. 为枚举添加标签方法,便于 UI 展示
  6. 使用 Laravel 9+ 的枚举验证规则

这种方法既保持了代码的可读性,又确保了数据库层面的数据完整性。

抱歉,评论功能暂时关闭!