Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Global Or Scope Laravel Package

lacodix/laravel-global-or-scope

Add multiple Eloquent global scopes that are grouped and applied with OR logic instead of the default AND. Use a simple trait to register OR-scopes and optionally disable some or all of them per query with withoutGlobalOrScopes().

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require lacodix/laravel-global-or-scope
    
  2. Add the trait to your Eloquent model:
    use Lacodix\LaravelGlobalOrScope\Traits\GlobalOrScope;
    
    class Post extends Model
    {
        use GlobalOrScope;
    }
    
  3. Register scopes in the booting() method:
    public static function booting(): void
    {
        static::addGlobalOrScopes([Scope1::class, Scope2::class]);
    }
    

First Use Case

Apply a query with additional conditions while leveraging OR logic for global scopes:

Post::query()->where('user_id', 1000)->get();
// Generates: `where user_id = 1000 AND (scope1 OR scope2)`

Implementation Patterns

Core Workflow

  1. Define Scopes:

    class ActiveScope implements Scope
    {
        public function apply(Builder $builder, Model $model)
        {
            return $builder->where('is_active', true);
        }
    }
    
    class DraftScope implements Scope
    {
        public function apply(Builder $builder, Model $model)
        {
            return $builder->where('is_draft', true);
        }
    }
    
  2. Register Scopes:

    class Post extends Model
    {
        use GlobalOrScope;
    
        public static function booting(): void
        {
            static::addGlobalOrScopes([
                ActiveScope::class,
                DraftScope::class
            ]);
        }
    }
    
  3. Query with OR Logic:

    // Applies: `WHERE (is_active = true OR is_draft = true)`
    Post::query()->get();
    

Dynamic Scope Management

  • Disable All Scopes:
    Post::query()->withoutGlobalOrScopes()->get();
    
  • Disable Specific Scope:
    Post::query()->withoutGlobalOrScope(ActiveScope::class)->get();
    
  • Temporary Disable for Request:
    Post::clearGlobalOrScopes();
    

Advanced Patterns

  1. Combine with Regular Global Scopes:

    class Post extends Model
    {
        use GlobalOrScope;
    
        public static function boot(): void
        {
            static::addGlobalScope(SoftDeletes::class); // Regular scope
            static::addGlobalOrScopes([ActiveScope::class, DraftScope::class]);
            parent::boot();
        }
    }
    
  2. Runtime Scope Addition:

    Post::query()->withGlobalOrScopes([new ArchivedScope()]);
    
  3. Nested OR Logic:

    $orScope1 = new OrScope([new ActiveScope(), new DraftScope()]);
    $orScope2 = new OrScope([new PublishedScope(), new ScheduledScope()]);
    
    Post::query()
        ->withGlobalScope('active_or_draft', $orScope1)
        ->withGlobalScope('published_or_scheduled', $orScope2);
    

Gotchas and Tips

Pitfalls

  1. Scope Registration Timing:

    • Register scopes before parent::boot() in the boot() method, or use booting().
    • Example of incorrect registration:
      public static function boot(): void
      {
          parent::boot(); // Scopes won't apply!
          static::addGlobalOrScopes([...]);
      }
      
  2. Scope Instantiation:

    • Use instantiated scopes (not just class names) in withGlobalOrScopes():
      // Correct:
      Post::query()->withGlobalOrScopes([new ActiveScope(), new DraftScope()]);
      
      // Incorrect (throws error):
      Post::query()->withGlobalOrScopes([ActiveScope::class, DraftScope::class]);
      
  3. SQL Injection Risk:

    • Avoid dynamic scope conditions that rely on user input without sanitization:
      // Risky:
      $scope = new class implements Scope {
          public function apply(Builder $builder, Model $model) {
              $builder->where('column', $_GET['value']); // UNSAFE!
          }
      };
      

Debugging Tips

  1. Inspect Disabled Scopes:

    $disabledScopes = Post::query()->removedOrScopes();
    dd($disabledScopes);
    
  2. Verify Scope Application:

    • Use toSql() to inspect the generated query:
      dd(Post::query()->toSql());
      
  3. Clear Cached Scopes:

    • If scopes aren’t applying, clear them manually:
      Post::clearGlobalOrScopes();
      

Extension Points

  1. Custom Scope Logic:

    • Extend OrScope for complex OR conditions:
      class ComplexOrScope extends OrScope
      {
          public function apply(Builder $builder, Model $model)
          {
              $builder->where(function($q) {
                  foreach ($this->scopes as $scope) {
                      $scope->apply($q, $model);
                      $q->orWhere(...);
                  }
              });
          }
      }
      
  2. Conditional Scope Registration:

    public static function booting(): void
    {
        if (auth()->check()) {
            static::addGlobalOrScopes([UserSpecificScope::class]);
        }
    }
    
  3. Scope Prioritization:

    • Use withoutGlobalOrScope() before withGlobalOrScopes() to override:
      Post::query()
          ->withoutGlobalOrScope(ActiveScope::class)
          ->withGlobalOrScopes([new ArchivedScope()]);
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata