event-engine/php-persistence
Event Engine PHP Persistence Package providing persistence layer utilities for PHP-based event-sourced and CQRS applications. Supports storing and retrieving events and state in a consistent way to integrate with Event Engine workflows.
## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require event-engine/php-persistence:^0.9.2
Register the service provider in config/app.php:
'providers' => [
// ...
EventEngine\Persistence\PersistenceServiceProvider::class,
],
Basic Configuration Publish the config file:
php artisan vendor:publish --provider="EventEngine\Persistence\PersistenceServiceProvider" --tag="config"
Update config/persistence.php with your storage backend (e.g., database, redis, or filesystem).
Note: This package now fully supports PHP 8.0+ and has removed all PHP 8.4 deprecation warnings, making it compatible with modern PHP versions.
First Use Case: Persisting an Event
use EventEngine\Persistence\Persistence;
$persistence = app(Persistence::class);
$event = new YourEventClass(['data' => 'payload']);
// Persist with default strategy
$persistence->persist($event);
// Retrieve later
$storedEvent = $persistence->retrieve($event->getId());
Event Persistence Strategies
database).
$persistence->persist($event, ['strategy' => 'database']);
EventEngine\Persistence\Strategies\StrategyInterface and bind in config/persistence.php:
'strategies' => [
'custom' => \App\Strategies\CustomPersistenceStrategy::class,
],
Event Retrieval
$event = $persistence->retrieve('event-uuid-here');
$events = $persistence->query([
'type' => YourEventClass::class,
'after' => now()->subHours(1),
]);
Event Sourcing Pattern
$stream = $persistence->loadStream('aggregate-id', YourEventClass::class);
foreach ($stream as $event) {
// Replay event
}
Middleware Integration
$persistence->persist($event)->withMiddleware([
\EventEngine\Persistence\Middleware\LogMiddleware::class,
\EventEngine\Persistence\Middleware\ValidateMiddleware::class,
]);
Database Backend
events table has columns: id, type, payload, occurred_at, metadata.Schema::create('events', function (Blueprint $table) {
$table->id();
$table->string('type');
$table->json('payload');
$table->timestamp('occurred_at')->useCurrent();
$table->json('metadata')->nullable();
});
Redis Backend
config/persistence.php:
'backends' => [
'redis' => [
'driver' => 'redis',
'connection' => 'cache',
],
],
Filesystem Backend
storage/app/persistence).Event Metadata
$persistence->persist($event, [
'metadata' => ['user_id' => 123, 'source' => 'api'],
]);
Testing
PersistenceTestCase trait or mock the Persistence facade:
$this->mock(Persistence::class)->shouldReceive('persist')->once();
Payload Serialization
JsonSerializable or use json_encode($payload, JSON_THROW_ON_ERROR).null values or complex objects.
JSON_THROW_ON_ERROR).ID Collisions
Str::uuid()), ensure uniqueness across backends.Str::orderedUuid() for globally unique IDs.Transaction Boundaries
DB::transaction(function () use ($persistence, $event) {
$persistence->persist($event);
// Other DB operations...
});
Backend-Specific Quirks
type and occurred_at for query performance.redis-cli --scan.Storage::lock().Event Type Registration
'event_types' => [
\App\Events\UserCreated::class,
\App\Events\OrderPlaced::class,
],
Enable Logging
Add to config/persistence.php:
'debug' => env('PERSISTENCE_DEBUG', false),
Logs will appear in storage/logs/laravel.log.
Query Inspection For database backend, enable query logging:
DB::enableQueryLog();
$persistence->query([...]);
dd(DB::getQueryLog());
Common Errors
JsonSerializable or #[AllowDynamicProperties] if needed.config/persistence.php has valid backend settings.Custom Backends
Implement EventEngine\Persistence\Backends\BackendInterface:
class S3Backend implements BackendInterface {
public function persist(Event $event, array $options) { ... }
public function retrieve(string $id) { ... }
// ...
}
Bind in config/persistence.php:
'backends' => [
's3' => \App\Backends\S3Backend::class,
],
Event Transformers Modify payloads before/after persistence:
$persistence->persist($event)->withTransformer(
\App\Transformers\EncryptPayloadTransformer::class
);
Hooks
Subscribe to persistence events via Laravel’s events facade:
Event::listen(\EventEngine\Persistence\Events\EventPersisted::class, function ($event) {
// Post-persistence logic
});
Batch Operations
For bulk persistence, use the batch method:
$persistence->batch($events)->persist();
Supports custom batch sizes and error handling.
Type Safety Leverage PHP 8.0+ features like union types or attributes for event classes:
#[Attribute]
class EventAttribute { ... }
#[EventAttribute]
class UserCreated { ... }
Named Arguments Use named arguments for clarity in persistence options:
$persistence->persist($event, strategy: 'database', metadata: ['user_id' => 123]);
Constructor Property Promotion Simplify event class definitions:
class UserCreated {
public function __construct(
public string $userId,
public string $name,
) {}
}
PHP 8.4+ Compatibility
JSON_THROW_ON_ERROR for stricter JSON validation.Modern PHP Features
How can I help you explore Laravel packages today?