rasuvaeff / yii3-audit-log-db
Database-backed audit writer for rasuvaeff/yii3-audit-log
Requires
- php: 8.3 - 8.5
- rasuvaeff/yii3-audit-log: ^1.0
- yiisoft/db: ^2.0
- yiisoft/db-migration: ^2.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.51
- friendsofphp/php-cs-fixer: ^3.95
- infection/infection: ^0.33
- maglnet/composer-require-checker: ^4.17
- rector/rector: ^2.4
- roave/backward-compatibility-check: ^8.0
- testo/bridge-infection: ^0.1.6
- testo/testo: ^0.10.25
- vimeo/psalm: ^6.16
- yiisoft/cache: ^3.2
- yiisoft/db-sqlite: ^2.0
- yiisoft/injector: ^1.2
- yiisoft/test-support: ^3.1
This package is auto-updated.
Last update: 2026-07-25 16:55:50 UTC
README
Database-backed AuditWriter for rasuvaeff/yii3-audit-log.
Persists audit events to any yiisoft/db-compatible database (SQLite, MySQL, PostgreSQL, etc.).
Using an AI coding assistant? llms.txt has a compact API reference you can use.
Requirements
- PHP 8.3+
rasuvaeff/yii3-audit-log^1.0yiisoft/db^2.0
Installation
composer require rasuvaeff/yii3-audit-log rasuvaeff/yii3-audit-log-db
Migration
Register the bundled migration by namespace — no vendor paths:
// config/common/di/migration.php use Yiisoft\Db\Migration\Service\MigrationService; return [ MigrationService::class => [ 'setSourceNamespaces()' => [[ 'App\\Migration', 'Rasuvaeff\\Yii3AuditLogDb\\Migration', ]], ], ];
./yii migrate:up
Custom table name
Set it in params — the same value reaches the migration and the writer:
// config/common/params.php 'rasuvaeff/yii3-audit-log-db' => [ 'table' => 'my_audit_log', 'table_prefix' => '', // prepended to `table`; e.g. 'rsv_' → rsv_my_audit_log ],
Index names follow the table name (idx_my_audit_log_subject, …), so two
installations can share one PostgreSQL schema — index names are unique per
schema there, not per table.
Do not configure the migration through the DI container.
M...::class => ['__construct()' => ['table' => ...]]does not work: the migration is built byInjector::make(), which resolves arguments by type and never reads a container definition keyed by the migration's own class. Worse, adding that definition makes the container fatal at build time in every request, because the class is not autoloadable until the migration runner requires it. That recipe was documented in 1.x; it never worked.
The migration creates:
| Column | Type | Notes |
|---|---|---|
id |
VARCHAR(32) PK | 32-char hex from AuditLogger |
actor_type |
VARCHAR(32) | user / system |
actor_id |
VARCHAR(255) NULL | null for system actor |
actor_name |
VARCHAR(255) NULL | display name, optional |
action |
VARCHAR(64) | create / update / delete / custom |
subject_type |
VARCHAR(255) | entity type, e.g. order |
subject_id |
VARCHAR(255) | entity id |
changes |
TEXT | JSON array of {field, old, new} objects |
occurred_at |
VARCHAR(30) | Y-m-d H:i:s UTC |
request_id |
VARCHAR(255) NULL | from AuditMetadata |
ip |
VARCHAR(45) NULL | from AuditMetadata |
user_agent |
TEXT NULL | from AuditMetadata |
Indexes: (subject_type, subject_id, occurred_at), (actor_type, actor_id, occurred_at), (occurred_at).
Yii3 config-plugin
Install rasuvaeff/yii3-audit-log (core) and rasuvaeff/yii3-audit-log-db (adapter).
The adapter's config/di.php automatically binds AuditWriter to DbAuditWriter.
The core's config/di.php wires AuditLogger. You only need to bind ClockInterface
in your application config:
// config/common/di/clock.php use Psr\Clock\ClockInterface; return [ ClockInterface::class => MySystemClock::class, ];
Custom table name via params:
// config/common/params.php return [ 'rasuvaeff/yii3-audit-log-db' => [ 'table' => 'my_audit_log', ], ];
Usage
Write via AuditLogger
use Rasuvaeff\Yii3AuditLog\AuditActor; use Rasuvaeff\Yii3AuditLog\AuditChangeSet; use Rasuvaeff\Yii3AuditLog\AuditLogger; use Rasuvaeff\Yii3AuditLog\AuditSubject; // Injected via DI: /** @var AuditLogger $logger */ $logger->logChange( actor: AuditActor::user(id: (string) $user->id, name: $user->name), subject: AuditSubject::of(type: 'order', id: (string) $order->id), changes: AuditChangeSet::fromArrays(old: $before, new: $after), );
Use directly
use Rasuvaeff\Yii3AuditLogDb\DbAuditWriter; $writer = new DbAuditWriter(db: $db, table: 'audit_log'); $writer->write(event: $auditEvent);
Security
DbAuditWritervalidates the table name against/^[A-Za-z_]\w*(\.[A-Za-z_]\w*)?$/— schema-qualified names likepublic.audit_logare allowed; arbitrary strings are rejected.- All event field values are passed as bound parameters via
yiisoft/db— no SQL injection risk. changesvalues are whateverAuditChangeSetcontains. ApplySensitiveValueMaskerinAuditLoggerbefore this writer runs (default in core DI).
Examples
See examples/ for runnable scripts.
Dependency analysers
This leaf package is selected by the root application through config-plugin and may legitimately have no class reference in an autoloaded source directory. Keep the direct dependency: the application, not a core package, selects the backend or bridge. Scope the Composer Dependency Analyser exception to this package:
use ShipMonk\ComposerDependencyAnalyser\Config\Configuration; use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType; return (new Configuration())->ignoreErrorsOnPackage( 'rasuvaeff/yii3-audit-log-db', [ErrorType::UNUSED_DEPENDENCY], );
composer-require-checker detects used but undeclared symbols, not unused
packages, so this config-only dependency needs no require-checker suppression.
Development
# from monorepo root (/home/rasuvaeff/projects/rasuvaeff) make -C yii3-audit-log-db install make -C yii3-audit-log-db build make -C yii3-audit-log-db cs-fix make -C yii3-audit-log-db test
Or with Docker directly:
docker run --rm -v "$PWD":/repo -w /repo/yii3-audit-log-db composer:2 composer build
License
BSD-3-Clause. See LICENSE.md.