laravel-specifications maintained by dangerwayne
Laravel Specifications
A powerful implementation of the Specification Pattern for Laravel applications.
📚 Full Documentation | 📦 Packagist | ⚡ Quick Start
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, 12: Full compatibility with modern Laravel versions
- Type Safe: Full PHP 8.0+ type declarations and PHPStan level 6+ compliance
Note: The
NOTspecification 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.
Feedback & Support
We'd love to hear from you! Here are ways to provide feedback or get help:
- 🐛 Report Issues: Create an issue for bug reports
- 💡 Request Features: Suggest new features
- 💬 Ask Questions: Start a discussion or ask a question
- 📧 Email: For private inquiries, reach out to the maintainers
Contributing
We welcome contributions! Please see CONTRIBUTING for details on:
- How to report issues
- How to suggest features
- How to submit pull requests
- Development setup and standards
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.