efureev/laravel-trees
Laravel Trees adds nested-set tree support to Eloquent models, making it easy to build, query, move, and reorder hierarchical data like categories or menus with efficient ancestor/descendant operations and a simple API.
Architecture fit: The package remains a nested-set implementation for Eloquent trees, not a general graph library. v7 sharpens that positioning: docs/Concepts.md now explains when a nested set is the right shape versus a simpler parent link, and the new RangeCheck, RootCheck, and restored MissingParentCheck make the integrity model concrete. For teams with read-heavy hierarchical data (categories, org units, menus) where subtree queries dominate, the fit is strong. For write-heavy trees or deep, frequently mutated hierarchies, the nested-set write amplification remains the architectural constraint, and nothing in this release changes that.
Integration feasibility: Feasibility is the main issue in v7. The floor is PHP ^8.5 and Laravel 13 — both bleeding edge. Most enterprise estates are on PHP 8.2/8.3 and Laravel 10–12, so this release is effectively greenfield-only until those platforms are upgraded. The breaking surface is deliberately small: three internal-only signatures, HealthyChecker::check() returning six entries instead of three, Table::fromQuery() becoming static and dropping pre-call instance configuration, and one exception import (Fureev\Trees\Exceptions\InvalidConfigException). The rest are fixes to behavior that was wrong. That is a good major-release shape, but the "wrong behavior" being fixed includes tree mutations — delete re-parenting and bound shifts — so integration testing against real tree data is mandatory, not optional.
Technical risk:
^8.5 also caps below PHP 9, which is correct but means another floor review within roughly a year.HealthyChecker now returns six entries, and three new checks run by default. Trees that previously passed can now fail. Any CI gate, cron health check, or dashboard comparing the array literally or asserting a clean result will start firing.DuplicatesCheck and WrongParentCheck now return node counts rather than pair/triple counts. Zero still means healthy, and isBroken() is unaffected — but thresholds and trend lines built on the old numbers are not comparable.ancestors and descendants are now ordered on every path, including eager loads. That is the correct behavior, but it adds ORDER BY to queries that did not have one, which can change plans on large trees.src/, PHPStan and PHPCS enforced in CI, and a single composer gate command. This materially lowers the "unmaintained package" risk that normally dominates a TPM's build-vs-buy call.Key questions:
RangeCheck/RootCheck/MissingParentCheck results reportable per-node, or only as aggregate counts? That determines whether we can build a remediation queue rather than a red/green alarm.Stack fit: Only viable where PHP 8.5 and Laravel 13 are already target-state or planned within the current planning horizon. On PHP 8.4 or below, this release cannot be installed at all — pin v6 and track the platform upgrade as the gating dependency. Treat v7 as the target for new services and as a scheduled migration for existing ones, not as an opportunistic bump.
Migration path:
HealthyChecker, DuplicatesCheck, and WrongParentCheck outputs across all tree-bearing models as a baseline.HealthyChecker::check() arrays, Table::fromQuery() called on an instance with prior configuration, catch blocks importing the Php\Support exception, and any code calling the three internal signatures.ancestors, descendants, and their eager-loaded variants before and after; confirm the added ordering is index-supported.composer gate (PHPStan, PHPCS, PHPUnit) into the pipeline to match upstream CI, so local and remote results agree.Compatibility: The Contracts\TreeModel expansion is static-analysis-only at runtime — nothing implements or asserts the interface — but code typed as Model&TreeModel will now pass analysis where it previously errored, and drift between contract and traits is now test-enforced. Attribute::make() gaining explicit parameters is source-compatible. isChildOf() is unchanged and retained, which is the right call; adopt isDescendantOf() and isDirectChildOf() in new code to remove the naming ambiguity.
Sequencing: Platform upgrade → package bump on a branch → data audit and repair → observability/metric updates → production cutover. Do not combine the package major with unrelated feature work; the data-repair step needs a clean rollback point.
Maintenance: The maintenance posture improves markedly. Complete coverage, enforced static analysis and coding standards, a single local gate command, and a Docker-based gate service mean the package is now cheap to validate before adopting a patch. The cost shifts to the consumer side: we own the data audit and any repair tooling.
Support: Upstream support for v6 is the open dependency. If v6 continues to receive fixes, the upgrade can be scheduled against the PHP 8.5 timeline. If not, teams on PHP 8.2–8.4 are stranded on an unpatched tree-mutation library, which is a material risk given that this release fixes silent data corruption.
Scaling: Unchanged in principle — nested sets trade write cost for read efficiency, and the single-statement shift() reduces round-trips on the write path. The new mandatory ORDER BY on both relations is the one scaling consideration: on very wide trees, ensure (tree_id, lft, rgt) indexing supports ordered retrieval so the sort does not spill.
Failure modes:
Ramp-up: Low for developers — the concepts doc, the clarified isDescendantOf()/isDirectChildOf() split, and the expanded TreeModel contract all reduce the "read the source to understand the semantics" tax that nested-set packages normally impose. The real ramp-up is on the operations side: whoever owns the health checks needs to understand what a range hole, a second root, and an orphan each mean, and what the remediation is. That is a half-day of onboarding plus a runbook, and it should be written before the first production health report, not after.
How can I help you explore Laravel packages today?