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 Morph Where Has Laravel Package

rackbeat/laravel-morph-where-has

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require rackbeat/laravel-morph-where-has
    

    No additional configuration is required—the package auto-registers its service provider.

  2. First Use Case: Suppose you have a polymorphic morphTo relation (e.g., owner()) that can belong to multiple models (Customer, Vendor). To query records where the morph relation matches a condition (e.g., Customer with active = true), use:

    Invoice::whereHasMorph('owner', [App\Customer::class], function ($query) {
        $query->where('active', true);
    })->get();
    

    Replace owner with your morph relation name and [App\Customer::class] with the allowed morph classes.


Implementation Patterns

Core Workflow

  1. Define Morph Classes: Explicitly declare all possible morph classes in your model’s whereHasMorph calls. Example:

    // In Invoice model
    public function customer() {
        return $this->morphTo('owner')->forClass(App\Customer::class);
    }
    

    Use this for type safety and clarity.

  2. Querying with Constraints:

    • Basic Filtering:
      Invoice::whereHasMorph('owner', [App\Customer::class, App\Vendor::class])
            ->get();
      
    • Nested Conditions:
      Invoice::whereHasMorph('owner', [App\Customer::class], function ($query) {
          $query->where('tier', 'premium')->where('balance', '>', 1000);
      })->get();
      
  3. Integration with Eloquent:

    • Chain with other query methods:
      Invoice::whereHasMorph('owner', [App\Customer::class])
            ->where('status', 'paid')
            ->orderBy('created_at', 'desc')
            ->get();
      
    • Use in API resources or controllers to filter collections dynamically.
  4. Dynamic Morph Classes: Pass an array of classes dynamically (e.g., from a request):

    $allowedClasses = request()->input('owner_types', [App\Customer::class]);
    Invoice::whereHasMorph('owner', $allowedClasses)->get();
    

Gotchas and Tips

Pitfalls

  1. Missing Morph Classes:

    • Error: SQLSTATE[42S22]: Column not found if a class in whereHasMorph isn’t registered in the morphTo relation.
    • Fix: Ensure all classes in the array are valid morph targets for the relation. Example:
      // Correct: Only include classes that can morph to 'owner'
      Invoice::whereHasMorph('owner', [App\Customer::class]); // ✅
      Invoice::whereHasMorph('owner', [App\InvalidClass::class]); // ❌
      
  2. Performance:

    • Issue: N+1 queries if not eager-loaded.
    • Fix: Use with() or load():
      Invoice::with(['owner' => function ($query) {
          $query->whereHas('activeCustomers');
      }])->whereHasMorph('owner', [App\Customer::class])->get();
      
  3. Case Sensitivity:

    • Gotcha: Class names in whereHasMorph must match exactly (including namespace) with the morphTo relation’s forClass definitions.
    • Tip: Use fully qualified class names (e.g., App\Models\Customer::class) to avoid ambiguity.

Debugging Tips

  1. Query Logs: Enable Laravel’s query logging to inspect generated SQL:

    DB::enableQueryLog();
    Invoice::whereHasMorph('owner', [App\Customer::class])->get();
    dd(DB::getQueryLog());
    
  2. Validation: Verify morph relations with:

    $invoice = new Invoice();
    dd($invoice->owner()->getMorphClass()); // Check expected class
    
  3. Fallback: If whereHasMorph fails, revert to raw queries or manual joins:

    Invoice::join('customers as owner', function ($join) {
        $join->on('invoices.owner_id', '=', 'owner.id')
             ->where('owner.ownerable_type', Invoice::class)
             ->where('owner.active', true);
    })->get();
    

Extension Points

  1. Custom Constraints: Extend the package by creating a macro for reusable conditions:

    use Illuminate\Database\Eloquent\Builder;
    
    Builder::macro('whereActiveOwner', function () {
        return $this->whereHasMorph('owner', [App\Customer::class], fn ($q) => $q->where('active', true));
    });
    
    // Usage:
    Invoice::whereActiveOwner()->get();
    
  2. Dynamic Class Resolution: Override the package’s MorphWhereHas class to add logic for resolving morph classes dynamically (e.g., from a config file).

  3. Testing: Mock morph relations in tests:

    $invoice = Invoice::factory()->create();
    $invoice->owner()->associate(Customer::factory()->create(['active' => true]));
    $invoice->save();
    
    $this->assertCount(1, Invoice::whereHasMorph('owner', [App\Customer::class])->get());
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle