Technical Evaluation
TPM summary: This is a Symfony2 bundle, not a Laravel package. Symfony2 reached end-of-life in November 2018, and the bundle's core dependency — symfony/security-acl — was deprecated in Symfony 3.0 and removed in Symfony 4.0. For a Laravel codebase this is not an adoptable dependency. It is a design reference for one recurring product problem: hierarchical entities with inherited permissions. The TPM decision it informs is "port the pattern, don't pull the package" — and the assessment below is scoped to that decision.
Architecture fit
- The bundle is coupled to three Symfony-specific substrates: the Symfony2 DI container (bundle class, service definitions, compiler passes), Doctrine ORM entity mapping, and the legacy
symfony/security-acl component. None can be shimmed into Laravel without effectively rewriting the package.
- Laravel's authorization model is a different abstraction entirely: closure-based Gates and Policies defined in code via
AuthServiceProvider, not ACL entries persisted in database tables. There is no natural seam where this bundle's permission model plugs in.
- The underlying ACL component is the load-bearing risk. The PHP ecosystem actively retreated from it for documented performance and complexity reasons; adopting it in 2024+ means importing a pattern the community has already abandoned.
Integration feasibility: Low. No Laravel service provider, no facade, no publishable config, no framework-agnostic core. A port is a rewrite of both persistence and authorization layers, with only the tree-traversal concept surviving intact.
Technical risk
- Abandonment risk — High. 17 stars, 0 dependents, no maintainers of record. Zero dependents is the strongest signal available: no downstream production deployment has stress-tested this, so there is no operational evidence to borrow.
- Security surface. ACL inheritance is a security-critical code path. An incorrect inheritance decision produces silent privilege escalation or silent lockout — the two worst failure classes for an access-control system. We would become sole maintainers of unvetted authorization logic.
- Version drift. Code written for PHP 5.x/7.0-era Symfony will surface errors under PHP 8.x strictness (typed properties, deprecations promoted to errors). No upstream will fix these.
- Opportunity cost. The 0.38 opportunity score captures this precisely: a real problem, solved with an approach the ecosystem has moved past.
Key questions before any decision
- What is the actual requirement — hierarchy traversal, inherited permission resolution, or both? These decompose into different work items and different packages.
- Are permissions data or code? Do they need to be runtime-editable, per-record, and auditable, or can they be derived from role + resource attributes in Gates/Policies? Most Laravel applications need the latter, which makes the bundle irrelevant.
- What is the tree's depth and churn rate? Deep trees with frequent moves change the storage recommendation (nested set vs. adjacency list/CTE).
- Is there an actual Symfony2 system to interoperate with, or is "Symfony" incidental to the request?
- What audit/compliance obligations attach to permission changes? This drives schema (change log) and cache-invalidation design.
Integration Approach
Stack fit: none as-is. Treat the repository as a design document, not a dependency. The reusable idea is the composition of a hierarchy-traversal strategy with an ACL resolver that walks ancestors to compute effective permissions. That concept ports cleanly; the implementation does not.
Recommended target architecture (Laravel-native)
- Hierarchy storage:
kalnoy/nestedset for read-heavy taxonomies (O(1) reads, O(n) moves) or staudenmeir/laravel-adjacency-list for write-heavy org charts (recursive CTEs, balanced). Choose from question 3.
- Authorization:
spatie/laravel-permission for role/permission assignment, wrapped in Gates and Policies. Resolve inherited permissions in a single service class that walks ancestors and memoizes per request.
- Persistence: one
permissions pivot keyed on (subject_type, subject_id, role_id, permission_id) with an explicit inherit boolean. This is the one schema idea worth lifting from the bundle.
- Caching: materialize effective permission sets keyed by user + node, invalidated on tree-mutation events.
Migration path — only if a Symfony2 system is the source of truth
- Spike (1 week). Stand the bundle up in a throwaway Symfony2 container, model one representative hierarchy, and document its exact inheritance semantics: deny-overrides-allow? nearest-ancestor-wins? depth limits? move/delete behavior?
- Semantics spec. Write the inheritance rules as executable, framework-independent tests. This is the real deliverable of the spike — it is portable, reviewable, and survives whichever stack wins.
- Data migration. Export ACL entries and tree structure to a neutral JSON/CSV shape; map Symfony ACL masks to Laravel permission names.
- Port. Implement the resolver in Laravel against the spec; run the identical test suite against both systems to prove behavioral equivalence.
- Cutover. Dual-run read comparisons across a sample of users/nodes before flipping authority.
Compatibility and sequencing
- Do not fork-and-shim the bundle into Laravel. The DI container and Doctrine mapping are load-bearing; shim cost exceeds rewrite cost.
- Sequence authorization after the hierarchy model is stable. Inheritance logic is meaningless until move/delete semantics are settled.
- If question 1 resolves to "traversal only," the bundle is irrelevant —
kalnoy/nestedset alone closes the ticket.
Operational Impact
Maintenance
- Adopting as a dependency transfers 100% of maintenance to us with no upstream. Given the EOL stack, there is no realistic path to contributing fixes back.
- The ported resolver becomes first-party code we own and must test. Budget it as such — this is not a "drop in a library" line item, and it should not be scheduled as one.
- The ACL component's removal from the ecosystem means no security advisories will be issued for the version we'd be pinned to. This is a standing, unnamed risk if adoption were ever approved.
Support
- No vendor, no active maintainer, no community. Internal documentation must be written from scratch during the spike; nothing can be deferred to "the docs."
- Ramp-up is asymmetric. A new engineer needs Laravel authorization knowledge plus an explanation of why the design mirrors a dead Symfony pattern. Document the rationale or it will be refactored away incorrectly — and silently.
Scaling
- The dominant scaling risk is recursive permission resolution: walking ancestors per node per request. Without memoization and a permission cache, this becomes N+1 queries proportional to tree depth × node count.
- Tree mutations invalidate cached permission sets for all descendants. In deep, high-churn hierarchies this is a write-amplification problem; plan async invalidation and budget for it in the initial design, not as a later optimization.
- Ancestor walks scale acceptably with recursive CTEs on Postgres/MySQL 8. Nested-set reads are O(1) but every move is O(n) — acceptable for taxonomies, painful for org charts that reorganize quarterly.
Failure modes to instrument from day one
- Silent privilege escalation — resolver returns an ancestor grant where a deny was intended, or skips a subtree. Highest severity. Requires deny-by-default posture and explicit tests per inheritance rule.
- Orphaned nodes — a deleted parent leaves descendants unreachable from the root, resolving to nothing (lockout) or everything (escalation) depending on the default branch.
- Stale cache after move — user retains access to a subtree they were moved out of. Invalidation must be tied to tree events, not TTL.
- Depth-limit truncation — a hard-coded recursion cap silently cutting off inheritance past a threshold. Must be configured and alarmed, not implicit.
- Framework-version drift — PHP upgrades breaking ported code that no upstream will fix.
TPM recommendation: Do not add godisco/acltree-bundle as a dependency. Fund a one-week spike to extract its inheritance semantics into an executable spec, then implement natively on kalnoy/nestedset + spatie/laravel-permission + Gates/Policies. Gate the native build approval on the semantics spec and its test suite existing — that artifact is the durable output of evaluating this package, regardless of which stack the work lands on.