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

Audit Bundle Laravel Package

benmacha/audit-bundle

Symfony bundle to audit Doctrine entity changes with rollback support. Includes a web UI and REST API to browse audit logs, flexible configuration, security integration, and optional async processing. Supports PHP 7.4–8.4 and Symfony 5.4–7.x.

View on GitHub
Deep Wiki
Context7

Symfony Audit Bundle v0.1.0

CI Coverage Status Latest Stable Version Total Downloads License

A comprehensive Symfony bundle for auditing entity changes with rollback functionality, web interface, and REST API. Now with Symfony Flex auto-configuration support!

Features

  • 🔍 Automatic Entity Tracking: Track changes to any Doctrine entity
  • 🔄 Rollback Functionality: Restore entities to previous states
  • 🎯 Flexible Configuration: Fine-grained control over what gets audited
  • 🌐 Web Interface: User-friendly web UI for viewing audit logs
  • 🚀 REST API: Complete API for programmatic access
  • 🔒 Security Integration: Role-based access control
  • 📊 Performance Optimized: Asynchronous processing support
  • 🎨 Customizable: Extensible architecture with events
  • 📱 Responsive Design: Mobile-friendly interface
  • 🔧 Developer Tools: Comprehensive debugging and monitoring

Requirements

  • PHP 7.4 - 8.4
  • Symfony 5.4 - 7.x
  • Doctrine ORM 2.10+
  • MySQL 5.7+ / PostgreSQL 10+ / SQLite 3.25+

Installation

With Symfony Flex (Recommended)

composer require benmacha/audit-bundle

Symfony Flex will automatically:

  • Register the bundle in config/bundles.php
  • Create default configuration in config/packages/audit.yaml
  • Set up routing in config/routes/audit.yaml
  • Configure services for auto-wiring

Manual Installation

If you're not using Symfony Flex:

composer require benmacha/audit-bundle

Then manually register the bundle in config/bundles.php:

return [
    // ...
    BenMacha\AuditBundle\AuditBundle::class => ['all' => true],
];

Step 1: Install the Bundle

composer require benmacha/audit-bundle

Step 2: Enable the Bundle

Add the bundle to your config/bundles.php:

<?php

return [
    // ...
    BenMacha\AuditBundle\AuditBundle::class => ['all' => true],
];

Step 3: Configure the Bundle

With Symfony Flex, the configuration file config/packages/audit.yaml is automatically created with sensible defaults:

audit:
    # Enable/disable the audit system
    enabled: '%env(bool:AUDIT_ENABLED)%'
    
    # Storage configuration
    storage:
        driver: '%env(AUDIT_STORAGE_DRIVER)%'
        
    # Logging configuration
    logging:
        level: '%env(AUDIT_LOG_LEVEL)%'
        
    # Default audit configuration
    entities:
        # Auto-discover entities with Auditable attribute
        auto_discover: true
        
        # Default settings for audited entities
        defaults:
            track_created_at: true
            track_updated_at: true
            track_deleted_at: true
            store_old_values: true
            store_new_values: true
            
    # Web interface configuration
    web_interface:
        enabled: true
        route_prefix: '/audit'
        
    # API configuration
    api:
        enabled: true
        route_prefix: '/api/audit'
        
    # Security configuration
    security:
        # Roles required to access audit features
        view_role: 'ROLE_ADMIN'
        manage_role: 'ROLE_SUPER_ADMIN'
        rollback_role: 'ROLE_SUPER_ADMIN'
        
    # Performance settings
    performance:
        batch_size: 100
        cache_enabled: true
        cache_ttl: 3600

Environment Variables

Add these environment variables to your .env file:

# Audit Bundle Configuration
AUDIT_ENABLED=true
AUDIT_STORAGE_DRIVER=doctrine
AUDIT_LOG_LEVEL=info

Create config/packages/audit.yaml:

audit:
    enabled: true
    retention_days: 365
    async_processing: false
    
    # Database configuration
    database:
        connection: default
    
    # Entity-specific configuration
    entities:
        App\Entity\User:
            enabled: true
            operations: ['create', 'update', 'delete']
            ignored_fields: ['password', 'lastLogin']
        App\Entity\Product:
            enabled: true
            operations: ['create', 'update']
    
    # API configuration
    api:
        enabled: true
        rate_limit: 100
        prefix: '/api/audit'
    
    # Security roles
    security:
        admin_role: 'ROLE_ADMIN'
        auditor_role: 'ROLE_AUDITOR'
        developer_role: 'ROLE_DEVELOPER'
    
    # UI configuration
    ui:
        route_prefix: '/admin/audit'
        items_per_page: 25
        show_ip_address: true

Step 4: Update Database Schema

php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate

Step 5: Configure Routes (Optional)

Add to config/routes.yaml:

audit_bundle:
    resource: '@AuditBundle/Resources/config/routes.yaml'
    prefix: /admin

audit_api:
    resource: '@AuditBundle/Resources/config/api_routes.yaml'
    prefix: /api

Quick Start

Basic Entity Auditing

Simply add the #[Auditable] attribute to your entity:

<?php

namespace App\Entity;

use BenMacha\AuditBundle\Attribute\Auditable;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[Auditable]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private int $id;
    
    #[ORM\Column(type: 'string')]
    private string $username;
    
    #[ORM\Column(type: 'string')]
    private string $email;
    
    // ... getters and setters
}

Viewing Audit Logs

Access the web interface at /admin/audit or use the API:

# Get all audit logs
curl -X GET /api/audit/logs

# Get logs for specific entity
curl -X GET /api/audit/logs/entity/User/123

# Rollback entity to previous state
curl -X POST /api/audit/rollback/456

Attributes Reference

#[Auditable]

Marks an entity as auditable.

use BenMacha\AuditBundle\Attribute\Auditable;

#[Auditable(
    operations: ['create', 'update', 'delete'], // Operations to track
    ignoredFields: ['password', 'updatedAt'],   // Fields to ignore
    async: true                                 // Process asynchronously
)]
class User
{
    // ...
}

Parameters:

  • operations: Array of operations to track (create, update, delete)
  • ignoredFields: Array of field names to exclude from auditing
  • async: Whether to process audit logs asynchronously

#[IgnoreAudit]

Excludes specific fields or operations from auditing.

use BenMacha\AuditBundle\Attribute\IgnoreAudit;

class User
{
    #[IgnoreAudit] // Never audit this field
    private string $password;
    
    #[IgnoreAudit(operations: ['update'])] // Don't audit on updates
    private \DateTime $createdAt;
}

Parameters:

  • operations: Array of operations to ignore for this field

#[AuditSensitive]

Marks fields as sensitive for special handling.

use BenMacha\AuditBundle\Attribute\AuditSensitive;

class User
{
    #[AuditSensitive(
        encrypt: true,           // Encrypt the value
        mask: true,             // Mask in UI (show as ***)
        hashAlgorithm: 'sha256' // Hash algorithm for encryption
    )]
    private string $socialSecurityNumber;
}

Parameters:

  • encrypt: Whether to encrypt the field value
  • mask: Whether to mask the value in the UI
  • hashAlgorithm: Algorithm for hashing sensitive data

#[AuditMetadata]

Adds custom metadata to audit logs.

use BenMacha\AuditBundle\Attribute\AuditMetadata;

class User
{
    #[AuditMetadata(
        tags: ['pii', 'gdpr'],           // Custom tags
        indexed: true,                   // Index for searching
        ttl: 2592000,                   // TTL in seconds (30 days)
        customData: ['department' => 'HR'] // Additional metadata
    )]
    private string $email;
}

Parameters:

  • tags: Array of custom tags for categorization
  • indexed: Whether to index this field for searching
  • ttl: Time-to-live in seconds
  • customData: Additional custom metadata

#[AuditContext]

Provides additional context for audit operations.

use BenMacha\AuditBundle\Attribute\AuditContext;

#[AuditContext(
    reason: 'User profile update',
    category: 'user_management',
    priority: 'high',
    metadata: ['source' => 'admin_panel']
)]
class User
{
    // ...
}

Parameters:

  • reason: Human-readable reason for the change
  • category: Category for grouping related changes
  • priority: Priority level (low, medium, high, critical)
  • metadata: Additional context metadata

Advanced Usage

Event Subscribers

Listen to audit events for custom processing:

<?php

namespace App\EventSubscriber;

use BenMacha\AuditBundle\Event\AuditEvent;
use BenMacha\AuditBundle\Event\AuditEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AuditSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            AuditEvents::PRE_AUDIT => 'onPreAudit',
            AuditEvents::POST_AUDIT => 'onPostAudit',
            AuditEvents::ROLLBACK => 'onRollback',
        ];
    }
    
    public function onPreAudit(AuditEvent $event): void
    {
        // Modify audit data before saving
        $auditLog = $event->getAuditLog();
        $auditLog->addMetadata('processed_by', 'custom_subscriber');
    }
    
    public function onPostAudit(AuditEvent $event): void
    {
        // React to audit log creation
        $this->notificationService->sendAuditNotification($event->getAuditLog());
    }
    
    public function onRollback(AuditEvent $event): void
    {
        // Handle rollback operations
        $this->logger->info('Entity rolled back', [
            'entity' => $event->getEntityClass(),
            'id' => $event->getEntityId()
        ]);
    }
}

Manual Audit Logging

Log changes manually when needed:

<?php

namespace App\Service;

use BenMacha\AuditBundle\Service\AuditService;

class UserService
{
    public function __construct(
        private AuditService $auditService
    ) {}
    
    public function updateUserProfile(User $user, array $data): void
    {
        $oldData = $this->extractUserData($user);
        
        // Update user
        $user->setEmail($data['email']);
        $user->setName($data['name']);
        
        // Manual audit logging
        $this->auditService->logEntityChange(
            $user,
            'update',
            $oldData,
            $this->extractUserData($user),
            'Profile updated via API'
        );
    }
}

Custom Rollback Logic

Implement custom rollback behavior:

<?php

namespace App\Service;

use BenMacha\AuditBundle\Service\AuditService;
use BenMacha\AuditBundle\Entity\AuditLog;

class CustomRollbackService
{
    public function __construct(
        private AuditService $auditService
    ) {}
    
    public function rollbackWithValidation(AuditLog $auditLog): bool
    {
        // Custom validation logic
        if (!$this->canRollback($auditLog)) {
            throw new \Exception('Rollback not allowed');
        }
        
        // Perform rollback
        return $this->auditService->rollbackEntity($auditLog);
    }
    
    private function canRollback(AuditLog $auditLog): bool
    {
        // Implement your validation logic
        return $auditLog->getCreatedAt() > new \DateTime('-24 hours');
    }
}

Flushing Audit Data

Manage audit data lifecycle:

<?php

namespace App\Command;

use BenMacha\AuditBundle\Service\AuditCleanupService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class AuditCleanupCommand extends Command
{
    protected static $defaultName = 'audit:cleanup';
    
    public function __construct(
        private AuditCleanupService $cleanupService
    ) {
        parent::__construct();
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Clean up old audit logs
        $deleted = $this->cleanupService->cleanupExpiredLogs();
        $output->writeln("Deleted {$deleted} expired audit logs");
        
        // Optimize audit tables
        $this->cleanupService->optimizeTables();
        $output->writeln('Optimized audit tables');
        
        return Command::SUCCESS;
    }
}

Customizing Views

Override default templates:

  1. Create templates/bundles/AuditBundle/ directory
  2. Copy templates from vendor/benmacha/audit-bundle/src/Resources/views/
  3. Customize as needed
{# templates/bundles/AuditBundle/audit/index.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}Custom Audit Logs{% endblock %}

{% block body %}
    <div class="custom-audit-container">
        <h1>My Custom Audit Interface</h1>
        
        {# Include original content with modifications #}
        {% include '@Audit/audit/_table.html.twig' %}
    </div>
{% endblock %}

API Reference

REST Endpoints

Method Endpoint Description
GET /api/audit/logs Get all audit logs
GET /api/audit/logs/{id} Get specific audit log
GET /api/audit/logs/entity/{class}/{id} Get logs for entity
POST /api/audit/rollback/{id} Rollback to audit log
DELETE /api/audit/logs/{id} Delete audit log
GET /api/audit/stats Get audit statistics

Query Parameters

  • limit: Number of results (default: 25)
  • offset: Offset for pagination (default: 0)
  • entity: Filter by entity class
  • operation: Filter by operation type
  • user: Filter by user ID
  • from: Start date (ISO 8601)
  • to: End date (ISO 8601)

Response Format

{
    "data": [
        {
            "id": 123,
            "entityClass": "App\\Entity\\User",
            "entityId": "456",
            "operation": "update",
            "oldValues": {"email": "old@example.com"},
            "newValues": {"email": "new@example.com"},
            "userId": 789,
            "ipAddress": "192.168.1.1",
            "userAgent": "Mozilla/5.0...",
            "createdAt": "2024-01-15T10:30:00Z",
            "metadata": {"reason": "Profile update"}
        }
    ],
    "total": 1,
    "limit": 25,
    "offset": 0
}

Performance Optimization

Asynchronous Processing

Enable async processing for high-traffic applications:

# config/packages/audit.yaml
audit:
    async_processing: true
    
# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            audit: '%env(MESSENGER_TRANSPORT_DSN)%'
        
        routing:
            'BenMacha\AuditBundle\Message\AuditMessage': audit

Database Optimization

  1. Indexing: The bundle automatically creates optimized indexes
  2. Partitioning: Consider table partitioning for large datasets
  3. Archiving: Use the cleanup service to archive old data

Memory Management

// Batch processing for large operations
$batchSize = 100;
for ($i = 0; $i < $totalRecords; $i += $batchSize) {
    $entities = $repository->findBy([], null, $batchSize, $i);
    
    foreach ($entities as $entity) {
        // Process entity
    }
    
    $entityManager->flush();
    $entityManager->clear(); // Clear memory
}

Security Considerations

Access Control

# config/packages/security.yaml
security:
    access_control:
        - { path: ^/admin/audit, roles: ROLE_AUDITOR }
        - { path: ^/api/audit, roles: ROLE_API_USER }

Data Protection

  1. Encryption: Use #[AuditSensitive] for sensitive fields
  2. Masking: Hide sensitive data in UI
  3. Retention: Configure appropriate retention periods
  4. Access Logging: All access is automatically logged

Troubleshooting

Common Issues

  1. Missing Audit Logs

    • Check entity has #[Auditable] attribute
    • Verify bundle is enabled
    • Check database permissions
  2. Performance Issues

    • Enable async processing
    • Optimize database indexes
    • Reduce retention period
  3. Memory Issues

    • Use batch processing
    • Clear entity manager regularly
    • Increase PHP memory limit

Debug Mode

Enable debug logging:

# config/packages/dev/monolog.yaml
monolog:
    handlers:
        audit:
            type: stream
            path: '%kernel.logs_dir%/audit.log'
            level: debug
            channels: ['audit']

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

Development Setup

git clone https://github.com/benmacha/audit-bundle.git
cd audit-bundle
composer install
php bin/phpunit

Code Quality

composer run quality  # Run all quality checks
composer run cs-fix   # Fix coding standards
composer run phpstan  # Static analysis
composer run psalm    # Additional static analysis

License

This bundle is released under the MIT License. See LICENSE for details.

Support

Changelog

See CHANGELOG.md for version history.

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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui