Skip to content

Laravel SpecificationsFrom Chaos to Clarity

Transform messy business logic into clean, testable, maintainable code using the Specification Pattern

Laravel Specifications

From Chaos to Clarity in 30 Seconds

❌ Before: Messy Controller Logic

php
public function searchProducts(Request $request)
{
    $query = Product::query();
    
    if ($request->category) {
        if (is_array($request->category)) {
            $query->whereIn('category_id', $request->category);
        } else {
            $query->where('category_id', $request->category);
        }
    }
    
    if ($request->min_price || $request->max_price) {
        if ($request->sale_only) {
            $query->where(function($q) use ($request) {
                if ($request->min_price) {
                    $q->where('sale_price', '>=', $request->min_price * 100);
                }
                if ($request->max_price) {
                    $q->where('sale_price', '<=', $request->max_price * 100);
                }
            })->whereNotNull('sale_price');
        } else {
            $query->where(function($q) use ($request) {
                if ($request->min_price) {
                    $q->where(function($subQ) use ($request) {
                        $subQ->where('sale_price', '>=', $request->min_price * 100)
                             ->orWhere(function($orQ) use ($request) {
                                 $orQ->whereNull('sale_price')
                                     ->where('price', '>=', $request->min_price * 100);
                             });
                    });
                }
                if ($request->max_price) {
                    // ... 50 more lines of conditional hell
                }
            });
        }
    }
    
    // Rating, availability, brand filtering nightmare continues...
    // ... another 100+ lines of nested conditions
    
    return $query->paginate();
}

✅ After: Clean Specification Logic

php
public function searchProducts(ProductSearchRequest $request)
{
    $spec = ProductSearchSpecification::fromRequest($request);
    
    return Product::whereSpecification($spec)->paginate();
}

Generated with:

bash
php artisan make:specification Product/ProductSearchSpecification --composite --cacheable

Individual specifications are clean, testable, and reusable:

php
// php artisan make:specification Product/PriceRangeSpecification --model=Product
// php artisan make:specification Product/CategorySpecification --model=Product  
// php artisan make:specification Product/InStockSpecification --model=Product

Why Developers Will Love Laravel Specifications

Transform Complex Logic Into Simple Rules

Reduce hundreds of lines of conditional logic down to clean, composable specifications. Make your business rules readable and maintainable for developers at any experience level.

Generate Specifications in Seconds

Use powerful Artisan generators to scaffold domain-organized specifications instantly. Keep your codebase clean and consistent with automated boilerplate generation.

Bring Elegance to Business Logic

Finally make your business rules as elegant as the rest of your Laravel application. The specification pattern integrates seamlessly with Laravel's philosophy and conventions.

Quick Taste: Common Use Cases

🛒 E-commerce Product Filtering

Transform complex product search logic into clean, composable specifications

php
$spec = ProductSearchSpecification::create()
    ->withPriceRange($minPrice, $maxPrice)
    ->withCategories($categories)  
    ->onlyInStock()
    ->build();

👤 User Management & Permissions

Clean up authorization logic with testable specifications

php
$canAccess = UserAccessSpecification::for($user, $resource)
    ->isSatisfiedBy(['user' => $user, 'resource' => $resource]);

📊 Dynamic Report Generation

Replace conditional hell with composable report filters

php
$reportData = Sale::whereSpecification(
    SalesReportSpecification::fromRequest($request)
)->get();

🎯 Content Moderation

Implement complex content rules with readable specifications

php
$shouldApprove = ContentModerationSpecification::create()
    ->allowedForUser($user)
    ->meetsSafetyGuidelines()
    ->withinRateLimit()
    ->isSatisfiedBy($content);

Released under the MIT License.