PHPackages                             precision-soft/symfony-doctrine-audit - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. precision-soft/symfony-doctrine-audit

ActiveSymfony-bundle[Database &amp; ORM](/categories/database)

precision-soft/symfony-doctrine-audit
=====================================

doctrine audit library

v3.4.4(2w ago)021MITPHPPHP &gt;=8.2

Since Sep 17Pushed 2w agoCompare

[ Source](https://github.com/precision-soft/symfony-doctrine-audit)[ Packagist](https://packagist.org/packages/precision-soft/symfony-doctrine-audit)[ Docs](https://github.com/precision-soft/symfony-doctrine-audit)[ RSS](/packages/precision-soft-symfony-doctrine-audit/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (10)Dependencies (56)Versions (23)Used By (0)

Symfony Doctrine Audit
======================

[](#symfony-doctrine-audit)

[![PHP >= 8.2](https://camo.githubusercontent.com/8f0af9c5395ae4ef8ba7a7ad65fa61c44927ea9c3eb3be91a13c678254f29bd4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e322d383839324246)](https://www.php.net/)[![PHPStan Level 8](https://camo.githubusercontent.com/44dc5f71fec76653887c975fe3db546a82ff603d094798eb6414a38369db1f44/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068707374616e2d6c6576656c253230382d627269676874677265656e)](https://phpstan.org/)[![Code Style PER-CS2.0](https://camo.githubusercontent.com/5cbab3b5c635536159b4d0a5ef49ebc70fcc20757f82d5f83bc251d872914301/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d5045522d2d4353322e302d626c7565)](https://www.php-fig.org/per/coding-style/)[![License MIT](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)

**You may fork and modify it as you wish.**

Any suggestions are welcomed.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.2
- Symfony 7.\*
- Doctrine ORM 3.\*
- Doctrine DBAL 4.\*

Installation
------------

[](#installation)

```
composer require precision-soft/symfony-doctrine-audit
```

Register the bundle in `config/bundles.php` (if not auto-discovered):

```
return [
    PrecisionSoft\Doctrine\Audit\PrecisionSoftDoctrineAuditBundle::class => ['all' => true],
];
```

How it works
------------

[](#how-it-works)

The library hooks into Doctrine's `onFlush` and `postFlush` events to capture entity changes automatically:

1. **Entity detection** -- Mark entities for auditing with the `#[Auditable]` PHP attribute. Individual fields can be excluded with `#[Ignore]`.
2. **Change capture** -- During Doctrine's flush cycle, the auditor inspects the Unit of Work to collect inserts, updates, and deletes. For updates, the full change set (old and new values) is recorded.
3. **Storage** -- Captured changes are wrapped in a `StorageDto` and dispatched to one or more storage backends (Doctrine tables, JSONL files, or a custom service). Storages can be synchronous or asynchronous.
4. **Transaction grouping** -- All changes within a single flush are grouped under one transaction record that includes the username (provided by a `TransactionProviderInterface` implementation) and a timestamp.

Limitations
-----------

[](#limitations)

Auditing is driven by Doctrine ORM flush events, so a few categories of changes are intentionally **not** captured:

- **To-many / inverse-side association changes** -- Modifications to `OneToMany`, `ManyToMany`, and inverse-side collections (adding/removing related entities) are surfaced by Doctrine as `PersistentCollection` change-set entries and are not recorded. Only owning-side to-one associations and scalar fields are audited. If you need to audit a relationship change, audit the owning side (e.g. the join entity of a many-to-many).
- **Bulk DQL / DBAL operations** -- `UPDATE`/`DELETE` issued via DQL or raw DBAL bypass the Unit of Work and therefore dispatch no flush events, so they produce no audit rows. Mutate entities through the ORM (persist/remove + flush) when an audit trail is required.

Configuration reference
-----------------------

[](#configuration-reference)

```
precision_soft_doctrine_audit:
    storages:
        # Doctrine storage -- writes audit rows into a dedicated database
        :
            type: doctrine                     # required
            entity_manager:           # required -- the entity manager for the audit database
            connection:        # optional -- defaults to the entity manager's connection
            logger:         # optional
            config:
                transaction_table_name: 'audit_transaction'  # optional

        # File storage -- appends JSONL entries to a file
        :
            type: file                         # required
            file: '%kernel.project_dir%/var/audit.log'  # required

        # Custom storage -- delegates to your own StorageInterface implementation
        :
            type: custom                       # required
            service: App\Service\MyStorage     # required -- must implement StorageInterface

    auditors:
        :
            entity_manager: default            # the source entity manager to audit (default: 'default')
            connection:        # optional -- defaults to the entity manager name
            storages:                           # required -- list of storage names from above
                -
            synchronous_storages:              # optional -- subset of storages executed synchronously (defaults to all)
                -
            transaction_provider: App\Service\TransactionProvider  # required -- must implement TransactionProviderInterface
            logger:         # optional
            ignored_fields:                    # optional -- field names to globally ignore
                - created
                - modified
```

Performance notes
-----------------

[](#performance-notes)

- The auditor reads entity metadata on first flush and caches it for subsequent flushes within the same request.
- Each audited flush triggers one INSERT per transaction plus one INSERT per changed entity per storage. For high-throughput systems, consider using asynchronous storages (e.g., a RabbitMQ-backed custom storage) so that only the message publish happens synchronously.
- The `ignored_fields` option (both global and per-entity via `#[Ignore]`) reduces the number of columns tracked and therefore the volume of audit data written.
- File storage appends JSONL lines and does not open a database connection, making it the lightest option for development or low-volume environments.

Usage
-----

[](#usage)

### Sample config and storage

[](#sample-config-and-storage)

```
precision_soft_doctrine_audit:
    storages:
        doctrine_one:
            type: doctrine
            entity_manager: audit_em_one
            config: # \PrecisionSoft\Doctrine\Audit\Storage\Doctrine\Configuration
                transaction_table_name: 'audit_transaction'
        file:
            type: file
            file: '%kernel.project_dir%/var/audit.log'
        doctrine_two:
            type: doctrine
            entity_manager: audit_em_two
            config: # \PrecisionSoft\Doctrine\Audit\Storage\Doctrine\Configuration
                transaction_table_name: 'audit_transaction'
        rabbit:
            type: custom
            service: Acme\Shared\Service\AuditStorageService
    auditors:
        doctrine:
            entity_manager: source_em_one
            storages:
                - doctrine
            transaction_provider: Acme\Shared\Service\AuditTransactionProviderService
            logger: monolog.logger
            ignored_fields:
                - created
                - modified
        file:
            entity_manager: source_em_two
            storages:
                - file
            transaction_provider: Acme\Shared\Service\AuditTransactionProviderService
        async:
            entity_manager: source_em_three
            storages:
                - doctrine_two
                - rabbit
            synchronous_storages:
                - rabbit # the rabbit storage will publish the storage dto and a consumer will be required to save to the doctrine storage
            transaction_provider: Acme\Shared\Service\AuditTransactionProviderService
```

```
services:
    Acme\Shared\Service\AuditStorageService:
        arguments:
            $storage: '@precision_soft_doctrine_audit.storage.doctrine_two'
```

```
