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 Tree Laravel Package

gzero/eloquent-tree

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require gzero/eloquent-tree
    

    Ensure your Laravel version (5.3+) matches the package's requirements.

  2. Model Setup: Extend the base Tree model in your Eloquent model:

    use Gzero\EloquentTree\Model\Tree;
    
    class Category extends Tree
    {
        protected $table = 'categories';
        // Custom fields, relations, etc.
    }
    
  3. Migration: Run the provided migration (adjust table/column names as needed):

    Schema::create('categories', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->integer('parent_id')->unsigned()->nullable();
        $table->integer('lft')->unsigned();
        $table->integer('rgt')->unsigned();
        $table->integer('depth')->unsigned();
        $table->timestamps();
    });
    
  4. First Use Case: Create a root node:

    $root = Category::create(['name' => 'Electronics']);
    

    Add a child:

    $child = $root->children()->create(['name' => 'Phones']);
    

Implementation Patterns

Core Workflows

  1. Tree Traversal:

    • Fetch all descendants (recursive):
      $root->descendants; // Collection of all children, grandchildren, etc.
      
    • Fetch direct children:
      $root->children; // Collection of immediate children
      
    • Get ancestors (path to root):
      $child->ancestors; // Collection from child → root
      
  2. Node Manipulation:

    • Move subtree (e.g., reparent a node):
      $node->move($newParent); // Moves entire subtree under $newParent
      
    • Insert siblings:
      $node->insertSibling(['name' => 'New Sibling'], 'after'); // 'before'|'after'
      
  3. Dynamic Tree Building:

    • Build tree from flat data (e.g., API response):
      $tree = Category::buildTree($flatData, 'id', 'parent_id');
      
  4. Query Scoping:

    • Scope queries to a subtree:
      Category::whereIn('id', $root->descendants->pluck('id'));
      

Integration Tips

  • Polymorphic Trees: Use morphTo/morphWith for shared tree structures (e.g., categories for products/media):

    public function treeable()
    {
        return $this->morphTo();
    }
    

    Update the Tree model to handle polymorphic relations.

  • Caching: Cache tree structures for read-heavy apps:

    $tree = Cache::remember("tree_{$root->id}", now()->addHours(1), function() use ($root) {
        return $root->withDescendants;
    });
    
  • Frontend Rendering: Serialize trees for JavaScript (e.g., nested-sortable):

    $treeData = $root->toTreeArray(); // Custom method to flatten for JS
    

Gotchas and Tips

Pitfalls

  1. Database Constraints:

    • Ensure parent_id is nullable (roots have NULL).
    • Add foreign key constraint:
      $table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade');
      
  2. Performance:

    • Avoid descendants on deep trees (>1000 nodes). Use pagination or lazy loading:
      $root->descendants()->paginate(50);
      
    • Index lft, rgt, and depth columns for large trees.
  3. Concurrency:

    • Tree operations (e.g., move) are atomic but may lock tables. Test under load.
  4. Legacy Data:

    • If migrating existing data, rebuild the tree manually:
      Category::rebuildTree(); // Built-in method to recalculate lft/rgt/depth
      

Debugging

  • Tree Corruption: If lft/rgt values are inconsistent, run:

    $node->rebuildTree(); // Recalculates for a subtree
    

    Or globally:

    Category::rebuildTree();
    
  • Query Debugging: Enable Eloquent logging:

    \DB::enableQueryLog();
    $tree = Category::find(1)->withDescendants;
    \DB::getQueryLog(); // Inspect generated SQL
    

Extension Points

  1. Custom Scopes: Add reusable scopes to your model:

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

    Usage:

    Category::active()->whereHasDescendants();
    
  2. Event Hooks: Listen for tree events (e.g., tree.moved):

    Category::moved(function ($model) {
        // Log or notify when a node is moved
    });
    
  3. Custom Tree Builders: Override buildTree() for non-standard hierarchies:

    public static function buildTree(array $items, $idKey = 'id', $parentKey = 'parent_id')
    {
        // Custom logic (e.g., handle circular references)
    }
    
  4. Soft Deletes: Extend for soft deletes (Laravel 5.7+):

    use SoftDeletes;
    class Category extends Tree {
        use SoftDeletes;
        // ...
    }
    

    Update queries to handle soft-deleted nodes in trees.

Pro Tips

  • Bulk Operations: Use insertSibling in loops for batch creation:

    $parent = Category::find(1);
    foreach ($items as $item) {
        $parent->insertSibling($item, 'after');
    }
    
  • Tree Depth Limits: Enforce max depth in validation:

    public function validateDepth()
    {
        $this->validate(['depth' => 'max:5']); // Prevent infinite trees
    }
    
  • Multi-Tenant Trees: Scope trees by tenant:

    class Category extends Tree {
        public function scopeForTenant($query, $tenantId)
        {
            return $query->where('tenant_id', $tenantId);
        }
    }
    
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.
ilhamsyabani/laravel-volt-starter
thethunderturner/filament-latex
ghostcompiler/laravel-querybuilder
webrek/laravel-telescope-mongodb
anousss007/blatui
zatona-eg/zatona-eg-api
cocosmos/filament-sticky-save-bar
patrickbussmann/oauth2-apple
3brs/enterprise-security-bundle
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat