NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Permissions for Laravel

Deleting holders

model_roles and model_permissions are polymorphic pivots, so they cannot foreign-key the holder table — deleting a user leaves its grant rows behind. If your app ever reuses primary keys (truncate and reseed, imports, non-autoincrement strategies), a new record that inherits an old id would silently inherit the deleted holder’s roles and permissions. Prevent that in one of two ways.

Detach on delete

Call forgetAllAuthorization() from the model’s deleting (or deleted) hook — the trait shorthand for Permissions::for($model)->forgetAllAuthorization(). It detaches every role and direct permission in one transaction and flushes the cache once the write commits:

use Illuminate\Foundation\Auth\User as Authenticatable;
use RoundlyConsulting\Permissions\Concerns\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    protected static function booted(): void
    {
        static::deleting(fn (self $model) => $model->forgetAllAuthorization());
    }
}

Prune orphans

Or sweep periodically. Permissions::pruneOrphans() deletes pivot rows whose model_type + model_id no longer resolve to a model — including rows whose morph type no longer maps to any class — and returns how many rows it removed:

use RoundlyConsulting\Permissions\Facades\Permissions;

Permissions::pruneOrphans(); // int — rows deleted

The prune command runs the same thing and reports the count:

php artisan permissions:prune-orphans

Schedule it to run on its own:

// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('permissions:prune-orphans')->daily();

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.