How to Use Enum in Laravel: Complete Guide with Practical Examples

How to Use Enum in Laravel: Complete Guide with Practical Examples

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.

What Are PHP Enums in Laravel?

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.

Key Benefits of Laravel Enum:

  • Type safety and compile-time validation
  • Improved IDE autocompletion and refactoring
  • Elimination of magic strings in your codebase
  • Better API documentation and contract definition
  • Enhanced code readability and maintenance

Prerequisites for Laravel Enum Implementation

Before implementing Laravel enum in your project, ensure you have:

  • PHP 8.1 or higher
  • Laravel 9.0+ (Laravel 10 enum and Laravel 11 enum support included)
  • Composer for dependency management

Step-by-Step Laravel Enum Implementation


Step 1: Project Setup


Create a new Laravel project or use an existing one:


composer create-project laravel/laravel laravel-enum-demo
cd laravel-enum-demo

Step 2: Laravel Enum Database Migration


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

Step 3: Creating Laravel Custom Enum Class

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',
        };
    }
}


Step 4: Laravel Enum Eloquent Model Integration

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


Step 5: Laravel Enum Factory and Seeder

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
    }
}


Step 6: Laravel Enum Validation Rules

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',
        ];
    }
}

Step 7: Laravel Enum API Resource

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

Step 8: Controller Implementation

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

Step 9: Routes Configuration


<!--?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()
        ])
    ]);
});

Laravel Enum Best Practices


1. Naming Conventions

  • Use descriptive, consistent naming for enum classes
  • Follow PSR-4 autoloading standards
  • Place enums in App\Enums namespace

2. Database Optimization

  • Use string-backed enums for better readability
  • Add database indexes on enum columns for performance
  • Consider enum column length for optimal storage

3. Validation Strategy

  • Always validate enum values in form requests
  • Use Laravel's built-in Enum validation rule
  • Provide meaningful error messages

4. API Design

  • Include enum metadata in API responses
  • Document available enum values in API documentation
  • Handle enum serialization consistently

Advanced Laravel Enum Techniques


Enum with Interfaces



// 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]);
    }
}

Performance Optimization

Laravel enum casting delivers superior performance compared to traditional string comparisons. Key advantages include:

  • Memory Efficiency:Enums are singletons, reducing memory usage
  • Database Performance:String-backed enums work efficiently with database indexes
  • Type Safety:Compile-time validation prevents runtime errors

Troubleshooting Common Laravel Enum Issues


Issue 1: Enum Serialization Problems

Solution: Ensure proper enum casting in your model and use enum values in API responses.


Issue 2: Database Constraint Violations

Solution: Validate enum values before database operations and manage enum changes with proper migration strategies.


Issue 3: IDE Autocomplete Issues

Solution: Restart your IDE, rebuild indexes, and verify namespace declarations are correct.


Migration from Legacy Code to Laravel Enums

When migrating from constants or string literals to Laravel enums:

  1. Create enum classes first with matching values
  2. Update model casting to use enum classes
  3. Refactor validation rules to use Enum validation
  4. Update API responses to include enum metadata
  5. Test thoroughly before deploying

Conclusion

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.


Essential Benefits:

  • Type-safe Laravel applications prevent runtime errors
  • Improved code organization and maintainability
  • Enhanced API responses with structured enum metadata
  • Performance optimizations through efficient casting
  • Future-proof development patterns for scalable applications

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.

Do you accept cookies?

We use cookies to enhance your browsing experience. By using this site, you consent to our cookie policy.

More