pbweb/audit-bundle
Symfony bundle for auditing Doctrine entities: it automatically tracks create, update, and delete changes through Doctrine listeners, recording who changed what and when. Configurable storage and a simple API make it easy to review entity change history in your application.
This is a Symfony bundle, not a Laravel package. Before anything else, internalise that mismatch: a Laravel app will not boot it, config/bundles.php doesn't exist in your app, and there is no service provider to auto-discover. Your realistic entry points are (a) you maintain a Symfony service alongside your Laravel work, (b) you're evaluating audit-trail designs, or (c) you're reusing the underlying Doctrine listener in a Laravel app that already runs Doctrine ORM.
Steps to evaluate:
composer.json and check the symfony/* version constraints and PHP floor. With 1 star and 0 dependents, expect it to target an older Symfony (3.x/4.x) and to fail on Symfony 6/7 or PHP 8.2+.src/DependencyInjection/Configuration.php — this is the authoritative source for the config tree. Anything the README says about keys should be verified here.Resources/config/services.* to see what the bundle actually registers and which tags it applies (typically a doctrine.event_subscriber or doctrine.orm.entity_listener).onFlush/postFlush (or preUpdate/postUpdate) methods. That is the entire behaviour of the bundle.First use case: audit an entity's create/update/delete into a log table, storing the changed fields plus a user/request context. In Symfony that's composer require pbweb/audit-bundle, register the bundle class in config/bundles.php, add a pbweb_audit: (verify the actual alias) block under config/packages/, and map the entities you want tracked. In Laravel the equivalent first use case is a ModelObserver on created/updated/deleted writing diffs via getDirty() / getOriginal() — or just install owen-it/laravel-auditing, which is the mature, maintained analogue.
The bundle almost certainly follows the standard Doctrine audit pattern, and that pattern is worth understanding regardless of whether you keep the dependency:
onFlush and walks UnitOfWork::getScheduledEntityInsertions/Updates/Deletions. An entity listener is attached per entity via #[ORM\EntityListeners] and is easier to scope. Prefer the listener for a handful of entities; use the subscriber only when you need blanket coverage.UnitOfWork::getEntityChangeSet($entity) returns [field => [old, new]] for scalar fields only. That's the value you persist — not the entity.RequestStack; Laravel: Auth::id(), request()->ip()) into the listener, and make it nullable so CLI/queue contexts don't blow up.onFlush schedules an insert; postFlush commits) so the audit trail can never diverge from the data. The alternative — dispatching to a queue in postFlush — trades consistency for latency; pick deliberately.updated_at, password_hash, tokens). Ignoring sensitive fields is a security requirement, not a nicety.Model::observe(AuditObserver::class); in updated(), use $model->getChanges() and $model->getOriginal($key); write to an audits table with auditable_type/id, event, old_values, new_values (JSON), user_id, ip. owen-it/laravel-auditing implements exactly this — steal its schema even if you don't use the package.services.yaml to point at a custom writer (DB table, PSR-3 logger, or event dispatcher), and decorate the subscriber rather than editing vendor code.laravel-doctrine/orm), you can manually instantiate the listener and tag it in your Doctrine config, but you'll be reimplementing the bundle's DI wiring by hand — at which point copying ~100 lines of listener code is cheaper and leaves you with no abandoned dependency.onFlush/postFlush re-enters the UnitOfWork. Guard with a boolean flag or a separate EntityManager; otherwise you get infinite loops or EntityManager is closed.getEntityChangeSet() will not tell you that a OneToMany/ManyToMany association changed. If association history matters, you need explicit collectionChangeSet handling or separate domain events.postRemove the entity is detached; capture identifiers and a snapshot of the fields you need at preRemove instead.bin/console cache:clear; stale container caches produce "unknown option" errors that look like bugs in the bundle.bin/console debug:container --tag=doctrine.event_subscriber confirms the subscriber is registered; debug:event-dispatcher shows listeners. If nothing is logged, the tag is usually missing — not the logic.old_values/new_values payloads.How can I help you explore Laravel packages today?