sofa/laravel-global-scope
Deprecated: Laravel 5.2+ changed global scopes, so this package is no longer valid. For Laravel 5.0–5.1, it provides an abstract Eloquent GlobalScope to define scopes via apply() and makes removing scopes from queries easier.
Installation:
composer require sofa/laravel-global-scope:0.1@dev
(Note: This package is outdated for Laravel 5.2+ but remains useful for legacy projects.)
Define a Global Scope:
Extend the provided Sofa\Eloquent\GlobalScope abstract class and implement the apply() method:
namespace App\Scopes;
use Sofa\Eloquent\GlobalScope;
class PublishedScope extends GlobalScope
{
public function apply($builder)
{
$builder->where('published_at', '<=', now());
}
}
Register the Scope:
Attach the scope to your model in the boot() method:
namespace App\Models;
use App\Scopes\PublishedScope;
use Sofa\Eloquent\GlobalScope as BaseGlobalScope;
class Post extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new PublishedScope());
}
}
First Use Case: Query the model—all results will automatically apply the scope:
$posts = Post::all(); // Only returns published posts
Conditional Scopes: Implement logic to conditionally apply scopes (e.g., based on user roles):
public function apply($builder)
{
if (auth()->user()->isAdmin()) {
return; // Skip scope for admins
}
$builder->where('is_active', true);
}
Dynamic Constraints: Use helper methods to encapsulate reusable query logic:
public function apply($builder)
{
$this->scopeActive($builder);
}
protected function scopeActive($builder)
{
$builder->where('active', true);
}
Macro Integration: Extend Eloquent’s query builder with macros for cleaner syntax:
public function apply($builder)
{
$builder->macro('published', function($builder) {
return $builder->where('published_at', '<=', now());
});
}
Scope Removal:
Temporarily disable the scope using withoutGlobalScopes():
$allPosts = Post::withoutGlobalScopes()->get(); // Bypasses all global scopes
Model-Specific Scopes:
Group scopes by model (e.g., UserScope, PostScope) in a Scopes directory for organization.
Development:
Use withoutGlobalScopes() in tests to isolate query logic:
$this->assertCount(10, Post::withoutGlobalScopes()->get());
Production: Leverage scopes for default query constraints (e.g., soft deletes, tenant isolation).
APIs:
Apply scopes dynamically based on request data (e.g., ?include=archived).
Soft Deletes:
Combine with Laravel’s built-in SoftDeletes trait for unified soft-delete logic:
class Post extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at', 'published_at'];
protected static function boot()
{
parent::boot();
static::addGlobalScope(new PublishedScope());
}
}
Tenancy:
Use scopes for multi-tenant applications (e.g., TenantScope):
class TenantScope extends GlobalScope
{
public function apply($builder)
{
$builder->where('tenant_id', auth()->user()->tenant_id);
}
}
Laravel 5.2+ Incompatibility: Native global scopes in Laravel 5.2+ replace this package’s need. Avoid using it in new projects.
Scope Order:
Scopes are applied in the order they are registered. Reorder with addGlobalScope() or withoutGlobalScopes():
// Wrong: Scopes may override each other unexpectedly.
static::addGlobalScope(new ScopeA());
static::addGlobalScope(new ScopeB());
// Better: Explicitly control order.
Performance:
Overly complex apply() methods can bloat queries. Test with DB::enableQueryLog():
DB::enableQueryLog();
Post::all();
dd(DB::getQueryLog());
Caching: Global scopes affect cached queries. Clear caches after modifying scopes:
php artisan cache:clear
php artisan view:clear
Query Inspection:
Use toSql() and getBindings() to debug scope logic:
$query = Post::query();
dd($query->toSql(), $query->getBindings());
Scope Isolation:
Test scopes in isolation with withoutGlobalScopes():
$query = Post::withoutGlobalScopes()->where(...);
No Built-in Config:
The package has no configuration file. All logic is in the apply() method.
Namespace Conflicts:
Ensure your GlobalScope class is namespaced to avoid collisions with Laravel’s native GlobalScope.
Custom Scope Logic: Extend the abstract class to add pre/post-apply hooks:
abstract class CustomGlobalScope extends GlobalScope
{
protected function beforeApply($builder) {}
protected function afterApply($builder) {}
}
Scope Metadata: Add metadata (e.g., priority, description) to scopes:
class PublishedScope extends GlobalScope
{
public static $priority = 10;
public static $description = 'Filters unpublished posts';
}
Dynamic Scope Registration: Register scopes dynamically based on environment or user context:
if (app()->environment('staging')) {
static::addGlobalScope(new StagingScope());
}
How can I help you explore Laravel packages today?