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

Audit Bundle Laravel Package

nti/audit-bundle

nti/audit-bundle provides audit trail functionality for Symfony applications, automatically logging Doctrine entity changes such as creates, updates, and deletes with configurable storage and user attribution for reliable change history.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle is a fork of the original data-dog/doctrine-audit-bundle, so most public docs and examples from DataDog apply directly. It targets Symfony 3 + Doctrine ORM — not Symfony 4/5/6, not Flex.

  1. Install the dependency:

    composer require nti/audit-bundle
    
  2. Register the bundle in app/AppKernel.php (Symfony 3, no autowiring):

    $bundles = [
        // ...
        new Nti\AuditBundle\NtiAuditBundle(),
    ];
    
  3. Configure the base audit entity in app/config/config.yml and point the bundle at an entity that extends AbstractAuditLog (or use the provided one if your DB permits):

    nti_audit:
        audit_log_class: AppBundle\Entity\AuditLog
    
  4. Create/update the audit tables. The audit log tables are normal Doctrine entities, so doctrine:schema:update --force (or a migration) creates them. Expect extra tables: one per audited entity plus a shared audit_log table.

  5. First use case — audit a single entity. Annotate a model with @Audit (and @AuditReader on the audit entity if you use a custom one):

    use Nti\AuditBundle\Annotation\Audit;
    
    /**
     * @ORM\Entity
     * @Audit
     */
    class Invoice { /* ... */ }
    

    Insert/update/delete a row, then inspect the generated *_audit table — it should contain a revision entry with serialized old/new values.

Where to look first in the repo: the EventListener/ and Doctrine/ directories (the onFlush/preUpdate listeners), Annotation/Audit.php, and Resources/config/ for the DI wiring. The Command/ directory is worth a look too — it holds the log-retention/purge command you'll want once audit tables start growing. The DataDog docs (README, docs/) are the de facto reference.

Implementation Patterns

Per-entity audit entities. For each audited entity you typically create a companion audit entity extending AbstractAuditLogEntity and register it via @AuditReader. This gives you typed columns for the diff and a clean way to query history.

Blame / user attribution. Wire the bundle's blame listener to your security token storage (or set a custom blame_user resolver service). Every revision row then records who made the change — the single most requested audit requirement.

Reading history in a controller. Query the audit repository by targetEntity + objectId, ordered by revision/loggedAt, and render a timeline view. The bundle stores a JSON/array diff per revision (oldValues, newValues), so a simple "field A: X → Y" table is a few lines of Twig.

Retention / pruning. The bundle ships a command that deletes audit logs older than a given age. Schedule it (cron or a Symfony command scheduler) against your audit_log table early — audit tables grow monotonically and a busy entity can outgrow its source table within months. If you're on v3.0.1 or older, bump to v3.0.2 first: that patch fixes class-name resolution in the delete-old-logs command, so the purge silently targeted the wrong class before. Verify the command actually removes rows in staging before turning it loose on production history.

Ignoring noisy fields. Annotate transient fields (updatedAt, cache counters, tokens) with the ignore option so you don't generate false-positive revisions. This is critical for entities that touch updatedAt on every save.

Integration with workflows. For state-machine style transitions (order status, ticket lifecycle), audit logs become the transition ledger — subscribe to doctrine.event_subscriber postFlush and mirror key revisions to a message bus or event dispatcher so downstream consumers see "what changed".

Relations. The bundle records collection changes as AuditEntry / relation deltas rather than full object graphs. If you need "which parent did this child move under", log the foreign key explicitly in your diff view — don't assume the collection diff is enough.

Testing. Use an in-memory SQLite DB, run a couple of persists/flushes, and assert revisions exist. The listeners run on onFlush so your functional test must go through the real EntityManager — mock repositories won't emit events.

Gotchas and Tips

  • Symfony 3 only. No Flex recipe, no autowiring, no service autoconfiguration. On modern Symfony you'll spend more time porting than the value of this bundle — the DataDog fork/alternatives (doctrine-audit, auditor-bundle, gedmo/loggable) are usually better fits.
  • onFlush ordering matters. The listener inspects the UnitOfWork's scheduled inserts/updates/deletions; if another listener alters the UoW (e.g. soft-delete, versioning) before it runs, the diff is wrong. Register it last, or move reads to postFlush when you depend on generated IDs.
  • Audit tables must exist. schema:update silently skips them if the audit entity isn't mapped — always diff your schema after enabling a new @Audit entity.
  • Don't audit the audit entity. It's easy to accidentally add @Audit to AuditLog while copying annotations; guard against it or you'll create infinite revisions.
  • JSON column caveats. Older MySQL (< 5.7) and SQLite store the diff as text in a TEXT/LONGTEXT column. Check the charset/collation — non-UTF8 field values (binaries, encrypted blobs, legacy latin1 columns) will corrupt or truncate the log.
  • Performance. Every flush incurs a diff computation per audited object in memory. On bulk imports/migrations, batch-disable auditing (set a flush flag or detach the listener) — otherwise a 100k-row import becomes a multi-minute transaction.
  • Purge command is version-sensitive. v3.0.2 fixes class naming in the delete-old-logs command (PR #33). On v3.0.1 and below, don't trust a "successful" purge run — assert the row count dropped. Treat the command as something to verify, not something to schedule blind.
  • Version constraints. Symfony 3's doctrine/orm range is narrow; pinning newer doctrine/dbal (e.g. v3) will break the UoW API this bundle relies on. Treat composer.lock as sacred.
  • Maintenance risk. This is a low-traffic fork (1 star, 0 dependents, last release Oct 2024). Audit trail gaps are a real compliance risk — before adopting, decide whether you're comfortable pinning it, or budget a fork you own.
  • Extension points. Override the blame resolver, the diff formatter, and the audit log entity class via bundle config / services.yml aliasing rather than editing vendor — those three are the seams the bundle was designed to flex.
  • Debugging. When a revision is unexpectedly missing, check (a) whether the entity is in the UoW's getScheduledEntityUpdates() at onFlush time, and (b) whether the changed field is in the ignore list. The listener swallows many "nothing to record" cases silently.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo