dangerwayne / laravel-specifications
Elegant specification pattern implementation for Laravel with support for Eloquent queries and in-memory filtering
Requires
- php: ^8.0
- illuminate/collections: ^9.0|^10.0|^11.0
- illuminate/database: ^9.0|^10.0|^11.0
- illuminate/support: ^9.0|^10.0|^11.0
Requires (Dev)
- laravel/pint: ^1.0
- mockery/mockery: ^1.5
- orchestra/testbench: ^7.0|^8.0|^9.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^9.5.10|^10.0|^11.0
This package is auto-updated.
Last update: 2025-08-26 06:58:10 UTC
README
A powerful implementation of the Specification Pattern for Laravel applications.
Features
- Artisan Generator: Create specifications with
php artisan make:specification
- Eloquent Integration: Seamlessly works with Laravel's Eloquent ORM
- Collection Support: Filter in-memory collections using the same specifications
- Fluent Builder: Intuitive API for building complex specifications
- Composite Operations: Combine specifications with AND, OR, NOT operations
- Caching Support: Built-in caching for improved performance
- Laravel 9, 10, 11: Full compatibility with modern Laravel versions
- Type Safe: Full PHP 8.0+ type declarations and PHPStan level 6+ compliance
Note: The
NOT
specification has full functionality in Laravel 10+. In Laravel 9, it provides basic compatibility with limited SQL generation capabilities.
Installation
composer require dangerwayne/laravel-specifications
The package will automatically register its service provider.
Artisan Command
Generate specification classes effortlessly using the artisan command:
php artisan make:specification UserActiveSpecification
Command Options
Domain Organization
Organize specifications by domain or module:
php artisan make:specification Bookmark/SearchSpecification php artisan make:specification Order/HighValueOrderSpecification
Model Binding
Generate specifications bound to specific models:
php artisan make:specification UserPremiumSpecification --model=User
Advanced Options
# Composite specification with example composition php artisan make:specification ComplexFilterSpecification --composite # Include caching support php artisan make:specification ExpensiveSpecification --cacheable # Use builder pattern for complex rules php artisan make:specification AdvancedRulesSpecification --builder # Generate with test file php artisan make:specification TestedSpecification --test # Generate with Pest test php artisan make:specification PestSpecification --pest # Force overwrite existing file php artisan make:specification ExistingSpecification --force
Combined Options
# Model-bound specification with caching and test php artisan make:specification Order/PremiumOrderSpecification --model=Order --cacheable --test # Composite specification with builder pattern php artisan make:specification Product/ComplexSearchSpecification --composite --builder
Publishing Stubs
Customize the generated specifications by publishing the stubs:
php artisan vendor:publish --tag=specification-stubs
The stubs will be published to resources/stubs/specification/
where you can modify them to match your coding style and requirements.
Basic Usage
Using Pre-built Specifications
use DangerWayne\Specification\Specifications\Common\WhereSpecification; $activeUsers = User::query() ->whereSpecification(new WhereSpecification('status', 'active')) ->get();
Creating Custom Specifications
use DangerWayne\Specification\Specifications\AbstractSpecification; use Illuminate\Database\Eloquent\Builder; class PremiumUserSpecification extends AbstractSpecification { public function isSatisfiedBy(mixed $candidate): bool { return $candidate->subscription === 'premium'; } public function toQuery(Builder $query): Builder { return $query->where('subscription', 'premium'); } }
Using the Fluent Builder
use DangerWayne\Specification\Facades\Specification; $spec = Specification::create() ->where('status', 'active') ->where('age', '>=', 18) ->whereNotNull('email_verified_at') ->build(); $users = User::whereSpecification($spec)->get();
Combining Specifications
$activeSpec = new WhereSpecification('status', '=', 'active'); $premiumSpec = new PremiumUserSpecification(); // AND combination $activePremiumSpec = $activeSpec->and($premiumSpec); // OR combination $activeOrPremiumSpec = $activeSpec->or($premiumSpec); // NOT combination $notActiveSpec = $activeSpec->not();
Working with Collections
$users = collect([ new User(['status' => 'active', 'age' => 25]), new User(['status' => 'inactive', 'age' => 30]), new User(['status' => 'active', 'age' => 17]), ]); $spec = Specification::create() ->where('status', 'active') ->where('age', '>=', 18) ->build(); $filteredUsers = $users->whereSpecification($spec);
Available Specifications
The package includes several pre-built specifications:
WhereSpecification
new WhereSpecification('status', '=', 'active'); new WhereSpecification('age', '>', 18); new WhereSpecification('name', 'like', '%john%');
WhereInSpecification
new WhereInSpecification('status', ['active', 'pending']);
WhereBetweenSpecification
new WhereBetweenSpecification('age', 18, 65);
WhereNullSpecification
new WhereNullSpecification('email_verified_at');
WhereHasSpecification
new WhereHasSpecification('posts', new WhereSpecification('published', true));
Fluent Builder Methods
Specification::create() ->where('field', 'operator', 'value') // Basic where clause ->where('field', 'value') // Defaults to '=' operator ->whereIn('field', [1, 2, 3]) // WHERE IN clause ->whereBetween('field', 1, 10) // BETWEEN clause ->whereNull('field') // IS NULL clause ->whereNotNull('field') // IS NOT NULL clause ->whereHas('relation', $specification) // Has relationship ->or() // Next condition uses OR ->build(); // Build the specification
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=specification-config
return [ 'cache' => [ 'enabled' => env('SPECIFICATION_CACHE_ENABLED', false), 'ttl' => env('SPECIFICATION_CACHE_TTL', 3600), 'prefix' => env('SPECIFICATION_CACHE_PREFIX', 'spec_'), ], 'performance' => [ 'lazy_collections' => env('SPECIFICATION_USE_LAZY', true), 'chunk_size' => env('SPECIFICATION_CHUNK_SIZE', 1000), ], ];
Advanced Usage
Custom Specifications with Parameters
class AgeRangeSpecification extends AbstractSpecification { public function __construct( private int $minAge, private int $maxAge ) {} public function isSatisfiedBy(mixed $candidate): bool { return $candidate->age >= $this->minAge && $candidate->age <= $this->maxAge; } public function toQuery(Builder $query): Builder { return $query->whereBetween('age', [$this->minAge, $this->maxAge]); } protected function getParameters(): array { return [ 'minAge' => $this->minAge, 'maxAge' => $this->maxAge, ]; } }
Complex Specifications
$specification = Specification::create() ->where('status', 'active') ->where(function ($builder) { return $builder ->where('role', 'admin') ->or() ->where('role', 'moderator'); }) ->whereNotNull('email_verified_at') ->build();
Testing
composer test
Code Quality
composer analyse # PHPStan analysis composer format # Code formatting with Pint
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.