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

Access Manager Laravel Package

gepur-it/access_manager

A Laravel package for managing application access control, with tools for defining permissions, roles, and access rules through a simple, configurable API. It helps centralize authorization logic and keep access policies maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish

composer require gepur-it/access_manager
php artisan vendor:publish --provider="GepurIt\AccessManager\AccessManagerServiceProvider"
php artisan migrate

The publish step is the important one — this package ships migrations and a config file, and you almost always end up editing both. Publish them in the same commit so the schema you deploy matches what your code expects.

Pin the version and record what you actually got

The package is at v5.1.0 as of this writing. That release only touched the Composer constraint (PHP >=7.3), so it is not a feature release — but it does confirm the constraint file is still being edited while the PHP code may not be. Commit your composer.lock and note the resolved version in the PR description. When you come back in six months, "which version of access_manager is this code written against" is the first question you'll ask.

Where to look first

  1. vendor/gepur-it/access_manager/composer.json — read the illuminate/* constraint before anything else. The PHP constraint tells you nothing about Laravel support; this file does. If it says ^7.0|^8.0, the package will refuse to install on Laravel 10 and you need to know that before you write a single line of code.
  2. config/access_manager.php — this is the source of truth. Look for the user model class, the table names, the middleware alias, and any cache TTL. Nearly every "why isn't this working" question resolves here.
  3. The trait the package exposes for your User model (add it before you touch anything else).
  4. The migrations — read the actual column names (role_id vs role, pivot table names) rather than guessing from the README. The README has drifted from the code.

Attach the trait

// app/Models/User.php
use GepurIt\AccessManager\Traits\HasAccess; // confirm exact namespace in vendor/

class User extends Authenticatable
{
    use HasAccess;
}

First use case: gate a route, not a view

Start with middleware on one route group rather than sprinkling checks across controllers. It gives you a single place to verify the whole chain (user → role → permission) is wired correctly:

Route::middleware(['auth', 'access:orders.manage'])->group(function () {
    Route::resource('orders', OrderController::class);
});

Seed one role, one permission, assign it to your own user, hit the route, and confirm a 403 for a user without it. If that works, everything else is variations on the theme.

Implementation Patterns

Seed roles and permissions as data, not code

The single biggest maintainability decision with any RBAC package is whether permissions live in a seeder/config or in an admin UI. For a package this small, keep them in a seeder checked into the repo and make role assignment the only runtime-editable thing:

// database/seeders/AccessSeeder.php
$roles = [
    'admin'   => ['orders.view', 'orders.manage', 'users.manage'],
    'manager' => ['orders.view', 'orders.manage'],
    'viewer'  => ['orders.view'],
];

This makes permission names greppable, reviewable in PRs, and diffable across environments. Runtime permission creation on a package this small is a debugging liability.

Centralise permission names as constants

String literals in middleware, Blade, and policies drift. One class:

final class Perm
{
    public const ORDERS_VIEW   = 'orders.view';
    public const ORDERS_MANAGE = 'orders.manage';
}

Then 'access:' . Perm::ORDERS_MANAGE in routes. Costs nothing, prevents typos that silently 403 in production.

Layer the checks by cost

Use middleware for route-level gates, Blade directives for UI affordances, and direct checks only inside controllers for row-level logic:

@access(\App\Support\Perm::ORDERS_MANAGE)
    <a href="{{ route('orders.create') }}">New order</a>
@endaccess

Hide the button and protect the route. Never rely on the Blade directive alone — it's cosmetic.

Pair with Policies for ownership

RBAC answers "can this role do X at all"; it doesn't answer "can this user edit this order". Keep those separate:

public function update(User $user, Order $order): bool
{
    return $user->hasAccess(Perm::ORDERS_MANAGE)
        && ($user->isAdmin() || $order->user_id === $user->id);
}

Trying to encode ownership into permission names is how RBAC setups rot.

Eager-load roles in list views

Any admin screen listing users and their roles will N+1 unless you eager-load the relationship the trait defines. Do it in the repository/query, not the Blade template.

Gotchas and Tips

A permissive PHP constraint is not a compatibility guarantee

v5.1.0 relaxes the requirement to php >=7.3 — no upper bound. That means Composer will happily install this package on PHP 8.3 or 8.4 even though nobody has run the test suite there, and it will also install it on a 7.3 box that may not have the Laravel version you're on. Do not read "it installed cleanly" as "it works." The constraint is a floor, not a support matrix.

Practical mitigations:

  • Run php artisan migrate and one middleware assertion on your actual PHP + Laravel pair before committing to the package.
  • If your production PHP is newer than what the package was written for, set config.platform.php in composer.json to your real production version so local resolution matches CI and prod.
  • Scan the source for PHP-8 breaking patterns ($dates, implicit nullable return types, strftime, dynamic properties) — the code predates 8.1.

Laravel version compatibility is still the real risk

The v5.1.0 note says nothing about illuminate/*. The original release targeted Laravel 7/8, and the PHP constraint change doesn't alter that. On Laravel 9+ expect friction: doctrine/dbal removal, the $dates → $casts migration, container binding changes, and PHP 8.1 deprecations in return types. If composer require refuses outright, that's the loud, good failure — you know immediately. If it installs but the middleware throws, the fix is usually two or three lines in a forked service provider. Fork it into app/Support/ or a private VCS repo rather than waiting on upstream — the project is small enough that you are effectively the maintainer for your copy.

Cache invalidation is the #1 production bug

RBAC packages cache the permission map per user. When you assign a role via a seeder, tinker, or admin panel, the old map persists until TTL expiry or an explicit flush. Symptom: "I gave them the role, they still get 403." Fix: call the package's cache-clear method (check the trait/provider for flushCache/clearCache) inside whatever service assigns roles, and always flush in test setUp().

Check the cache driver in production

If the package uses Cache::remember with the default driver, CACHE_DRIVER=array in a queue worker means each worker computes its own map — fine functionally, but role changes mid-job won't apply. Use redis or database for the cache store if you're mutating roles at runtime.

Watch for name collisions

If you already have spatie/laravel-permission, or ever plan to, don't install both. Table names (roles, permissions, role_user) and trait method names (hasRole, hasPermission, assignRole) collide directly. Pick one. For a new project on Laravel 10/11, Spatie is the safer call; take this package only if you're inheriting a codebase already on it or want something deliberately minimal.

Migrations are published, so they're yours

Once published, php artisan migrate:fresh uses your copy. That's a feature — add indexes on the pivot table's user_id and role_id columns, since every request does a lookup there. The stock migration may not have them.

Extension points worth knowing

  • The user model class in config — point it at your own model if you have multiple authenticatable types.
  • Custom permission resolution: if the package exposes a repository/resolver contract, bind your own in a service provider to add super-admin bypass without touching vendor code.
  • The middleware is usually a thin wrapper; if you need guard-specific behaviour (admin guard vs web guard), subclass it rather than duplicating the check in every controller.

Testing

Use RefreshDatabase plus a seeded permission set, and build factory states (->forRole('manager')) so tests read as intent rather than setup. Add one test asserting a permission-less user gets 403 on every protected route — it's cheap and catches the entire class of "someone removed the middleware" regressions. Run this suite against the lowest PHP version you claim to support, not just your local one — the >=7.3 floor means Composer will let you deploy somewhere the code has never executed.

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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums