rasuvaeff/yii3-outbox-db

Database-backed outbox storage for Yii3

Maintainers

Package info

github.com/rasuvaeff/yii3-outbox-db

pkg:composer/rasuvaeff/yii3-outbox-db

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v2.0.0 2026-07-25 13:27 UTC

README

Stable Version Total Downloads Build Static analysis Psalm Level License Русская версия

Database-backed storage for rasuvaeff/yii3-outbox. Durably persists outbox messages in a yiisoft/db table so a worker can publish or export them asynchronously — surviving process restarts and downstream outages.

Using an AI coding assistant? llms.txt has a compact API reference you can use.

Requirements

  • PHP 8.3+
  • rasuvaeff/yii3-outbox ^1.0
  • yiisoft/db ^2.0, yiisoft/db-migration ^2.0

Installation

composer require rasuvaeff/yii3-outbox-db

Usage

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\\Yii3OutboxDb\\Migration',
        ]],
    ],
];
./yii migrate:up

Set the table name in params — the same value reaches the migration and DbOutboxStorage:

// config/common/params.php
'rasuvaeff/yii3-outbox-db' => [
    'table' => 'my_outbox',
    'table_prefix' => '',   // prepended to `table`; e.g. 'rsv_' → rsv_my_outbox
],

Index names follow the table name (idx_my_outbox_pending), 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 by Injector::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.

Recording and processing

use Rasuvaeff\Yii3Outbox\Outbox;
use Rasuvaeff\Yii3OutboxDb\DbOutboxStorage;

$storage = new DbOutboxStorage(db: $connection);          // ConnectionInterface
$outbox = new Outbox(storage: $storage, clock: $clock);

// request path — durable, no network call to the sink
$outbox->record(type: 'ab.exposure', payload: '{"experiment":"checkout"}');

// worker — fetch a batch of one consumer's types and process them
$pending = $storage->findPending(types: ['ab.exposure', 'ab.conversion'], limit: 1000);

Storage API

Method Purpose
save(OutboxMessage) upsert by id (initial record or retry re-save)
findPending(array $types = [], int $limit = 1000) pending rows, optional type filter, created_at ASC
markPublished(OutboxMessage) re-save with Published status
markFailed(OutboxMessage) re-save with Failed status
getById(string $id) single message or null
deleteByStatus(OutboxStatus) housekeeping (e.g. purge Published)

findPending's $types filter lets several consumers — a generic Processor and a specialized exporter — share one outbox without competing for each other's messages.

Yii3 DI

The config-plugin binds StorageInterface to DbOutboxStorage from config/di.php. Core yii3-outbox binds nothing, so this backend (or the application) is the single source of StorageInterface. Set the table name in params:

// config/params.php
'rasuvaeff/yii3-outbox-db' => ['table' => 'outbox'],

Security

  • All values are written through yiisoft/db parameterized commands.
  • OutboxRowMapper validates every column and rejects corrupt rows with InvalidOutboxRowException — no silent coercion.
  • Payloads may contain PII; retention/purging is the application's responsibility (deleteByStatus helps).

Examples

Runnable scripts live in examples/.

Development

make build        # full gate: validate + normalize + require-checker + cs + psalm + test
make cs-fix
make psalm
make test
make test-coverage
make mutation

Core yii3-outbox is consumed via a path repository while unpublished — see AGENTS.md for the monorepo-root Docker invocation.

License

BSD-3-Clause. See LICENSE.md.