← Back to Modules

Interactive Demo

🎯 Interactive Demo

Query Scopes & Attribute Accessors

Learn how to create reusable query constraints and automatic attribute transformations.

🔍 Query Scopes - Reusable Filters

Without Scope (Repetitive)

Module::where('is_active', true)->get()
Result: 3 modules found
SQL: select * from `modules` where `is_active` = ?

With Scope (Clean & Reusable)

Module::active()->get()
Model Definition:
public function scopeActive($query) {
    return $query->where('is_active', true);
}
Benefit: Reusable, readable, chainable

💡 Scope Benefits:

  • DRY Code: Define once, use everywhere
  • Chainable: Combine multiple scopes: Model::active()->recent()->featured()
  • Testable: Easy to test in isolation

🎨 Attribute Accessors - Transform on Read

Example Data

Raw Title: Service Container & Dependency Injection
Uppercase (accessor): SERVICE CONTAINER & DEPENDENCY INJECTION

Accessor Definition

protected function titleUppercase(): Attribute {
    return Attribute::make(
        get: fn () => strtoupper($this->title)
    );
}
Usage:
$module->title_uppercase
Common Use Cases:
  • • Format names (full_name)
  • • Calculate fields (age from birthday)
  • • Format currency
  • • Parse JSON to arrays
Examples:
  • $user->full_name
  • $user->age
  • $product->formatted_price
Note:

Accessors don't modify the database, only the retrieved value!

✏️ Attribute Mutators - Transform on Write

Mutator Definition

protected function slug(): Attribute {
    return Attribute::make(
        set: fn ($value) => Str::slug($value)
    );
}

How It Works

Usage:
$module->slug = 'My Title'; // Stored as 'my-title'
Benefit: Automatic data sanitization and formatting
Common Use Cases:
  • • Hash passwords
  • • Generate slugs
  • • Sanitize input
  • • Format phone numbers
Examples:
  • • Auto-hash passwords
  • • Lowercase emails
  • • Strip whitespace
  • • Convert to proper format
Important:

Mutators transform data BEFORE saving to the database!

📝 Practical Example: User Model

class User extends Model
{
    // Accessor: Combine first and last name
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => "{$this->first_name} {$this->last_name}"
        );
    }
    
    // Mutator: Always hash passwords
    protected function password(): Attribute
    {
        return Attribute::make(
            set: fn ($value) => bcrypt($value)
        );
    }
    
    // Both: Normalize email
    protected function email(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => strtolower($value),
            set: fn ($value) => strtolower(trim($value))
        );
    }
    
    // Query Scope: Only active users
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }
    
    // Query Scope: Recently registered
    public function scopeRecent($query)
    {
        return $query->where('created_at', '>=', now()->subDays(30));
    }
}

// Usage:
$user = User::active()->recent()->first();
echo $user->full_name;  // "John Doe" (accessor)

$user->password = 'secret123';  // Automatically hashed (mutator)
$user->email = '  TEST@EXAMPLE.COM  ';  // Stored as "test@example.com" (mutator)