zendframework/zend-permissions-rbac
Role-based access control component for Zend Framework and PHP applications. Define hierarchical roles and permissions, attach assertions for dynamic rules, and check user access through a simple, flexible API.
Architecture fit. zend-permissions-rbac is a standalone, in-memory RBAC graph: roles, optional parent roles for inheritance, permissions attached to roles, and optional assertions for context-sensitive checks (isGranted($role, $permission, $assertion)). It ships no Laravel service provider, config file, facade, Blade directive, middleware, or Eloquent persistence. Laravel already provides an authorization layer (Gates, Policies, Gate::before, Authorize middleware) with identical conceptual coverage. Adopting this package therefore means running a second, parallel authorization paradigm alongside the framework's native one — a net architectural negative unless you have an explicit reason to preserve Zend RBAC semantics.
Integration feasibility. Technically trivial, structurally awkward. The library is small (a handful of classes) and can be registered as a singleton in a service provider, with the role tree seeded from config/ or a cached database read, then bridged into Laravel via Gate::before() or a custom Gate implementation. That is roughly 1–3 engineer-days of adapter work. The awkwardness is not code volume; it is that every access check now has two possible call sites ($rbac->isGranted() vs $user->can()), which erodes consistency and testability over time.
Technical risk — this is the deciding factor. The package is archived, last released 2019-06-25, with 42 stars. Concretely:
| Risk | Severity | Notes |
|---|---|---|
| Abandonment | High | Archived upstream; superseded by laminas/laminas-permissions-rbac (the Zend Framework → Laminas rename). No security releases. |
| PHP 8+ compatibility | High | Released in the PHP 7.1–7.3 era; PHP 8.x support is unverified and will never be patched here. |
| Transitive rot | Medium | Depends on the archived zendframework/zend-stdlib; Composer audit/SCA noise and eventual resolution conflicts. |
| Low adoption | Medium | 42 stars means few production users, thin community answers, minimal third-party scrutiny of edge cases. |
| Licensing | Low | BSD-3-Clause is permissive and commercially safe, but carries no explicit patent grant (unlike Apache-2.0). |
Recommendation: do not introduce this package into a Laravel codebase. Treat it as a legacy-compatibility artifact only — relevant if you are porting a Zend Framework 2/3 application whose role tree and assertions are already encoded against this API.
Key questions for the team.
Stack fit. Poor as a primary authorization layer, acceptable as an isolated role-resolution engine behind a Laravel-native façade. The winning pattern is: keep Laravel's Gate/can() as the only interface your application code touches, and let the Zend RBAC graph (or its Laminas successor) act as a pluggable resolver beneath it. That preserves optionality to swap the engine later without touching call sites.
Migration path. Two viable routes, chosen by whether legacy semantics must survive:
roles, permissions, role_permission, role_user tables; express checks as Policies and Gates. Effort: 1–2 sprints depending on how many authorization decisions the app makes. Removes the dependency entirely.laminas/laminas-permissions-rbac (maintained, PHP 8-ready, same API lineage) for the archived zendframework/* package via Composer replace, register it as a singleton in a service provider, hydrate the role tree from config or a cached DB query in a RoleTreeRepository, and expose it through Gate::before() or a RbacGate decorator. Effort: ~3–5 engineer-days including tests. Preserves hierarchical role inheritance and assertions that Gates do not model natively.Compatibility. Verify in a spike before committing: run the package's own tests on your target PHP runtime; confirm no zendframework/* transitive dependency collides with an existing Laminas/Symfony constraint; confirm the archived package resolves cleanly under Composer 2 with --prefer-lowest and --prefer-stable. Expect the archived version to fail on PHP 8.2+ — this is the most likely spike outcome and should be timeboxed to one day.
Sequencing.
Gate.Maintenance. Under the archived package, maintenance burden transfers entirely in-house: security patches, PHP-version bumps, and dependency conflicts are yours. Under the Laminas successor, maintenance is community-driven but healthy. Either way you own the adapter layer. Budget a recurring ~1–2 engineer-days per year for dependency hygiene if forked, versus near-zero if replaced with native Gates.
Support. No vendor SLA. Support is Stack Overflow and GitHub issues — and with 42 stars, the answer pool is thin. This is a real onboarding tax: a new engineer will find Laravel Gate documentation instantly and Zend RBAC documentation only via archived readthedocs pages. Factor that into ramp-up, not just into code review.
Scaling. Effectively free. The RBAC graph is in-memory and O(roles × depth) per assertion; it will never be your bottleneck. The scaling concern is configuration scaling: the role tree must be rebuilt or cached per request, so put it behind Laravel's cache with a short TTL and explicit invalidation on role/permission writes. Watch for role trees that grow to hundreds of nodes with deep inheritance — assertion ordering and cycle detection become non-obvious.
Failure modes.
isGranted() returns false when a role or permission is missing. Safe from a security standpoint, dangerous operationally: a mis-seeded config or cache miss silently locks users out with no error. Add explicit "role not found" logging and a health check.Ramp-up. Conceptually light — RBAC with inheritance is well-understood and a mid-level engineer is productive in a day. The cost is vocabulary friction: addRole/setParent/isGranted/AssertionInterface versus Laravel's Gate/Policy/can/before. Two authorization idioms in one codebase is a durable cognitive tax and a common source of review comments and inconsistent patterns.
Bottom line for the decision log: archived status and an unmaintained PHP-version story disqualify this package for new adoption. Redirect to laminas/laminas-permissions-rbac if hierarchical RBAC semantics are genuinely required, otherwise consolidate on Laravel's native authorization and close the ticket.
How can I help you explore Laravel packages today?