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

Filament Bouncer Laravel Package

elpandape/filament-bouncer

Filament Bouncer integrates the Bouncer authorization package with Filament, adding role and permission management resources, user ability assignment, and policy-aware controls so you can manage access directly from your Filament admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

This release adds a write-boundary event to the role/stance store, so the first thing to do is decide whether your application currently listens to AbilityStanceChangedEvent for anything other than cell-level bookkeeping.

  1. Install/upgrade as usual (composer require the new version), then check the package's Events namespace — AbilityStancesSavedEvent ships alongside the existing AbilityStanceChangedEvent.
  2. Look first at whatever code consumes AbilityStanceChangedEvent. Audit logs, cache busters, webhooks, and notification listeners are the usual suspects, and they are exactly the ones that should often move to the new event.
  3. Your first use case is almost certainly cache invalidation or an audit entry: mark several stance cells on a role, save, and confirm one AbilityStancesSavedEvent arrives carrying the role and the number of changed cells, after the per-cell events.

A minimal listener:

Event::listen(function (AbilityStancesSavedEvent $event) {
    Cache::forget("role:{$event->role->getKey()}:stances");
    Log::info('stances saved', [
        'role' => $event->role->getKey(),
        'changed' => $event->changedCount,
    ]);
});

Start by replacing one "flush on every cell" listener with the aggregate event and verifying the cache still clears correctly for a multi-cell save, a saveRow() save, and a no-op save.

Implementation Patterns

Split your listeners by intent. Keep AbilityStanceChangedEvent for anything that genuinely needs per-cell granularity (row highlighting, fine-grained diffs, per-ability audit trails). Move anything that represents "a user did a thing" — notifications, webhooks, activity log entries, cache invalidation — to AbilityStancesSavedEvent. The release note is explicit that the aggregate event belongs in the store because only the store knows where a save ends; mirror that reasoning in your app and stop trying to infer save boundaries from request lifecycle.

Use the changed count as a guard. AbilityStancesSavedEvent carries the role plus the number of cells changed, so you can skip work cheaply:

public function handle(AbilityStancesSavedEvent $event): void
{
    if ($event->changedCount === 0) {
        return; // defensive; the package already suppresses no-op saves
    }

    $this->invalidate($event->role);
    $this->dispatchSync(new SyncRoleStances($event->role));
}

Bulk UI saves. A form that marks ten checkboxes and posts once will produce ten AbilityStanceChangedEvents and exactly one AbilityStancesSavedEvent. If you have a "you changed permissions" notification, hook it to the aggregate event so users get one notification per save instead of ten.

Row-level saves. saveRow() closes the write with a single change, so row-level editors can use the same listener as grid editors — no special-casing. This is the main reason to adopt the event early: it gives you one code path for both interaction styles.

Ordering. The aggregate event fires after the last cell event and never instead of it. If you have both listeners registered, do not increment the same counter in both — pick one as the source of truth (usually the aggregate) and keep the per-cell listener purely observational.

Queue long-running work. Because the aggregate event is one-per-save, it is the natural place to dispatch a job that recalculates effective permissions, warms caches, or pushes to an external authorization service. Put the listener behind ShouldQueue and consider afterCommit() so the job doesn't run for a rolled-back save.

Gotchas and Tips

  • A save that changed nothing closes nothing. Don't use the absence of an event to mean "the save failed", and don't rely on the event as a save confirmation — check your own return value or a follow-up read.
  • Don't flush a buffer at request end. The release note's rationale is a direct warning: if you already have an application-level "collect cell changes, flush on terminate" mechanism, delete it. It loses entries when the request ends somewhere unexpected (queued jobs, artisan commands, Livewire-style partial requests, exceptions). The package now gives you the correct boundary.
  • saveRow() fires the aggregate event too. If you were assuming the aggregate event only accompanies grid saves, that assumption will produce double-processing or missed processing at the row level.
  • Order matters if you rely on both events in one request. Any state you mutate in the per-cell listener will already be mutated by the time the aggregate listener runs. If the aggregate listener needs the "before" picture, capture it in the per-cell listener.
  • Debugging: log the role identifier and changed count from the aggregate event and compare against the number of per-cell events for the same request. A mismatch of more than one is the fastest signal that something else in your app is triggering a nested save.
  • Extension point: if you need the set of changed cells (not just the count) in one place, keep accumulating them in your per-cell listener and finalize in the aggregate listener — that's the intended pairing, and it keeps the save boundary owned by the store.
  • Upgrade check: search your codebase for AbilityStanceChangedEvent before deploying. Nothing is removed in this release, but listeners that were effectively "once per user action" by accident (because single-cell saves were the norm) will now fire once per cell in bulk flows, which can multiply side effects.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package