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

Closure Table Laravel Package

jiaxincui/closure-table

Closure table implementation for Laravel Eloquent models, adding fast hierarchical tree queries and operations—ancestors, descendants, siblings, moving nodes—without recursive queries. Simple trait integration with support for multiple trees.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit The package implements the closure-table pattern as an Eloquent trait plus a companion table. From a program standpoint this is a build-vs-buy decision on commodity plumbing: hierarchy (categories, org charts, menu/permission trees, comment threads, location pickers) recurs across roadmaps, and each occurrence otherwise triggers a design spike on recursive queries, cycle prevention, and subtree moves. Adopting the package converts that into a migration plus a trait, and collapses "all descendants of X" / "path to root" into a single indexed join rather than recursive CTEs or N+1 walks — a p95 and database-CPU commitment, not an implementation detail. The counterweight is architectural, not cosmetic: every insert, move, and delete rewrites ancestor–descendant rows for the affected subtree. Adoption is therefore a read/write ratio decision that must be made with product input before commitment. It fits read-heavy, moderate-depth, occasionally-restructured trees; it does not fit high-frequency drag-and-drop reorg, bulk taxonomy imports, or true graph problems (multi-parent DAGs, dependency resolution).

Integration feasibility Low ceremony and small blast radius: one migration, one trait, configurable table/column names, and opted-in models remain ordinary Eloquent models for every other concern. Existing relationships and query-builder usage keep working, so integration risk is confined to models we deliberately enroll. Multi-tree support (several independent roots in one table, keyed by tenant or context) is a genuine product enabler — frequently the difference between shipping to all customers now versus a schema migration in six months. Friction to plan for: the trait only applies to models we control, so legacy or vendor tables need adapter models; there is no first-class caching, no bulk-mutation API, and no admin-panel or API-resource integration — all of that becomes our scope. Documentation beyond the README is thin and release notes are partly in Chinese, so internal onboarding material is a deliverable, not an afterthought.

Technical risk Ranked for the program risk register:

  • Maintenance concentration (high). ~111 stars, zero dependents, effectively one maintainer. Bus factor 1. MIT licensing is the mitigation — the codebase is small enough to fork in a day — but we should budget for owning it, not merely consuming it.
  • Breaking-change churn (medium-high). The release history shows return-shape and signature movement: v2.1.0 wrapped getTree() output for multi-tree, v3.0.0 "standardized method signatures and return values," plus repeated fixes for string/UUID IDs (3.0.2, 3.0.5), toTree() returning empty (3.0.4), getRoot() ordering nondeterminism (2.1.7), and table-prefix handling (2.1.8). Plan for minor upgrades to require code changes; pin exact versions.
  • Version-support claims (medium). v3.0.8 asserts Laravel 13 with a 2026-09-16 release. Treat every "supports Laravel N" claim as untested until our CI matrix is green on the PHP/Laravel versions we actually run.
  • Correctness and concurrency (medium-high). Circular-reference prevention, orphan cleanup, and concurrent reparent of the same node are not handled for us, and there is no database-level guard against a corrupt path set. A mutation that fails mid-transaction leaves a tree that reads incorrectly rather than erroring loudly — the worst failure class for a hierarchy.
  • Data-model lock-in (medium, priced). Storage is roughly nodes × average depth rows plus a second table per tree-bearing model. Cheap to accept now, mildly expensive to unwind — record it as a conscious accepted cost with a defined exit path.

Key questions to resolve before commitment

  1. Which specific roadmap items are currently blocked on tree structure, and what is their read/write profile in production terms (queries per session vs. reparent events per month)?
  2. What is the maximum realistic tree depth and node count per tree in 12 months, and does the write amplification stay inside an acceptable request budget?
  3. Who owns the fork if the maintainer stops? Name a person and a review cadence, or do not adopt.
  4. Do any consumers sit outside Laravel/PHP? If so, they inherit only a schema convention and the value proposition weakens.
  5. Is as-of/temporal hierarchy (what did the org chart look like last quarter) on any roadmap? Closure tables hold current state only — if yes, this is a redesign later.

Integration Approach

Stack fit Laravel + Eloquent, PHP 8.x, Laravel 9–13. Pin v3.0.8 or later — do not adopt pre-3.0.2 (string/UUID primary key support landed there), and toTree() was returning empty as recently as 3.0.4. String/char IDs matter for our conventions, so the floor is firm. Confirm the package's Laravel support matrix against our own CI before scheduling, and treat the 3.0.8/Laravel 13 claim as unverified until proven in our pipeline.

Migration path Two tracks, sequenced deliberately:

  1. Greenfield model (recommended first). A new hierarchy — one deferred roadmap item — gets the migration and trait from day one, with no data movement. This is the proof point.
  2. Existing adjacency-list table (only if justified). Backfill closure rows from the existing parent_id column in a batched, idempotent job, run in a maintenance window or behind a feature flag with dual-read verification. The same script that backfills is the rebuild-from-adjacency-list repair tool — build it once, keep it in the runbook, and it doubles as the exit path if we ever leave the package.

Compatibility The package's shape is a trait plus a table; our compatibility surface is (a) the Eloquent/Laravel versions we run, (b) our primary key strategy (auto-increment vs. UUID), and (c) our column-naming conventions, since ancestor/descendant columns become part of our schema. Declare compatibility explicitly in an internal ADR and add the package to the dependency-review process so upgrades are gated, not automatic.

Sequencing (recommended)

  1. Week 1–2 — Spike and ADR. One engineer, one throwaway model, verify read semantics, move/delete behavior, UUID keys, and multi-tree. Output: ADR with the read/write ratio decision recorded and the pin decision documented.
  2. Week 2 — Guardrails. Add composite indexes on (ancestor, descendant) on day one, a uniqueness constraint on the pair, transaction wrapping for all mutations, and circular-reference validation at the service boundary.
  3. Week 3–5 — First module. Ship one deferred feature (catalog browse or admin menu tree) behind our own repository/service layer. The package is invisible above that layer — no controller, resource, or domain object references package methods directly.
  4. Week 5 — Exit-hatch validation. Confirm the rebuild script reproduces a correct tree from the adjacency list, and confirm a fork is a one-day job. This is the adoption gate.
  5. Week 6+ — Expand. Enroll additional models only after the first module has survived a full release cycle and the integration test suite covers move/delete/orphan/concurrent-reparent cases.

Non-goals to state up front: no bulk tree surgery inside a request cycle (route through queued jobs), no graph/DAG use cases, no vendor or API exposure of closure columns.

Operational Impact

Maintenance We are the de facto maintainers. Budget: a named owner, a pinned version, periodic review of upstream releases, and a fork-on-demand capability. Keep a "rebuild the tree from the adjacency list" script in the runbook — it is both the corruption recovery tool and the migration-off path. Hide the package behind an internal repository/service interface so a fork or replacement touches one layer, not the application.

Support There is no vendor, no SLA, and no security review trail from upstream. Support plan is literally "read the source." Escalation path is internal: the owning engineer, then the fork. Add the dependency to our OSS inventory with an explicit risk acceptance note rather than letting it arrive quietly in a composer require.

Scaling Reads are the strength — single indexed joins, no recursive CTEs, which keeps drill-down screens inside latency targets without bolting on a cache tier. Writes are the constraint: subtree moves and deletes scale with subtree size, and storage scales with nodes × depth. Operating thresholds to agree with engineering before launch:

  • Depth: a 10,000-node-wide catalog is fine; a 10,000-level-deep chain is not.
  • Mutation frequency: occasional reparenting is fine; high-frequency drag-and-drop reorg needs a different model or a queue-and-batch design.
  • Bulk operations (imports, mass reclassification, taxonomy reshapes) run asynchronously, in batches, in transactions, and users must be told the operation is asynchronous — a UX commitment, not just an engineering one.

Failure modes

  • Silent path corruption. A mutation failing mid-transaction leaves a hierarchy that reads incorrectly without erroring. Mitigation: transactions on every mutation, integrity assertions in the test suite, the rebuild script in the runbook, and a periodic consistency check comparing closure rows to the adjacency list.
  • Circular references. Not prevented for us. Mitigation: validate at the service boundary on every move; reject with a clear domain error.
  • Concurrent reparent. Two admins moving the same node simultaneously can produce an inconsistent path set. Mitigation: optimistic locking or row-level serialization on the subtree root, plus a uniqueness constraint that makes duplicates fail loudly.
  • Upstream churn. A minor bump changes a return shape and breaks a screen. Mitigation: exact pin, upgrade only through a PR with the tree test suite green.
  • Orphaned nodes. Deletes that bypass the package (raw SQL, bulk deletes, cascade rules) skip closure maintenance. Mitigation: prohibit raw deletes on tree tables by policy and lint/review.

Ramp-up Low-to-moderate. The API is fluent and the pattern is well understood; the cost is not learning the package but learning the failure modes, which are undocumented upstream. Ramp plan: internal onboarding doc (README is thin, notes are partly Chinese), the integration test suite as executable documentation, one engineer trained as the tree owner, and a review checklist for any PR touching hierarchy (transactions, cycle check, no raw deletes, no synchronous bulk moves).

Product-facing note for stakeholders: no new UI, no user-visible behavior change — this makes deep category trees, org drill-downs, and comment threads load reliably fast and unblocks deferred nested-content roadmap items. The one visible change: reorganizing very large trees becomes asynchronous, so bulk moves will feel slower than a single drag-and-drop.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings