Weave Code
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

Entity Audit Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require sonata-project/entity-audit-bundle
    
  2. Enable the bundle in config/bundles.php:
    SimpleThings\EntityAudit\SimpleThingsEntityAuditBundle::class => ['all' => true],
    
  3. Configure audited entities in config/packages/entity_audit.yaml:
    simple_things_entity_audit:
        audited_entities:
            - App\Entity\Post
            - App\Entity\User
    
  4. Generate audit tables (run once):
    php bin/console doctrine:schema:update --dump-sql
    

First Use Case: Audit a CRUD Operation

Inject AuditReader into a controller/service to query audit data:

use SimpleThings\EntityAudit\AuditReader;

class PostController extends AbstractController
{
    public function showHistory(AuditReader $auditReader, Post $post)
    {
        $revisions = $auditReader->findRevisions(Post::class, $post->getId());
        // Render revisions or redirect to audit UI
    }
}

Implementation Patterns

Workflow: Auditing a New Entity

  1. Annotate the entity (no extra annotations needed; just include in config).
  2. Test audit behavior:
    $post = new Post();
    $post->setTitle('Draft');
    $entityManager->persist($post);
    $entityManager->flush();
    
    // Verify audit table has an entry
    $revision = $auditReader->getCurrentRevision(Post::class, $post->getId());
    

Integration with Existing Code

  • Exclude fields (e.g., timestamps) via global_ignore_columns:
    simple_things_entity_audit:
        global_ignore_columns: [created_at, updated_at]
    
  • Custom username resolution (e.g., for CLI commands):
    simple_things_entity_audit:
        service:
            username_callable: app.audit.username_resolver
    

Querying Patterns

  1. Get entity state at a revision:
    $oldPost = $auditReader->find(Post::class, 1, 5); // Revision 5
    
  2. Compare revisions:
    $revision1 = $auditReader->find(Post::class, 1, 3);
    $revision2 = $auditReader->find(Post::class, 1, 7);
    // Manually diff $revision1->getTitle() vs $revision2->getTitle()
    

UI Integration

Use the built-in routes (secure them!):

# config/routes.yaml
simple_things_entity_audit:
    resource: "@SimpleThingsEntityAuditBundle/Resources/config/routing/audit.xml"
    prefix: /admin/audit
  • Routes:
    • /admin/audit → Revision list.
    • /admin/audit/entity/Post/1 → Post history.
    • /admin/audit/compare/Post/1?rev1=3&rev2=7 → Diff tool.

Gotchas and Tips

Pitfalls

  1. Schema Updates:

    • Audit tables (*_audit) are auto-generated but not migrated via doctrine:migrations. Run schema:update manually after adding/removing audited entities.
    • Fix: Use --dump-sql first to review changes:
      php bin/console doctrine:schema:update --dump-sql
      
  2. Performance:

    • Audit queries can be slow for large datasets. Tip: Add indexes to rev and id columns in audit tables:
      // In a migration
      $this->addSql('CREATE INDEX idx_post_audit_rev ON post_audit(rev)');
      
    • Alternative: Use findRevisions() with LIMIT for paginated history.
  3. ManyToMany Associations:

    • Audit tables for join entities (e.g., post_tag_audit) may throw NoRevisionFoundException. Workaround: Ensure the join table’s primary key is audited or use disable_foreign_keys: true in config.
  4. Username Resolution:

    • In non-web contexts (e.g., CLI commands), set a default username:
      simple_things_entity_audit:
          service:
              username_callable: 'function() { return "system"; }'
      
  5. Global Ignore Columns:

    • Bug: Updating only an ignored column (e.g., updated_at) still triggers a revision. Fix: Use global_ignore_columns and explicitly ignore in entity metadata (if supported in future versions).

Debugging

  • Check audit logs:

    php bin/console doctrine:query-log
    

    Look for INSERT INTO *audit queries.

  • Verify revisions:

    $revisions = $auditReader->findRevisions(Post::class, 1);
    dd($revisions); // Debug revision data
    

Extension Points

  1. Custom Audit Tables:

    • Override table names via audit_table_name in entity metadata (not officially supported; use events).
  2. Post-Audit Actions:

    • Listen to entity_audit.post_revision event:
      $eventDispatcher->addListener(
          'entity_audit.post_revision',
          function ($event) {
              // Log to external system
          }
      );
      
  3. Standalone Usage:

    • For non-Symfony projects, manually configure AuditManager and AuditReader as shown in the README.

Configuration Quirks

  • Multi-EntityManager: Specify connection and entity_manager in config:
    simple_things_entity_audit:
        connection: pgsql
        entity_manager: custom_em
    
  • Symfony 8+: Uses doctrine/persistence v4. Tip: If using older Doctrine, pin versions in composer.json.

Pro Tips

  • Audit Selective Fields: Use global_ignore_columns for non-critical fields (e.g., token, password_hash).

  • Compare Revisions Programmatically:

    $diff = [];
    $entity1 = $auditReader->find(Post::class, 1, 3);
    $entity2 = $auditReader->find(Post::class, 1, 7);
    foreach (get_object_vars($entity1) as $field => $value) {
        if ($entity1->$field !== $entity2->$field) {
            $diff[$field] = [$entity1->$field, $entity2->$field];
        }
    }
    
  • Disable for Tests: Override config in phpunit.xml:

    <env name="AUDIT_ENABLED" value="false"/>
    

    Then conditionally enable in config/packages/test/entity_audit.yaml:

    simple_things_entity_audit: { audited_entities: [] }
    
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor