1. Go to this page and download the library: Download rasuvaeff/yii3-outbox library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
rasuvaeff / yii3-outbox example snippets
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
use Rasuvaeff\Yii3Outbox\InMemoryStorage;
use Rasuvaeff\Yii3Outbox\Outbox;
$clock = new class implements ClockInterface {
public function now(): DateTimeImmutable { return new DateTimeImmutable(); }
};
$outbox = new Outbox(storage: $storage, clock: $clock);
$message = $outbox->record(
type: 'order.created',
payload: json_encode(['orderId' => 42]),
aggregateId: 'order-42',
);
$db->transaction(static function () use ($orders, $outbox, $order, $json): void {
$orders->insert($order);
$outbox->record(
type: 'order.created',
payload: $json,
aggregateId: $order->id,
);
});
use Rasuvaeff\Yii3Outbox\MessageIdGeneratorInterface;
// symfony/uid
final readonly class Uuid7IdGenerator implements MessageIdGeneratorInterface
{
public function generate(): string
{
return \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
}
}
// ramsey/uuid — equally monotonic within the same millisecond
final readonly class RamseyUuid7IdGenerator implements MessageIdGeneratorInterface
{
public function generate(): string
{
return \Ramsey\Uuid\Uuid::uuid7()->toString();
}
}
$outbox = new Outbox(storage: $storage, clock: $clock, idGenerator: new Uuid7IdGenerator());
use Rasuvaeff\Yii3Outbox\StorageInterface;
use Rasuvaeff\Yii3Outbox\OutboxMessage;
final class DbStorage implements StorageInterface
{
public function save(OutboxMessage $message): void
{
// INSERT INTO outbox ... ON CONFLICT(id) DO UPDATE ...
// Must run on the caller's connection so it commits with the business write.
}
public function claim(array $types = [], int $limit = 1000): array
{
// Atomically: SELECT ids of status = 'pending' [AND type IN (:types)]
// LIMIT :limit FOR UPDATE SKIP LOCKED
// then UPDATE outbox SET status = 'processing', claimed_by = :worker
// WHERE id IN (...) — and return the claimed rows.
// Every claimed message must end up markPublished(), markFailed(),
// or save($msg->withStatus(Pending)); none may stay Processing.
}
public function findPending(array $types = [], int $limit = 1000): array
{
// SELECT * FROM outbox WHERE status = 'pending'
// [AND type IN (:types)] LIMIT :limit -- empty $types = all types
// Read-only: no atomicity, so two workers would both get the same rows.
// For retry support, also return status = 'pending' with attempts > 0
}
public function markPublished(OutboxMessage $message): void
{
// UPDATE outbox SET status = 'published' WHERE id = ?
}
public function markFailed(OutboxMessage $message): void
{
// UPDATE outbox SET status = 'failed' WHERE id = ?
}
public function getById(string $id): ?OutboxMessage
{
// SELECT * FROM outbox WHERE id = ?
}
}
use Rasuvaeff\Yii3Outbox\PublisherInterface;
use Rasuvaeff\Yii3Outbox\OutboxMessage;
use Rasuvaeff\Yii3Outbox\PublishException;
final class RabbitPublisher implements PublisherInterface
{
public function publish(OutboxMessage $message): void
{
try {
// publish to RabbitMQ, Kafka, etc.
} catch (\Throwable $e) {
throw new PublishException(
message: $e->getMessage(),
outboxMessage: $message,
previous: $e,
);
}
}
}
use Rasuvaeff\Yii3Outbox\Processor;
use Rasuvaeff\Yii3Outbox\RetryPolicy;
$processor = new Processor(
storage: $storage,
publisher: $publisher,
retryPolicy: new RetryPolicy(maxAttempts: 3, delaySeconds: 60),
clock: $clock,
batchSize: 100,
);
$result = $processor->process();
// $result->published — successfully published
// $result->failed — publish exceptions (message kept Pending if retries remain)
// $result->skipped — not yet ready for retry