Skip to content

WhereSpecification

A built-in specification for basic WHERE clause conditions. This is the most commonly used specification for simple equality and comparison operations.

Namespace

php
DangerWayne\Specification\Specifications\Common\WhereSpecification

Constructor

php
public function __construct(
    string $field,
    mixed $operator = null,
    mixed $value = null
)

Parameters

  • $field (string) - The database column or field name
  • $operator (mixed) - The comparison operator (optional, defaults to '=')
  • $value (mixed) - The value to compare against (optional if operator is value)

Operator Signatures

The constructor supports two signatures:

php
// Two parameters: field and value (assumes '=' operator)
new WhereSpecification('status', 'active');

// Three parameters: field, operator, and value
new WhereSpecification('age', '>=', 18);

Supported Operators

  • = - Equal
  • != or <> - Not equal
  • > - Greater than
  • >= - Greater than or equal
  • < - Less than
  • <= - Less than or equal
  • like - SQL LIKE operator
  • not like - SQL NOT LIKE operator

Usage Examples

Basic Equality

php
use DangerWayne\Specification\Specifications\Common\WhereSpecification;

// Check for active status
$activeSpec = new WhereSpecification('status', 'active');

// Apply to query
$activeUsers = User::whereSpecification($activeSpec)->get();

// Use with in-memory collection
$users = User::all();
$activeUsers = $users->filter(function($user) use ($activeSpec) {
    return $activeSpec->isSatisfiedBy($user);
});

Comparison Operators

php
// Age greater than or equal to 18
$adultSpec = new WhereSpecification('age', '>=', 18);

// Price less than 100
$affordableSpec = new WhereSpecification('price', '<', 100);

// Not equal
$notDeletedSpec = new WhereSpecification('status', '!=', 'deleted');

LIKE Operator

php
// Search for names starting with 'John'
$nameSpec = new WhereSpecification('name', 'like', 'John%');

// Search for emails containing 'gmail'
$emailSpec = new WhereSpecification('email', 'like', '%gmail%');

// Not like
$notGmailSpec = new WhereSpecification('email', 'not like', '%gmail%');

Combining with Other Specifications

AND Combinations

php
$activeSpec = new WhereSpecification('status', 'active');
$verifiedSpec = new WhereSpecification('email_verified_at', '!=', null);

// Active AND verified users
$activeVerifiedSpec = $activeSpec->and($verifiedSpec);

$users = User::whereSpecification($activeVerifiedSpec)->get();

OR Combinations

php
$adminSpec = new WhereSpecification('role', 'admin');
$moderatorSpec = new WhereSpecification('role', 'moderator');

// Admin OR moderator
$staffSpec = $adminSpec->or($moderatorSpec);

$staffUsers = User::whereSpecification($staffSpec)->get();

Complex Combinations

php
$activeSpec = new WhereSpecification('status', 'active');
$premiumSpec = new WhereSpecification('subscription', 'premium');
$oldAccountSpec = new WhereSpecification('created_at', '<', now()->subYear());

// (Active AND Premium) OR Old Account
$complexSpec = $activeSpec->and($premiumSpec)->or($oldAccountSpec);

Real-World Examples

E-commerce Product Filtering

php
// Products on sale
$onSaleSpec = new WhereSpecification('sale_price', '!=', null);

// Products in stock
$inStockSpec = new WhereSpecification('stock_quantity', '>', 0);

// Featured products
$featuredSpec = new WhereSpecification('is_featured', true);

// Combine: Featured products on sale and in stock
$hotDealsSpec = $featuredSpec
    ->and($onSaleSpec)
    ->and($inStockSpec);

$hotDeals = Product::whereSpecification($hotDealsSpec)->get();

User Account Management

php
// Active accounts
$activeSpec = new WhereSpecification('status', 'active');

// Email verified
$verifiedSpec = new WhereSpecification('email_verified_at', '!=', null);

// Recently active (logged in within 30 days)
$recentSpec = new WhereSpecification('last_login_at', '>=', now()->subDays(30));

// Active, verified, and recently logged in users
$engagedUsersSpec = $activeSpec
    ->and($verifiedSpec)
    ->and($recentSpec);

$engagedUsers = User::whereSpecification($engagedUsersSpec)->get();

Content Moderation

php
// Published content
$publishedSpec = new WhereSpecification('status', 'published');

// Safe content (not flagged)
$safeSpec = new WhereSpecification('is_flagged', false);

// Recent content (last 7 days)
$recentSpec = new WhereSpecification('created_at', '>=', now()->subDays(7));

// Published, safe, recent content
$displayableSpec = $publishedSpec
    ->and($safeSpec)
    ->and($recentSpec);

$content = Post::whereSpecification($displayableSpec)->get();

Implementation Details

isSatisfiedBy() Method

The isSatisfiedBy() method evaluates the candidate's field value:

php
public function isSatisfiedBy(mixed $candidate): bool
{
    $value = data_get($candidate, $this->field);
    
    return match($this->operator) {
        '=' => $value == $this->value,
        '!=' => $value != $this->value,
        '>' => $value > $this->value,
        '>=' => $value >= $this->value,
        '<' => $value < $this->value,
        '<=' => $value <= $this->value,
        'like' => str_contains($value, str_replace('%', '', $this->value)),
        'not like' => !str_contains($value, str_replace('%', '', $this->value)),
        default => false,
    };
}

toQuery() Method

The toQuery() method applies the condition to the Eloquent builder:

php
public function toQuery(Builder $query): Builder
{
    return $query->where($this->field, $this->operator, $this->value);
}

Performance Considerations

  1. Index Usage: Ensure database columns used in WhereSpecification have appropriate indexes
  2. LIKE Performance: Leading wildcards (%value) prevent index usage
  3. Type Coercion: Be aware of type comparisons in isSatisfiedBy()
  4. Null Handling: Use WhereNullSpecification for NULL checks instead

Common Patterns

Nullable Fields

php
// Don't use WhereSpecification for NULL checks
// Bad
$notNullSpec = new WhereSpecification('field', '!=', null);

// Good - use WhereNullSpecification
$notNullSpec = new WhereNullSpecification('field', false);

Date Comparisons

php
// Recent records
$recentSpec = new WhereSpecification('created_at', '>=', now()->subDays(30));

// Date range (combine with WhereBetweenSpecification for better performance)
$startSpec = new WhereSpecification('date', '>=', $startDate);
$endSpec = new WhereSpecification('date', '<=', $endDate);
$dateRangeSpec = $startSpec->and($endSpec);

Boolean Fields

php
// Active flag
$activeSpec = new WhereSpecification('is_active', true);

// Soft deletes
$notDeletedSpec = new WhereSpecification('deleted_at', null);

Testing

php
use Tests\TestCase;
use App\Models\User;
use DangerWayne\Specification\Specifications\Common\WhereSpecification;

class WhereSpecificationTest extends TestCase
{
    public function test_it_filters_by_status()
    {
        User::factory()->create(['status' => 'active']);
        User::factory()->create(['status' => 'inactive']);
        
        $spec = new WhereSpecification('status', 'active');
        
        $users = User::whereSpecification($spec)->get();
        
        $this->assertCount(1, $users);
        $this->assertEquals('active', $users->first()->status);
    }
    
    public function test_it_handles_comparison_operators()
    {
        User::factory()->create(['age' => 17]);
        User::factory()->create(['age' => 18]);
        User::factory()->create(['age' => 25]);
        
        $spec = new WhereSpecification('age', '>=', 18);
        
        $adults = User::whereSpecification($spec)->get();
        
        $this->assertCount(2, $adults);
    }
}

See Also

Released under the MIT License.