Laravel enum implementation has revolutionized how developers handle fixed value sets in modern web applications. With PHP 8.1 enum Laravel integration, you can now create type-safe, maintainable code that eliminates magic strings and provides better IDE support. This tutorial walks you through practical implementation steps, real-world examples, and proven optimization strategies.
PHP enum Laravel support was introduced with Laravel 9, leveraging PHP 8.1's native enum functionality. Unlike traditional constants or database enum columns, Laravel enum casting provides type safety, better performance, and enhanced developer experience.
Before implementing Laravel enum in your project, ensure you have:
Create a new Laravel project or use an existing one:
composer create-project laravel/laravel laravel-enum-demo
cd laravel-enum-demo
Create a migration for our example product catalog system:
php artisan make:migration create_products_table
Database Migration with Enum-Compatible Column:
// database/migrations/create_products_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description');
$table->string('status', 20)->default('draft');
$table->string('category', 30)->index();
$table->decimal('price', 10, 2);
$table->timestamps();
// Add database index for better performance
$table->index('status');
});
}
public function down(): void
{
Schema::dropIfExists('products');
}
};
Run the migration:
php artisan migrate
Create an enum directory and your first enum class:
mkdir -p app/Enums
Creating Your First Laravel Enum:
// app/Enums/ProductStatusEnum.php
namespace App\Enums;
enum ProductStatusEnum: string
{
case DRAFT = 'draft';
case PUBLISHED = 'published';
case ARCHIVED = 'archived';
case DELETED = 'deleted';
// Add helper methods for better usability
public function label(): string
{
return match($this) {
self::DRAFT => 'Draft',
self::PUBLISHED => 'Published',
self::ARCHIVED => 'Archived',
self::DELETED => 'Deleted',
};
}
public function color(): string
{
return match($this) {
self::DRAFT => 'gray',
self::PUBLISHED => 'green',
self::ARCHIVED => 'yellow',
self::DELETED => 'red',
};
}
public static function active(): array
{
return [self::DRAFT, self::PUBLISHED];
}
}
Advanced Category Enum Example:
// app/Enums/ProductCategoryEnum.php
namespace App\Enums;
enum ProductCategoryEnum: string
{
case ELECTRONICS = 'electronics';
case CLOTHING = 'clothing';
case BOOKS = 'books';
case HOME_GARDEN = 'home-garden';
public function icon(): string
{
return match($this) {
self::ELECTRONICS => 'fas fa-laptop',
self::CLOTHING => 'fas fa-tshirt',
self::BOOKS => 'fas fa-book',
self::HOME_GARDEN => 'fas fa-home',
};
}
}
Create and configure your Eloquent model with Laravel enum casting:
php artisan make:model Product
<!--?php
// app/Models/Product.php
namespace App\Models;
use App\Enums\ProductCategoryEnum;
use App\Enums\ProductStatusEnum;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'name',
'description',
'status',
'category',
'price',
];
// Enum casting for automatic type conversion
protected $casts = [
'status' =--> ProductStatusEnum::class,
'category' => ProductCategoryEnum::class,
'price' => 'decimal:2',
];
// Query scopes using enums
public function scopeByStatus(Builder $query, ProductStatusEnum $status): Builder
{
return $query->where('status', $status);
}
public function scopeActive(Builder $query): Builder
{
return $query->whereIn('status', ProductStatusEnum::active());
}
public function scopeByCategory(Builder $query, ProductCategoryEnum $category): Builder
{
return $query->where('category', $category);
}
// Dynamic attribute using enum methods
public function getStatusBadgeAttribute(): string
{
return sprintf(
'<span class="badge badge-%s">%s</span>',
$this->status->color(),
$this->status->label()
);
}
}
Factory with Enum Integration:
php artisan make:factory ProductFactory
<!--?php
// database/factories/ProductFactory.php
namespace Database\Factories;
use App\Enums\ProductCategoryEnum;
use App\Enums\ProductStatusEnum;
use App\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProductFactory extends Factory
{
protected $model = Product::class;
public function definition(): array
{
return [
'name' =--> $this->faker->words(3, true),
'description' => $this->faker->paragraph,
'status' => $this->faker->randomElement(ProductStatusEnum::cases()),
'category' => $this->faker->randomElement(ProductCategoryEnum::cases()),
'price' => $this->faker->randomFloat(2, 10, 1000),
];
}
// Factory states for specific enum values
public function draft(): static
{
return $this->state(fn (array $attributes) => [
'status' => ProductStatusEnum::DRAFT,
]);
}
public function published(): static
{
return $this->state(fn (array $attributes) => [
'status' => ProductStatusEnum::PUBLISHED,
]);
}
}
Database Seeder Implementation:
php artisan make:seeder ProductSeeder
<!--?php
// database/seeders/ProductSeeder.php
namespace Database\Seeders;
use App\Models\Product;
use Illuminate\Database\Seeder;
class ProductSeeder extends Seeder
{
public function run(): void
{
// Create products with different statuses using enum
Product::factory(10)--->draft()->create();
Product::factory(15)->published()->create();
Product::factory(5)->create(); // Random status
}
}
Form Request with Laravel Enum Validation:
php artisan make:request ProductRequest
<!--?php
// app/Http/Requests/ProductRequest.php
namespace App\Http\Requests;
use App\Enums\ProductCategoryEnum;
use App\Enums\ProductStatusEnum;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
class ProductRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' =--> 'required|string|max:255',
'description' => 'required|string',
'status' => ['required', new Enum(ProductStatusEnum::class)],
'category' => ['required', new Enum(ProductCategoryEnum::class)],
'price' => 'required|numeric|min:0',
];
}
// Custom error messages for enum validation
public function messages(): array
{
return [
'status.required' => 'Product status is required',
'category.required' => 'Product category is required',
];
}
}
Create API resources for clean JSON responses:
php artisan make:resource ProductResource
<!--?php
// app/Http/Resources/ProductResource.php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' =--> $this->id,
'name' => $this->name,
'description' => $this->description,
'status' => [
'value' => $this->status->value,
'label' => $this->status->label(),
'color' => $this->status->color(),
],
'category' => [
'value' => $this->category->value,
'icon' => $this->category->icon(),
],
'price' => $this->price,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
Create a comprehensive controller showcasing Laravel enum usage:
php artisan make:controller ProductController
<!--?php
// app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Enums\ProductStatusEnum;
use App\Enums\ProductCategoryEnum;
use App\Http\Requests\ProductRequest;
use App\Http\Resources\ProductResource;
use App\Models\Product;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function index(Request $request): JsonResponse
{
$query = Product::query();
// Enum-based filtering with type safety
if ($request--->has('status')) {
$status = ProductStatusEnum::tryFrom($request->status);
if ($status) {
$query->byStatus($status);
}
}
if ($request->has('category')) {
$category = ProductCategoryEnum::tryFrom($request->category);
if ($category) {
$query->byCategory($category);
}
}
$products = $query->paginate(15);
return response()->json([
'data' => ProductResource::collection($products),
'meta' => [
'available_statuses' => collect(ProductStatusEnum::cases())->map(fn($status) => [
'value' => $status->value,
'label' => $status->label(),
]),
'available_categories' => collect(ProductCategoryEnum::cases())->map(fn($category) => [
'value' => $category->value,
'icon' => $category->icon(),
]),
]
]);
}
public function store(ProductRequest $request): JsonResponse
{
$product = Product::create($request->validated());
return response()->json([
'message' => 'Product created successfully',
'data' => new ProductResource($product)
], 201);
}
public function show(Product $product): JsonResponse
{
return response()->json([
'data' => new ProductResource($product)
]);
}
public function update(ProductRequest $request, Product $product): JsonResponse
{
$product->update($request->validated());
return response()->json([
'message' => 'Product updated successfully',
'data' => new ProductResource($product)
]);
}
public function updateStatus(Request $request, Product $product): JsonResponse
{
$request->validate([
'status' => ['required', new \Illuminate\Validation\Rules\Enum(ProductStatusEnum::class)]
]);
$product->update(['status' => $request->status]);
return response()->json([
'message' => 'Product status updated successfully',
'data' => new ProductResource($product)
]);
}
}
<!--?php
// routes/api.php
use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;
Route::apiResource('products', ProductController::class);
Route::patch('products/{product}/status', [ProductController::class, 'updateStatus']);
// Test route for Laravel enum demonstration
Route::get('enum-demo', function() {
// Create a product with Laravel enum
$product = \App\Models\Product::create([
'name' =--> 'Laravel Enum Demo Product',
'description' => 'Testing Laravel enum implementation',
'status' => \App\Enums\ProductStatusEnum::PUBLISHED,
'category' => \App\Enums\ProductCategoryEnum::ELECTRONICS,
'price' => 299.99
]);
return response()->json([
'product' => $product,
'status_label' => $product->status->label(),
'status_color' => $product->status->color(),
'category_icon' => $product->category->icon(),
'all_statuses' => collect(\App\Enums\ProductStatusEnum::cases())->map(fn($status) => [
'value' => $status->value,
'label' => $status->label()
])
]);
});
// app/Enums/StatusInterface.php
namespace App\Enums;
interface StatusInterface
{
public function label(): string;
public function color(): string;
public function isActive(): bool;
}
// app/Enums/ProductStatusEnum.php
namespace App\Enums;
enum ProductStatusEnum: string implements StatusInterface
{
case DRAFT = 'draft';
case PUBLISHED = 'published';
case ARCHIVED = 'archived';
public function label(): string
{
return match($this) {
self::DRAFT => 'Draft',
self::PUBLISHED => 'Published',
self::ARCHIVED => 'Archived',
};
}
public function color(): string
{
return match($this) {
self::DRAFT => 'gray',
self::PUBLISHED => 'green',
self::ARCHIVED => 'yellow',
};
}
public function isActive(): bool
{
return in_array($this, [self::DRAFT, self::PUBLISHED]);
}
}
Laravel enum casting delivers superior performance compared to traditional string comparisons. Key advantages include:
Solution: Ensure proper enum casting in your model and use enum values in API responses.
Solution: Validate enum values before database operations and manage enum changes with proper migration strategies.
Solution: Restart your IDE, rebuild indexes, and verify namespace declarations are correct.
When migrating from constants or string literals to Laravel enums:
Laravel enum implementation provides a robust, type-safe approach to handling fixed value sets in your applications. By following this comprehensive guide and implementing the best practices outlined above, you'll create maintainable, scalable Laravel applications that leverage the full power of PHP 8.1 enums.
The combination of Laravel enum casting, validation, and API integration creates a seamless development experience while ensuring data integrity and improving code quality. Modern Laravel development increasingly relies on type-safe patterns, making enum mastery essential for professional developers.
Begin integrating Laravel enums into your projects today and experience the transformation in code quality, maintainability, and developer productivity that comes with type-safe development practices.