Weave 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

Nest Tool Laravel Package

aiman/nest-tool

A Laravel package for working with nested set hierarchical data, offering helpers to create, move, and query tree nodes so you can manage categories, menus, and other parent-child structures with efficient ancestor and descendant lookups.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install, do two minutes of recon. aiman/nest-tool has 2 stars, no dependents, and its last release was June 2020 — that predates Laravel 8. There is no meaningful README coverage to lean on, so treat the source as the documentation.

  1. Check the constraint block first. Open the repo's composer.json before running composer require. A 2020 package will typically declare laravel/framework: ^6.0|^7.0 and php: ^7.2. If you're on Laravel 10/11 and PHP 8.2+, Composer will refuse; you'll need --ignore-platform-reqs or a "replace"/fork strategy. Decide this before you write code against it.

  2. Read three files in this order:

    • src/*ServiceProvider.php — what it registers, whether it publishes config or migrations, whether it registers a custom Eloquent builder or a Blueprint macro.
    • src/ trait(s) — the trait your model will use. This is where the actual API lives (node creation, traversal, move operations).
    • database/migrations/* — the schema it expects: almost certainly _lft, _rgt, parent_id, and optionally depth. Copy these column names exactly into your own migration rather than relying on a published stub, since 2020-era stubs use $table->integer() without unsigned/index hints.
  3. Install and migrate:

    composer require aiman/nest-tool
    php artisan vendor:publish --provider="Aiman\NestTool\NestToolServiceProvider"
    php artisan migrate
    

    If vendor:publish reports nothing to publish, the package expects you to hand-write the columns. Diff the package migration against your table and add the lft/rgt/parent_id columns yourself, with an index on (lft, rgt).

  4. First use case — a category tree. Add the trait to an existing model, seed three nodes through the package's root/append methods, then dump the tree:

    use Aiman\NestTool\HasNest; // verify exact namespace in src/
    
    class Category extends Model
    {
        use HasNest;
        protected $fillable = ['name', 'parent_uuid']; // match the package's FK column
    }
    

    The single most important smoke test is round-tripping the tree: create a root, append two children, then fetch the tree and assert the ordering. If that works, lft/rgt bookkeeping is intact and everything else (moves, deletes, scopes) is worth investing in. If it doesn't, stop and evaluate alternatives (kalnoy/nestedset, staudenmeir/laravel-adjacency-list) — you will spend more time debugging this package than replacing it.

Implementation Patterns

Traits, not inheritance. The package is almost certainly a trait + query scope. Apply it to models where the hierarchy is a first-class domain concept (categories, org units, page sections, comment threads). Do not bolt it onto models that merely have an optional self-referencing FK — nested sets rewrite every sibling's lft/rgt on insert, which is a real write cost on a busy table.

Write-through-model only. Every structural operation must go through the trait's methods so the lft/rgt invariants are maintained:

$root = Category::createRoot(['name' => 'Catalog']);   // name per src/, verify
$child = $root->appendChild(['name' => 'Shoes']);
$child->appendChild(['name' => 'Sneakers']);

Never Category::insert([...]) or ->update(['parent_id' => $x]) directly — raw inserts and mass updates bypass the left/right recalculation and silently corrupt the tree. If you need bulk seeding, loop over the model API inside a transaction, or seed flat and run the package's rebuild/fixTree command (check src/Console/ — if no such command exists, that's a serious gap and a reason to look elsewhere).

Tree reads: fetch once, render recursively. Nested sets exist to kill N+1. Pull the whole subtree in one ordered query and build the tree in memory rather than calling children() per level:

$nodes = Category::orderBy('lft')->get();       // or the package's tree scope
$tree  = $nodes->toTree();                       // if provided

For Blade, a recursive partial over an in-memory children relation is far cheaper than recursive queries. For APIs, flatten to a JsonResource with an explicit children key so clients get a stable contract even if the package's internal array shape changes.

Moves get a transaction and a test. Reparenting is the highest-risk operation:

DB::transaction(fn () => $node->moveTo($newParent));

Then re-assert lft/rgt integrity (see below). Write a test for each of the four move cases: to root, to a leaf, to a sibling, and into its own descendant (which must be rejected or is a data-corruption bug).

Integration touchpoints that matter in practice:

  • Admin forms: a parent_id select must exclude the node itself and all descendants, or you invite a cyclic move. Build the options from one tree query.
  • Route binding: if the package uses a slug/uuid column, ensure getRouteKeyName() aligns, and confirm ancestor scoping (a nested page should resolve under its parent's slug, not globally).
  • Multi-tenancy / scoped trees: if each tenant has its own tree, you need the package to scope lft/rgt per tenant. Verify this early — it requires a scope column in every query, and 2020-era packages often hardcode a single global tree. If unsupported, keep separate tables per tenant or skip the package.
  • Caching: serialise the rendered tree to cache, not the model collection — the lft/rgt values are meaningless outside the DB, and stale cache after a move is a common bug.

Gotchas and Tips

It is effectively unmaintained. Two stars, zero dependents, last release 2020. Assume no security fixes, no Laravel 9+ support, and no answers to issues. Budget for a fork: "repositories" with a VCS entry in your composer.json lets you patch it in place, and if you do, pin to a commit SHA — a floating dev-main on a dead repo is a supply-chain risk.

PHP 8 / Laravel 9+ breakage is near-certain. Look for array_get(), str_slug(), str_* helpers, untyped properties, and $dates — all removed or deprecated. composer require failing is the good outcome; a package that installs under --ignore-platform-reqs and then throws Call to undefined function array_get() at runtime is worse. Grep before you trust it:

grep -rnE "array_get|str_slug|str_random|->lists\(|\$dates" vendor/aiman/nest-tool/src

Integrity is invisible until it isn't. lft/rgt corruption produces trees that look fine in small fixtures and drop or duplicate nodes once you pass ~100 rows. Add a cheap invariant check to your test suite:

// every node: lft < rgt, and rgt - lft is odd; set of (lft,rgt) has no dupes

Run it after every move test. Also assert (rgt - lft - 1) / 2 === descendants()->count(). That single assertion catches most bookkeeping bugs.

Deletes are ambiguous — decide explicitly. Deleting a parent either cascades the subtree or orphans children. Nested-set packages differ. Test it: create a 3-level tree, delete the middle node, count rows. If orphans are re-parented, your FK needs nullOnDelete and your UI needs a "these moved to root" affordance. If it cascades, soft deletes may leave lft/rgt gaps — check whether SoftDeletes is accounted for at all. On a 2020 package, assume it isn't.

Concurrency. Two simultaneous inserts under the same parent race on lft/rgt shifts. Wrap structural writes in DB::transaction() and, if you have real write volume, take a table lock or serialise through a queue. This is the classic failure mode for nested sets and it fails silently.

Eager loading. If children is a real Eloquent relation, with('children.children') is fine at fixed depth but pathological for arbitrary depth. Prefer the single ordered query + in-memory build. Conversely, ancestors() is where nested sets shine — it's one WHERE lft < ? AND rgt > ? query, no recursion.

Config quirks to check on day one: does the package let you rename the lft/rgt/parent_id columns (config file)? If not, and you're retrofitting an existing table with a parent_id already in use for something else, you'll collide. Does it register a global scope? A surprise orderBy('lft') on every query will silently change pagination order across your app.

Extension points, in order of safety: (1) compose — wrap the trait in a repository/service of your own so call sites don't depend on package method names; (2) override individual trait methods in your model by aliasing (use HasNest { moveTo as parentMoveTo; }) — fragile but workable; (3) fork. Given the maintenance reality, (1) plus a planned fork is the honest answer.

Exit criteria. If within a day you cannot get createRoot → append → ordered tree read → moveTo → integrity assertion green on your target Laravel version, switch to kalnoy/nestedset. It is the de-facto standard, actively maintained, and has the same conceptual API — so the migration is mostly renaming the trait and the column set. The only reason to stay with aiman/nest-tool is if it is already deeply embedded in a codebase you inherited, in which case a fork with your own test coverage is mandatory.

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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle