Artisan Generator โ
Master the powerful make:specification
command that generates specifications with domain organization, tests, and multiple templates. Create production-ready specifications in seconds!
Why You'll Love This Generator โ
Building on Laravel's excellent Artisan foundation, the specifications generator adds powerful domain-driven features:
- ๐ Domain Organization: Automatically organizes specs by business domain
- ๐งช Multiple Templates: Choose from 7 different specification types
- ๐ Model Integration: Smart model binding with type hints
- ๐งต Auto-Testing: Generates comprehensive test files
- โ๏ธ Customizable: Publish and modify stub templates
Basic Usage โ
Simple Specification โ
php artisan make:specification UserActiveSpecification
Creates app/Specifications/UserActiveSpecification.php
:
<?php
namespace App\Specifications;
use DangerWayne\Specification\Specifications\AbstractSpecification;
use Illuminate\Database\Eloquent\Builder;
class UserActiveSpecification extends AbstractSpecification
{
public function isSatisfiedBy(mixed $candidate): bool
{
// TODO: Implement your business rule logic here
return false;
}
public function toQuery(Builder $query): Builder
{
// TODO: Implement your query logic here
return $query;
}
protected function getParameters(): array
{
return [
// Add constructor parameters for caching
];
}
}
Domain Organization โ
The Power of Namespacing โ
Organize specifications by business domain for better maintainability:
# User domain
php artisan make:specification User/ActiveUserSpecification
php artisan make:specification User/PremiumUserSpecification
php artisan make:specification User/EmailVerifiedSpecification
# Order domain
php artisan make:specification Order/PaidOrderSpecification
php artisan make:specification Order/ShippableOrderSpecification
php artisan make:specification Order/RefundableOrderSpecification
# Product domain
php artisan make:specification Product/AvailableProductSpecification
php artisan make:specification Product/FeaturedProductSpecification
This creates a clean directory structure:
app/Specifications/
โโโ User/
โ โโโ ActiveUserSpecification.php
โ โโโ PremiumUserSpecification.php
โ โโโ EmailVerifiedSpecification.php
โโโ Order/
โ โโโ PaidOrderSpecification.php
โ โโโ ShippableOrderSpecification.php
โโโ Product/
โโโ AvailableProductSpecification.php
โโโ FeaturedProductSpecification.php
Model Binding โ
Generate specifications with smart model integration:
php artisan make:specification User/ActiveUserSpecification --model=User
Creates a specification with model-specific type hints and validation:
<?php
namespace App\Specifications\User;
use App\Models\User;
use DangerWayne\Specification\Specifications\AbstractSpecification;
use Illuminate\Database\Eloquent\Builder;
class ActiveUserSpecification extends AbstractSpecification
{
/**
* Determine if the user satisfies the specification.
*/
public function isSatisfiedBy(mixed $candidate): bool
{
if (!$candidate instanceof User) {
return false;
}
// TODO: Implement your User business rule logic here
return false;
}
/**
* Apply the specification to a User query builder.
*
* @param Builder<User> $query
* @return Builder<User>
*/
public function toQuery(Builder $query): Builder
{
// TODO: Implement your User query logic here
return $query;
}
}
Template Options โ
1. Composite Specifications โ
For complex specifications that combine multiple conditions:
php artisan make:specification Order/ComplexOrderSpecification --composite
class ComplexOrderSpecification extends AbstractSpecification
{
private array $specifications = [];
public function addSpecification(SpecificationInterface $specification): self
{
$this->specifications[] = $specification;
return $this;
}
public function isSatisfiedBy(mixed $candidate): bool
{
foreach ($this->specifications as $spec) {
if (!$spec->isSatisfiedBy($candidate)) {
return false;
}
}
return true;
}
// Additional methods for managing child specifications...
}
2. Cacheable Specifications โ
For expensive operations that benefit from caching:
php artisan make:specification User/ExpensiveUserSpecification --cacheable
use DangerWayne\Specification\Traits\CacheableSpecification;
class ExpensiveUserSpecification extends AbstractSpecification
{
use CacheableSpecification;
protected int $cacheTtl = 3600; // 1 hour
public function getCacheKey(): string
{
return 'expensive_user_spec_' . md5(serialize($this->getParameters()));
}
// Implementation...
}
3. Builder Pattern Specifications โ
For fluent specification building:
php artisan make:specification Search/ProductSearchSpecification --builder
use DangerWayne\Specification\Specifications\Builders\SpecificationBuilder;
class ProductSearchSpecification extends AbstractSpecification
{
private SpecificationInterface $specification;
public function __construct(array $filters = [])
{
$this->specification = $this->buildFromFilters($filters);
}
private function buildFromFilters(array $filters): SpecificationInterface
{
$builder = new SpecificationBuilder();
if (!empty($filters['category'])) {
$builder->whereIn('category_id', $filters['category']);
}
if (!empty($filters['price_range'])) {
$builder->whereBetween('price', $filters['price_range'][0], $filters['price_range'][1]);
}
return $builder->build();
}
// Delegate to built specification...
}
Testing Integration โ
Generate specifications with comprehensive tests:
php artisan make:specification User/PremiumUserSpecification --model=User --test
Creates both the specification and a test file:
// tests/Unit/Specifications/User/PremiumUserSpecificationTest.php
class PremiumUserSpecificationTest extends TestCase
{
public function test_it_identifies_premium_users()
{
$premiumUser = User::factory()->create([
'subscription_type' => 'premium'
]);
$basicUser = User::factory()->create([
'subscription_type' => 'basic'
]);
$spec = new PremiumUserSpecification();
$this->assertTrue($spec->isSatisfiedBy($premiumUser));
$this->assertFalse($spec->isSatisfiedBy($basicUser));
}
public function test_it_filters_premium_users_in_query()
{
User::factory()->create(['subscription_type' => 'premium']);
User::factory()->create(['subscription_type' => 'basic']);
User::factory()->create(['subscription_type' => 'premium']);
$spec = new PremiumUserSpecification();
$premiumUsers = User::whereSpecification($spec)->get();
$this->assertCount(2, $premiumUsers);
$this->assertTrue($premiumUsers->every(fn($user) => $user->subscription_type === 'premium'));
}
}
Pest Testing Support โ
Prefer Pest? No problem:
php artisan make:specification User/ActiveUserSpecification --pest
// tests/Unit/Specifications/User/ActiveUserSpecificationTest.php
use App\Models\User;
use App\Specifications\User\ActiveUserSpecification;
it('identifies active users', function () {
$activeUser = User::factory()->create(['status' => 'active']);
$inactiveUser = User::factory()->create(['status' => 'inactive']);
$spec = new ActiveUserSpecification();
expect($spec->isSatisfiedBy($activeUser))->toBeTrue();
expect($spec->isSatisfiedBy($inactiveUser))->toBeFalse();
});
it('filters active users in queries', function () {
User::factory()->count(3)->create(['status' => 'active']);
User::factory()->count(2)->create(['status' => 'inactive']);
$spec = new ActiveUserSpecification();
$activeUsers = User::whereSpecification($spec)->get();
expect($activeUsers)->toHaveCount(3);
expect($activeUsers->every(fn($user) => $user->status === 'active'))->toBeTrue();
});
Real-World Examples โ
E-commerce Product Search โ
# Generate the main search specification
php artisan make:specification Product/ProductSearchSpecification --composite --cacheable
# Generate individual filter specifications
php artisan make:specification Product/PriceRangeSpecification --model=Product
php artisan make:specification Product/CategorySpecification --model=Product
php artisan make:specification Product/AvailabilitySpecification --model=Product --test
User Management System โ
# Core user specifications
php artisan make:specification User/ActiveUserSpecification --model=User --test
php artisan make:specification User/VerifiedUserSpecification --model=User
# Permission system
php artisan make:specification User/Permission/HasPermissionSpecification --composite
php artisan make:specification User/Permission/RoleBasedAccessSpecification --model=User
# Engagement tracking
php artisan make:specification User/Engagement/ActiveEngagementSpecification --cacheable
Order Processing Pipeline โ
# Order status specifications
php artisan make:specification Order/ReadyToShipSpecification --model=Order --test
php artisan make:specification Order/PaymentProcessedSpecification --model=Order
php artisan make:specification Order/RefundableOrderSpecification --model=Order
# Complex processing rules
php artisan make:specification Order/Processing/OrderProcessingSpecification --composite
Advanced Options โ
Multiple Options Combined โ
# Create a comprehensive specification with all features
php artisan make:specification Order/ComplexOrderProcessingSpecification \
--model=Order \
--composite \
--cacheable \
--test
Force Overwrite โ
# Overwrite existing specifications
php artisan make:specification User/ActiveUserSpecification --force
Inline Generation โ
# Skip domain organization
php artisan make:specification FlatSpecification --inline
Customizing Templates โ
Publish and customize the stub templates:
php artisan vendor:publish --tag=specification-stubs
This creates customizable stubs in resources/stubs/specification/
:
specification.stub
- Basic templatespecification.model.stub
- Model-bound templatespecification.composite.stub
- Composite templatespecification.cacheable.stub
- Cacheable templatespecification.test.stub
- PHPUnit test templatespecification.pest.stub
- Pest test template
Custom Stub Example โ
Edit resources/stubs/specification/specification.stub
:
<?php
namespace {{ namespace }};
use DangerWayne\Specification\Specifications\AbstractSpecification;
use Illuminate\Database\Eloquent\Builder;
/**
* {{ class }}
*
* Business rule: TODO - Document your business rule here
*/
class {{ class }} extends AbstractSpecification
{
public function __construct(
// TODO: Add your parameters here
) {
//
}
public function isSatisfiedBy(mixed $candidate): bool
{
// TODO: Implement your business logic here
return false;
}
public function toQuery(Builder $query): Builder
{
// TODO: Implement your database query here
return $query;
}
protected function getParameters(): array
{
return [
// TODO: Return constructor parameters for caching
];
}
}
Pro Tips โ
1. Domain-First Approach โ
Always organize by business domain, not technical concerns:
# Good: Domain organization
php artisan make:specification User/ActiveUserSpecification
php artisan make:specification Order/PaidOrderSpecification
php artisan make:specification Product/AvailableProductSpecification
# Avoid: Technical organization
php artisan make:specification Database/UserDatabaseSpecification
php artisan make:specification API/UserAPISpecification
2. Descriptive Names โ
Use descriptive, business-focused names:
# Good: Clear business intent
php artisan make:specification User/EligibleForDiscountSpecification
php artisan make:specification Order/ReadyForShippingSpecification
php artisan make:specification Product/InStockAndAvailableSpecification
# Avoid: Generic or technical names
php artisan make:specification User/UserCheckSpecification
php artisan make:specification Order/OrderValidatorSpecification
3. Test Everything Important โ
Always generate tests for critical business logic:
# Critical business rules should always have tests
php artisan make:specification User/EligibleForLoanSpecification --model=User --test
php artisan make:specification Order/HighRiskOrderSpecification --model=Order --test
php artisan make:specification Payment/FraudDetectionSpecification --model=Payment --test
What You've Mastered โ
Congratulations! You now know how to:
- โ Generate specifications with domain organization
- โ Use model binding for type safety
- โ Create composite and cacheable specifications
- โ Generate comprehensive test suites
- โ Customize templates for your team's standards
- โ Follow best practices for naming and organization
Quick Start Complete! โ
You've now completed the Laravel Specifications Quick Start! You've learned:
- โ Installation - Set up the package
- โ Your First Specification - Transform messy logic
- โ Artisan Generator - Master the code generator
What's Next? โ
Ready to dive deeper? Explore these sections:
- ๐ฝ๏ธ Appetizers - See dramatic before/after transformations
- ๐ Complete Guide - Master all features and advanced patterns
- ๐ก Examples - Real-world implementations
- ๐๏ธ API Reference - Complete technical documentation
You're Ready!
You now have everything you need to start writing clean, maintainable Laravel applications with the Specification Pattern. Happy coding!