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

sonata-project/entity-audit-bundle

Doctrine 2 entity versioning for Symfony, inspired by Hibernate Envers. Tracks changes to audited entities and associations, storing revision history you can browse and compare for full audit trails.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle
    composer require sonata-project/entity-audit-bundle
    
  2. Enable the Bundle Add to config/bundles.php:
    SimpleThings\EntityAudit\SimpleThingsEntityAuditBundle::class => ['all' => true],
    
  3. Configure Audited Entities Define in config/packages/entity_audit.yaml:
    simple_things_entity_audit:
        audited_entities:
            - App\Entity\YourEntity
    
  4. Update Schema Run migrations to create audit tables:
    php bin/console doctrine:schema:update --dump-sql
    

First Use Case: Audit a Model

Annotate your entity (no extra annotations needed; just include it in audited_entities). Example:

// src/Controller/YourController.php
use SimpleThings\EntityAudit\AuditReader;

class YourController extends AbstractController {
    public function showAudit(AuditReader $auditReader, int $id) {
        $revisions = $auditReader->findRevisions(YourEntity::class, $id);
        return $this->render('audit/show.html.twig', ['revisions' => $revisions]);
    }
}

Implementation Patterns

Workflow: Auditing CRUD Operations

  1. Automatic Logging The bundle hooks into Doctrine events, so no manual code is needed for create, update, or delete operations. Example:

    // Automatically logs changes to $user when saved
    $user = new User();
    $user->setName('John Doe');
    $entityManager->persist($user);
    $entityManager->flush(); // Audit log created
    
  2. Querying Audit Data

    • Get Revisions for an Entity:
      $revisions = $auditReader->findRevisions(User::class, 1);
      
    • Compare Two Revisions:
      $rev1 = $auditReader->find(User::class, 1, 5);
      $rev2 = $auditReader->find(User::class, 1, 10);
      
    • List All Changes in a Revision:
      $changes = $auditReader->findEntitiesChangedAtRevision(10);
      
  3. Integrating with Forms Use audit data to populate forms with historical values:

    {# Display entity state at revision 5 #}
    <input type="text" value="{{ auditEntity.name }}">
    
  4. Custom Username Logic Override the default username resolution (e.g., for API users):

    simple_things_entity_audit:
        service:
            username_callable: App\Service\CustomUsernameResolver
    
    // App/Service/CustomUsernameResolver.php
    public function __invoke() {
        return 'api_user_' . request()->ip();
    }
    
  5. Excluding Fields Ignore non-critical fields (e.g., timestamps):

    simple_things_entity_audit:
        global_ignore_columns:
            - createdAt
            - updatedAt
    

Integration Tips

  • Symfony Commands Use AuditReader in console commands to log audit data:

    use SimpleThings\EntityAudit\AuditReader;
    
    class AuditCommand extends Command {
        public function __construct(private AuditReader $auditReader) {}
    
        protected function execute(InputInterface $input, OutputInterface $output) {
            $revisions = $this->auditReader->findRevisions(User::class, 1);
            $output->writeln('Revisions: ' . count($revisions));
        }
    }
    
  • Event Subscribers Trigger actions on audit events (e.g., notify admins of critical changes):

    use SimpleThings\EntityAudit\Event\RevisionEvent;
    
    class AuditSubscriber implements EventSubscriber {
        public function onRevision(RevisionEvent $event) {
            if ($event->getRevisionType() === 'DEL') {
                // Send alert
            }
        }
    }
    
  • API Endpoints Expose audit data via API:

    #[Route('/audit/{id}', name: 'api_audit_history')]
    public function getAuditHistory(AuditReader $auditReader, int $id): JsonResponse {
        return new JsonResponse($auditReader->findRevisions(User::class, $id));
    }
    

Gotchas and Tips

Pitfalls

  1. Schema Mismatches

    • Issue: Audit tables (*_audit) may not sync with entity changes if the schema is manually altered.
    • Fix: Always run doctrine:schema:update after entity changes. Use --dump-sql to preview changes:
      php bin/console doctrine:schema:update --dump-sql
      
  2. Performance Overhead

    • Issue: Auditing adds writes to the database for every change.
    • Fix:
      • Exclude frequently updated fields with global_ignore_columns.
      • Use disable_foreign_keys if foreign keys cause performance issues:
        simple_things_entity_audit:
            disable_foreign_keys: true
        
  3. ManyToMany Associations

    • Issue: Audit logs for ManyToMany may throw NoRevisionFoundException.
    • Fix: Ensure the owning side of the association is audited. Update to v1.20.0+ for fixes.
  4. Username Resolution

    • Issue: Anonymous users or API requests may log as null.
    • Fix: Implement a custom username_callable to handle edge cases:
      $auditConfig->setUsernameCallable(function () {
          return auth()->check() ? auth()->user()->email : 'system';
      });
      
  5. Joined Inheritance

    • Issue: The bundle does not support JoinedTableInheritance.
    • Fix: Use SingleTableInheritance or avoid auditing inherited entities.
  6. Debugging Missing Revisions

    • Issue: Revisions not appearing for expected changes.
    • Debug Steps:
      1. Verify the entity is in audited_entities.
      2. Check global_ignore_columns isn’t excluding critical fields.
      3. Ensure the entity is flushed (audits are logged on flush()).

Tips

  1. Selective Auditing Dynamically enable/disable auditing for specific entities:

    $auditConfig->setAuditedEntityClasses([User::class]); // Override config
    
  2. Custom Audit Tables Override table names in AuditConfiguration:

    $auditConfig->setAuditTableName('custom_audit_table');
    
  3. Bulk Operations Disable auditing for bulk operations to improve performance:

    $entityManager->getConnection()->getConfiguration()->setSQLLogger(null);
    // Perform bulk operations
    $entityManager->getConnection()->getConfiguration()->setSQLLogger($logger);
    
  4. Testing Use AuditReader in tests to verify audit logs:

    $this->assertCount(1, $auditReader->findRevisions(User::class, 1));
    
  5. Symfony 8+ Routing Use the new audit.php routing file (deprecated audit.xml):

    # config/routes.yaml
    simple_things_entity_audit:
        resource: "@SimpleThingsEntityAuditBundle/Resources/config/routing/audit.php"
        prefix: /audit
    
  6. Extension Points

    • Custom Revision Metadata: Extend Revision class (though deprecated in v1.19.0+, consider forking).
    • Pre/Post Audit Events: Listen to onRevision or onFlush events for custom logic.
  7. Large Datasets Paginate audit queries to avoid memory issues:

    $revisions = $auditReader->findRevisions(User::class, 1, 10, 20); // Limit 20
    
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.
bugban/symfony
beyonder-capi/workflow-extensions-bundle
beyonder-capi/job-queue-bundle
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin