PHPackages                             wedevelopnl/audit-log - 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. [Logging &amp; Monitoring](/categories/logging)
4. /
5. wedevelopnl/audit-log

ActiveSymfony-bundle[Logging &amp; Monitoring](/categories/logging)

wedevelopnl/audit-log
=====================

Immutable, self-contained audit trail for Symfony and Doctrine.

6.0.0-rc.2(1mo ago)0409↓25.2%BSD-3-ClausePHPPHP &gt;=8.5CI passing

Since Jun 1Pushed 1mo agoCompare

[ Source](https://github.com/wedevelopnl/audit-log)[ Packagist](https://packagist.org/packages/wedevelopnl/audit-log)[ RSS](/packages/wedevelopnl-audit-log/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (27)Versions (4)Used By (0)

wedevelopnl/audit-log
=====================

[](#wedevelopnlaudit-log)

Immutable, self-contained audit trail for Symfony and Doctrine.

An audit record answers — durably and credibly — **who** did **what**, to **what**, **when**, from **where**, and **what changed**, and keeps answering it regardless of what later happens to the rest of the system. Records are immutable snapshots of a past fact: they survive deletion of the actor, the subject, and the producing code.

The package ships as a Symfony bundle: a framework-free core (value objects, the `AuditEvent` contract, the `Recorder` and read ports) plus Doctrine persistence and Symfony runtime adapters, pre-wired by the bundle. The core stays free of Symfony and Doctrine ([ADR-0009](docs/adr/0009-symfony-bundle-packaging.md)).

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

[](#requirements)

- PHP 8.5+
- Symfony 8.0 (`framework-bundle`, `security-core`, `translation`, and the components pulled in transitively)
- Doctrine (`dbal` ^4, `orm` ^3.6, `doctrine-bundle` ^3.2)

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

[](#installation)

```
composer require wedevelopnl/audit-log
```

There is no Flex recipe; register the bundle manually in `config/bundles.php`:

```
return [
    // ...
    WeDevelop\AuditLog\AuditLogBundle::class => ['all' => true],
];
```

The bundle auto-registers its Doctrine DBAL types and the `AuditRecordEntity` mapping. See [docs/installation.md](docs/installation.md) for the migration, the recommended append-only database grant, and the services you must provide.

Design
------

[](#design)

Three responsibilities are deliberately separated:

ResponsibilityTypeConcernDescribe an act`AuditEvent`Pure data + phrasing. No clock, identity, or services.Capture the moment`Recorder`Resolves time, actor, origin, subject label; freezes everything.The durable read shape`AuditRecord`Immutable snapshot, interpretable without the producing code.Query the trail`RecordReader`Paginated, filterable reads (`AuditQuery` → `AuditPage`) for display.The architecture derives from six governing properties — immutable, self-contained, faithful to the moment, attributable, intelligible, queryable. The rationale lives in the [Architecture Decision Records](docs/adr/).

Usage
-----

[](#usage)

Describe an auditable act by implementing `AuditEvent` (or extending `AbstractAuditEvent` for sane defaults):

```
use WeDevelop\AuditLog\Event\AbstractAuditEvent;
use WeDevelop\AuditLog\Event\Changeset;
use WeDevelop\AuditLog\Event\FieldChange;
use WeDevelop\AuditLog\Event\Subject;

final readonly class UserRoleChanged extends AbstractAuditEvent
{
    public function __construct(
        private string $userId,
        private string $from,
        private string $to,
    ) {
    }

    public function code(): string
    {
        return 'user.role_changed';
    }

    public function subject(): Subject
    {
        return new Subject(User::class, $this->userId);
    }

    public function changes(): Changeset
    {
        return new Changeset(FieldChange::of('role', $this->from, $this->to));
    }

    protected function parameters(): array
    {
        return ['from' => $this->from, 'to' => $this->to];
    }
}
```

Record it through the `Recorder` — the single write seam, autowired by the bundle. It captures the ambient strands of the moment (clock, acting principal, origin, subject label) and appends a frozen record:

```
$recorder->record(new UserRoleChanged($userId, 'member', 'admin'));
```

To attach human-readable subject labels, provide a `SubjectLabeller` (the default returns none); read the trail back through `RecordReader`. See [docs/installation.md](docs/installation.md) for wiring.

Sensitive fields are recorded as changed **without** their values:

```
new Changeset(FieldChange::redacted('password'));
```

License
-------

[](#license)

BSD 3-Clause. See [LICENSE](LICENSE). © 2026 WeDevelop.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance90

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

2

Last Release

52d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7a41b16aafbe795cfad0b4941b9ac37305e5bba2aefbcf56cc1f0c180928de27?d=identicon)[WeDevelop](/maintainers/WeDevelop)

---

Top Contributors

[![erikfrerejean](https://avatars.githubusercontent.com/u/197732?v=4)](https://github.com/erikfrerejean "erikfrerejean (40 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/wedevelopnl-audit-log/health.svg)

```
[![Health](https://phpackages.com/badges/wedevelopnl-audit-log/health.svg)](https://phpackages.com/packages/wedevelopnl-audit-log)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.9M400](/packages/easycorp-easyadmin-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M754](/packages/sylius-sylius)[contao/core-bundle

Contao Open Source CMS

1231.6M2.8k](/packages/contao-core-bundle)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M215](/packages/sulu-sulu)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M600](/packages/shopware-core)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
