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

Eloquent Has Many Deep Laravel Package

staudenmeir/eloquent-has-many-deep

Extend Eloquent’s HasManyThrough to traverse unlimited intermediate models. Define deep relationships by concatenating existing relations or manually specifying models/keys. Supports many-to-many, polymorphic relations, and combinations, plus some third‑party packages.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require staudenmeir/eloquent-has-many-deep:"^1.7"
    

    Ensure compatibility with your Laravel version (check version table).

  2. Basic Usage: Add the trait to your model:

    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
    

    Define a deep relationship via concatenation:

    public function comments()
    {
        return $this->hasManyDeepFromRelations($this->posts(), (new Post())->comments());
    }
    
  3. First Use Case: Fetch nested data in a single query:

    $country = Country::find(1);
    $comments = $country->comments()->get(); // Retrieves Country → User → Post → Comment
    

Implementation Patterns

Workflows

  1. Concatenating Existing Relationships:

    • Use hasManyDeepFromRelations() for chaining existing relationships (e.g., hasManyThrough + hasMany).
    • Example: Country → User → Post → Comment:
      $this->hasManyDeepFromRelations($this->users(), (new User())->posts(), (new Post())->comments());
      
  2. Manual Definition:

    • Specify intermediate models, foreign keys, and local keys explicitly:
      $this->hasManyDeep(
          Comment::class,       // Target model
          [User::class, Post::class], // Intermediate models
          ['user_id', 'post_id'],     // Foreign keys
          ['id', 'id']             // Local keys
      );
      
  3. Query Constraints:

    • Apply constraints to intermediate tables:
      $this->hasManyDeep(Comment::class, [User::class, Post::class])
          ->where('posts.published', true)
          ->where('users.active', true);
      
  4. Many-to-Many Paths:

    • Include pivot tables in the intermediate chain:
      $this->hasManyDeep(Permission::class, ['role_user', Role::class, 'permission_role']);
      
  5. Polymorphic Relationships:

    • Use arrays for polymorphic keys (e.g., ['commentable_type', 'commentable_id']):
      $this->hasManyDeep(Comment::class, [Post::class], [null, ['commentable_type', 'commentable_id']]);
      

Integration Tips

  • Soft Deletes: Use withTrashed() or withoutTrashed() on intermediate relationships.
  • Eager Loading: Combine with with() for optimized queries:
    Country::with('comments')->get();
    
  • Third-Party Packages: Integrate with packages like laravel-adjacency-list or compoships for hierarchical data.
  • Composite Keys: Use CompositeKey for multi-column joins:
    use \Staudenmeir\EloquentHasManyDeep\CompositeKey;
    $this->hasManyDeep(..., [new CompositeKey(['col1', 'col2']), ...]);
    

Gotchas and Tips

Pitfalls

  1. Column Ambiguity:

    • Qualify column names in where() clauses if they exist in multiple tables:
      ->where('posts.published', true) // Not ->where('published', true)
      
  2. Key Mismatches:

    • Ensure foreign/local keys align with database schema. For pivot tables, swap keys on the "right" side:
      // Pivot table keys: foreign (left) → local (right)
      ['user_id', 'role_id'] // Correct for role_user pivot
      
  3. Constraint Propagation:

    • Constraints from concatenated relationships do not auto-propagate. Use hasManyDeepFromRelationsWithConstraints() to enforce them:
      $this->hasManyDeepFromRelationsWithConstraints(
          [$this, 'users'], // Callable returning constrained relationship
          [(new User()), 'posts']
      );
      
  4. Polymorphic Quirks:

    • Polymorphic keys must be specified as arrays starting with *_type:
      [null, ['commentable_type', 'commentable_id']] // Incorrect: ['commentable_id', 'commentable_type']
      
  5. Soft Deletes:

    • Intermediate models with soft deletes require explicit handling:
      ->withTrashed() // Include soft-deleted intermediates
      ->withoutTrashed() // Exclude soft-deleted intermediates
      

Debugging

  • Query Logs: Enable Laravel’s query logging to inspect generated SQL:
    \DB::enableQueryLog();
    $comments = $country->comments()->get();
    dd(\DB::getQueryLog());
    
  • IDE Helpers: Use the HasManyDeep return type for autocompletion:
    public function comments(): \Staudenmeir\EloquentHasManyDeep\HasManyDeep { ... }
    

Extension Points

  1. Custom Constraints:

    • Extend the query builder dynamically:
      $this->hasManyDeep(Comment::class, [User::class, Post::class])
          ->where(function($query) {
              $query->where('users.country_id', $this->id);
          });
      
  2. Dynamic Relationships:

    • Build relationships conditionally:
      if ($this->isAdmin()) {
          return $this->hasManyDeep(..., [User::class, Post::class]);
      }
      
  3. Performance:

    • Use select() to limit columns:
      ->select(['comments.id', 'comments.body'])
      
    • Avoid N+1 queries with eager loading:
      Country::with('comments')->get();
      
  4. Testing:

    • Mock relationships in unit tests:
      $country = new Country();
      $country->shouldReceive('users')->andReturn(new Collection([$user]));
      
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport