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

Laravel Eloquent extension for “deep” has-many-through relationships across unlimited intermediate models. Supports many-to-many and polymorphic paths, combinations, and some third-party packages. Define relations by concatenating existing ones or configuring keys manually.

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 versions table).

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

    use Staudenmeir\EloquentHasManyDeep\HasRelationships;
    
  3. First Use Case: Define a deep relationship (e.g., Country → User → Post → Comment):

    public function comments()
    {
        return $this->hasManyDeep(Comment::class, [User::class, Post::class]);
    }
    

    Fetch results:

    $country = Country::find(1);
    $comments = $country->comments()->get();
    

Implementation Patterns

Workflows

  1. Concatenating Existing Relationships: Use hasManyDeepFromRelations() for chaining existing relationships:

    public function comments()
    {
        return $this->hasManyDeepFromRelations(
            $this->users(), // Country → User
            (new User())->posts(), // User → Post
            (new Post())->comments() // Post → Comment
        );
    }
    
  2. Manual Definition: Specify intermediate models, foreign keys, and local keys:

    public function permissions()
    {
        return $this->hasManyDeep(
            Permission::class,
            ['role_user', Role::class],
            ['user_id', 'role_id', 'permission_id'],
            ['id', 'role_id', 'id']
        );
    }
    
  3. Constraints and Scopes: Apply constraints to intermediate steps:

    public function activeComments()
    {
        return $this->hasManyDeep(Comment::class, [User::class, Post::class])
            ->where('posts.published', true)
            ->where('comments.approved', true);
    }
    
  4. Polymorphic Relationships: Handle polymorphic keys (e.g., commentable_type, commentable_id):

    public function postComments()
    {
        return $this->hasManyDeep(
            Comment::class,
            [Post::class],
            [null, ['commentable_type', 'commentable_id']]
        );
    }
    
  5. Many-to-Many Paths: Include pivot tables in the chain:

    public function permissions()
    {
        return $this->hasManyDeep(
            Permission::class,
            ['role_user', Role::class, 'permission_role']
        );
    }
    

Integration Tips

  • Soft Deletes: Use withTrashed() or withoutTrashed() on intermediate relationships.
  • Eager Loading: Combine with with() for performance:
    $countries = Country::with('comments')->get();
    
  • Third-Party Packages: Integrate with packages like laravel-adjacency-list or compoships for tree/graph structures.
  • Composite Keys: Use Staudenmeir\EloquentHasManyDeep\CompositeKey for multi-column relationships.

Gotchas and Tips

Pitfalls

  1. Key Mismatches:

    • Ensure foreign/local keys align with database columns. Use null for defaults:
      $this->hasManyDeep(Comment::class, [User::class, Post::class], [null, 'custom_user_id']);
      
    • For pivot tables, swap keys on the "right" side:
      ['role_user', Role::class], // Keys: ['user_id', 'role_id', 'role_id']
      
  2. Constraint Ambiguity:

    • Qualify column names to avoid SQL conflicts:
      ->where('posts.published', true) // Not ->where('published', true)
      
  3. Performance:

    • Deep relationships can be slow. Use select() to limit columns:
      ->select('comments.id', 'comments.body')
      
    • Avoid hasManyDeep in loops; eager-load instead.
  4. Soft Deletes:

    • Ensure all intermediate models support soft deletes if using withTrashed():
      ->withTrashed() // Applies to all intermediate steps
      
  5. IDE Helpers:

    • Install the IDE helper for autocompletion:
      composer require --dev staudenmeir/eloquent-has-many-deep-ide-helper
      

Debugging

  • SQL Queries: Use ->toSql() and ->getBindings() to inspect generated queries:
    $query = $this->comments()->toSql();
    $bindings = $this->comments()->getBindings();
    
  • Relationship Chain: Verify intermediate models/tables are correct. Test with a single step first.

Extension Points

  1. Custom Constraints: Extend the query builder with custom constraints:

    public function scopeActive($query)
    {
        return $query->where('active', true);
    }
    

    Then use:

    $this->comments()->active();
    
  2. Dynamic Relationships: Use closures for dynamic paths:

    public function dynamicComments($userModel)
    {
        return $this->hasManyDeep(Comment::class, [$userModel, Post::class]);
    }
    
  3. Reverse Relationships: For inverse paths (e.g., Comment → Post → User → Country), manually define keys:

    public function country()
    {
        return $this->hasManyDeep(
            Country::class,
            [User::class, Post::class],
            ['user_id', 'country_id'],
            ['id', 'user_id']
        );
    }
    
  4. Unique Results: Use distinct() or groupBy to avoid duplicates:

    ->distinct()
    // or
    ->groupBy('comments.id')
    
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
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