Skip to main content
Version: 7.x

Audit Viewer

Web interface for browsing audit logs

The bundle includes a web interface for browsing audit logs.

✨ Enabling the Viewer

# config/packages/dh_auditor.yaml
dh_auditor:
providers:
doctrine:
viewer: true

Or with options:

dh_auditor:
providers:
doctrine:
viewer:
enabled: true
page_size: 50

🛤️ Routes

The viewer registers three routes:

RouteURLDescription
dh_auditor_list_audits/auditList all audited entities
dh_auditor_show_entity_stream/audit/{entity}/{id?}Entity audit stream
dh_auditor_show_transaction_stream/audit/transaction/{hash}Transaction details

Route Configuration

With Symfony Flex, routes are auto-configured. Otherwise, create config/routes/dh_auditor.yaml:

dh_auditor:
resource: "@DHAuditorBundle/Controller/"
type: auditor

📄 Pages

Entity List (/audit)

Displays all audited entities with:

  • 📋 Entity class name
  • 🗄️ Audit table name
  • 🔢 Number of audit entries
  • 🔗 Link to view history

Entity Stream (/audit/{entity})

Shows audit entries for an entity:

  • 📅 Chronological list (newest first)
  • 🏷️ Operation type (insert/update/remove/associate/dissociate)
  • 👤 User and timestamp
  • 📝 Changed properties (diff)

Filter by specific entity ID:

/audit/App-Entity-User/42

🔍 Filters

The entity stream page includes filters to narrow down audit entries:

Action Type Filter Filter by operation type:

  • insert - Record created
  • update - Record updated
  • remove - Record deleted
  • associate - Relation added
  • dissociate - Relation removed

User Filter Filter by the user who performed the action:

  • All registered users who have made changes
  • Anonymous (for actions without user attribution)
  • CLI commands (each command is tracked by its name, e.g., app:import-users)

TIP

Filters can be combined and are preserved during pagination.

URL parameters:

/audit/App-Entity-User?type=update&user=42
/audit/App-Entity-User?type=insert&user=__anonymous__

Transaction View (/audit/transaction/{hash})

Groups all changes from a single database transaction across all entities.

📊 Activity Graph

Each entity card displays a visual sparkline graph showing audit activity over time.

Configuration

dh_auditor:
providers:
doctrine:
viewer:
enabled: true
activity_graph:
enabled: true # Show/hide the graph (default: true)
days: 30 # Number of days to display (default: 30, max: 30)
layout: 'bottom' # Graph layout: 'bottom' or 'inline' (default: 'bottom')
cache:
enabled: true # Enable caching (default: true)
pool: 'cache.app' # Cache pool service ID
ttl: 300 # Cache TTL in seconds (default: 300)

Layout Options

LayoutDescription
bottomSparkline displayed below the entity info, full width (default)
inlineCompact sparkline displayed in the header row, next to event count

Caching

The activity graph uses caching to improve performance on large audit tables.

NOTE

Caching requires symfony/cache:

composer require symfony/cache

If symfony/cache is not installed, the graph will still work but without caching.

Cache with Tags

If your cache pool supports tags (TagAwareCacheInterface), the bundle uses the tag dh_auditor.activity for efficient cache invalidation.

🗑️ Clear Cache Command

Clear the activity graph cache manually:

# Clear all activity graph cache
php bin/console audit:cache:clear

# Clear cache for a specific entity
php bin/console audit:cache:clear --entity="App\Entity\User"

IMPORTANT

Clearing all cache requires a cache pool that supports tags. If your cache pool doesn't support tags, you can only clear cache for specific entities.

Display Behavior

StateBehavior
Graph disabled (enabled: false)Activity graph section is completely hidden
Graph enabled, no dataPlaceholder with "No recent activity" message
Graph enabled, with dataBars are normalized (tallest bar = 100%)

🌙 Dark Mode

The viewer includes a dark/light mode toggle button in the header.

Behavior

  • Default: Follows system preference (prefers-color-scheme)
  • Manual toggle: Click the sun/moon icon in the header
  • Persistence: User preference is saved in localStorage

The toggle works without page reload and persists across sessions.

🔒 Access Control

Via Configuration

dh_auditor:
providers:
doctrine:
entities:
App\Entity\User:
roles:
view:
- ROLE_ADMIN

Via Attributes

#[Audit\Auditable]
#[Audit\Security(view: ['ROLE_ADMIN'])]
class User {}

Via Symfony Security

# config/packages/security.yaml
security:
access_control:
- { path: ^/audit, roles: ROLE_ADMIN }

🔗 URL Format

Entity namespaces use dashes instead of backslashes:

App\Entity\User → App-Entity-User

Helper methods:

use DH\AuditorBundle\Helper\UrlHelper;

// Namespace to URL parameter
$param = UrlHelper::namespaceToParam('App\Entity\User');
// Returns: 'App-Entity-User'

// URL parameter to namespace
$namespace = UrlHelper::paramToNamespace('App-Entity-User');
// Returns: 'App\Entity\User'

🔧 Generating URLs

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

// Entity list
$url = $urlGenerator->generate('dh_auditor_list_audits');

// Entity stream
$url = $urlGenerator->generate('dh_auditor_show_entity_stream', [
'entity' => 'App-Entity-User',
]);

// Specific entity
$url = $urlGenerator->generate('dh_auditor_show_entity_stream', [
'entity' => 'App-Entity-User',
'id' => 42,
]);

// With filters
$url = $urlGenerator->generate('dh_auditor_show_entity_stream', [
'entity' => 'App-Entity-User',
'type' => 'update',
'user' => '42',
]);

// Transaction
$url = $urlGenerator->generate('dh_auditor_show_transaction_stream', [
'hash' => $transactionHash,
]);

🎨 Customization

Override Templates

Create files in templates/bundles/DHAuditorBundle/:

templates/bundles/DHAuditorBundle/
├── Audit/
│ ├── audits.html.twig # Entity list
│ ├── entity_stream.html.twig # Entity audit stream
│ ├── transaction_stream.html.twig # Transaction view
│ ├── entry.html.twig # Single entry
│ └── helpers/
│ ├── helper.html.twig # Helper macros
│ └── pager.html.twig # Pagination
└── layout.html.twig # Base layout

Custom Layout

{# templates/bundles/DHAuditorBundle/layout.html.twig #}
{% extends 'base.html.twig' %}

{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('bundles/dhauditor/app.css') }}">
{% endblock %}

{% block body %}
<div class="container">
{% block dh_auditor_content %}{% endblock %}
</div>
{% endblock %}

Template Blocks

BlockDescriptionAvailable in
titlePage titleAll pages
stylesheetsCSS includesAll pages
dh_auditor_contentMain content areaAll pages
dh_auditor_headerSub-header with back link & filtersEntity stream, Transaction view
dh_auditor_pagerPaginationEntity stream
javascriptsJavaScript includesAll pages

📦 Assets

Install assets:

bin/console assets:install

Assets are installed to public/bundles/dhauditor/.

🌍 Translations

Available translations:

LanguageCode
Englishen
Frenchfr
Germande
Spanishes
Italianit
Dutchnl
Russianru
Ukrainianuk
Estonianet

The viewer uses your application's locale automatically.

🚫 Disabling the Viewer

dh_auditor:
providers:
doctrine:
viewer: false

Routes are not registered, /audit returns 404.


🚀 Next Steps