simplethings/entity-audit-bundle
Doctrine 2 auditing/versioning bundle inspired by Hibernate Envers. Tracks entity changes and associations over time, stores revisions, and lets you inspect historical states for debugging, compliance, and change history in Symfony/Doctrine apps.
Pros:
*_audit) with minimal overhead, avoiding complex triggers or stored procedures. Aligns with Laravel’s relational database patterns.AuditReader provides methods to fetch historical states, revisions, and diffs—critical for audit logs or rollback scenarios.Cons:
doctrine/dbal + custom ORM).php artisan audit:generate).doctrine/dbal or laravel-doctrine/orm, integration is straightforward (replace Symfony’s EntityManager with Laravel’s Doctrine instance).saving, updating) and delegate to the bundle’s AuditManager. Higher effort but feasible.SchemaTool equivalent).AuditReader and controllers can be adapted into Laravel routes/services (e.g., Route::get('/audit/{entity}', [AuditController::class, 'index'])).Auth::user()->name).spatie/laravel-activitylog). Mitigate via:
prefix_audit).findRevisions()). Consider indexing rev and timestamp.DEL revisions, but Laravel’s SoftDeletes may conflict. Requires explicit handling (e.g., ignore deleted_at in global_ignore_columns).connection/entity_manager config may not map cleanly to Laravel’s multi-connection setup.saved) be intercepted to trigger audits?SchemaTool or Laravel’s Schema Builder?AuditReader results)?/audit routes?AuditReader or seeding audit tables?spatie/laravel-activitylog been considered? It’s Laravel-native but lacks full entity versioning.EntityManager with Laravel’s Doctrine instance (if using laravel-doctrine/orm).// app/Providers/EventServiceProvider.php
public function boot(): void {
Eloquent::getEventDispatcher()->listen('saved', function ($model) {
// Manually trigger Doctrine audit via AuditManager
app('doctrine')->getManager()->getAuditManager()->logEntity($model);
});
}
AuditReader, AuditManager) in config/app.php.Route::resource or controller bindings:
Route::prefix('audit')->group(function () {
Route::get('/', [AuditController::class, 'index']);
Route::get('/revision/{id}', [AuditController::class, 'showRevision']);
});
Auth facade to resolve usernames (override username_callable):
# config/services.php
'simple_things_entity_audit.username_callable' => \App\Services\AuditUsernameResolver::class
// App/Services/AuditUsernameResolver.php
class AuditUsernameResolver {
public function __invoke() {
return Auth::check() ? Auth::user()->name : null;
}
}
refreshDatabase()) to reset audit tables.AuditReader in unit tests:
$this->partialMock(AuditReader::class, function ($mock) {
$mock->shouldReceive('findRevisions')->andReturn([/* ... */]);
});
doctrine:schema:update --dump-sql) and manual migration creation.prePersist, preUpdate) trigger audits.User, Product)./audit routes).| Feature | Compatibility | Workaround |
|---|---|---|
| Doctrine ORM | ✅ Native support | Use laravel-doctrine/orm package. |
| Eloquent | ❌ No native support | Custom event listeners or Doctrine Bridge. |
| Laravel Migrations | ⚠️ Manual integration required | Create raw SQL migrations for audit tables or extend SchemaTool. |
| Soft Deletes | ⚠️ May conflict with DEL revisions |
Exclude `deleted |
How can I help you explore Laravel packages today?