minvws/audit-logger-bundle
A Symfony bundle for structured audit logging of security-relevant events. It records who did what and when, with configurable storage and integration points, helping PHP teams meet compliance, traceability, and accountability requirements.
First, the critical caveat: this is a Symfony bundle, not a Laravel package. The Bundle suffix, the minvws (Dutch Ministry of Health) namespace, and the nl-rdo-* repo naming all point to the Symfony ecosystem. If you're evaluating it for a Laravel codebase, treat it as a reference implementation rather than a composer require-and-go dependency. There is no AuditLoggerBundleServiceProvider, no config publish command, and no facade.
That said, the underlying concepts (PSR-3 logging, immutable audit records, event-driven capture) are framework-agnostic, so you can vendor the logic or write a thin adapter.
Minimal first steps:
composer require minvws/audit-logger-bundle — expect it to pull in symfony/framework-bundle, symfony/http-kernel, and likely psr/log. In a Laravel app these will sit alongside your existing Symfony components (Laravel already ships several), so check for version conflicts with composer why-not.src/ for the audit record model, the event subscriber(s), and any interfaces intended for extension.DependencyInjection/ folder for the configuration tree — that tells you exactly what is tunable (log sinks, redaction rules, user-context resolvers). As of 1.1.0, AuditLoggerInterface is now wired into the bundle's configuration automatically — this is the central contract you should read first, because it names the method(s) every audit sink must implement.Because this is a Symfony bundle, the natural integration pattern in Laravel is not to boot it but to extract its domain pieces:
app/Audit/AuditEvent.php and mirror the field semantics exactly — the bundle is presumably designed against NL-RDO / NEN 7510 audit requirements, and mismatched field names make downstream compliance reporting painful.AuditLoggerInterface is the seam. 1.1.0 makes explicit what the bundle expects: an AuditLoggerInterface registered in the DI config. In Symfony this resolves to a concrete PSR-3-backed logger; in Laravel, implement the same interface (or a Laravel-native parallel) and bind it in a service provider — $this->app->bind(AuditLoggerInterface::class, LaravelAuditLogger::class). This is the single most portable piece of the bundle.kernel.request / kernel.response). In Laravel, the equivalents are middleware or model observers. A common pattern:
app/Http/Middleware/AuditRequest.php for request-scoped audit (actor, route, IP, outcome).AuditObserver) on models that represent sensitive resources — hook created, updated, deleted, and capture the diff with explicit allow-listing of attribute keys.Event::listen for authentication (Login, Logout, Failed) via Laravel's built-in auth events.AuditLoggerInterface (now auto-registered as of 1.1.0). In Laravel, bind that interface to a dedicated channel (config/logging.php → audit channel, likely a separate file or a stream to a central collector) so audit records never get mixed with application debug logs. Do not reuse the default stack channel.Context (if you're on Laravel 11's Context facade).Security. In Laravel you'd implement the same interface against Auth::user(), and inject a NullUser for CLI/queue jobs where there is no authenticated actor (but still log the system actor).A realistic day-to-day workflow looks like: model change → observer constructs AuditEvent → event pushed to a queue (ShouldQueue) for async write → dedicated audit logger serializes to JSON → shipped to WORM storage or SIEM. Keep the synchronous write path for auth events only; everything else queues.
AuditLoggerInterface in DI config — is a Symfony-side fix and does nothing to bridge that gap for you.AuditLoggerInterface (confirmed real and central as of 1.1.0), the user/actor resolver, the record serializer, and the log handler. Those four are what you'll reimplement for Laravel — everything else is glue.How can I help you explore Laravel packages today?