event-engine/php-schema
Event Engine PHP Schema provides PHP type definitions to describe and validate event-driven message payloads. Define schemas for commands, events, and queries with reusable types, enabling consistent serialization, documentation, and tooling across your services.
Installation
composer require event-engine/php-schema
Add to composer.json under autoload:
"autoload": {
"psr-4": {
"App\\": "app/",
"EventEngine\\Schema\\": "vendor/event-engine/php-schema/src/"
}
}
Run composer dump-autoload.
First Use Case
Define a schema for an event (e.g., UserRegistered):
use EventEngine\Schema\EventSchema;
$schema = new EventSchema('UserRegistered');
$schema->addField('user_id', 'integer', true); // Required
$schema->addField('email', 'string', false);
$schema->addField('metadata', 'array', false, ['default' => []]);
Validate an event payload:
$payload = ['user_id' => 123, 'email' => 'test@example.com'];
$validator = $schema->getValidator();
$isValid = $validator->validate($payload); // Returns bool
Key Files to Explore
src/EventSchema.php: Core schema definition logic.src/FieldSchema.php: Field validation rules.src/Validator.php: Payload validation utilities.Reusable Schema Classes
Extend EventSchema for domain-specific schemas:
class UserRegisteredSchema extends EventSchema {
public function __construct() {
parent::__construct('UserRegistered');
$this->addField('user_id', 'integer', true);
$this->addField('email', 'string', true, ['format' => 'email']);
}
}
Dynamic Schema Generation
Load schemas from a config file (e.g., config/events.php):
$schemas = config('events.schemas');
foreach ($schemas as $eventName => $fields) {
$schema = new EventSchema($eventName);
foreach ($fields as $name => $config) {
$schema->addField($name, $config['type'], $config['required']);
}
}
Integration with Laravel Events Use schemas to validate dispatched events:
use Illuminate\Support\Facades\Event;
Event::listen('user.registered', function ($payload) {
$schema = new UserRegisteredSchema();
if (!$schema->getValidator()->validate($payload)) {
throw new \InvalidArgumentException('Invalid event payload');
}
// Proceed with event logic
});
Custom Validators
Extend Validator for domain-specific rules:
use EventEngine\Schema\Validator;
class CustomValidator extends Validator {
protected function validateCustomRule($value, $rule) {
return strpos($value, $rule) !== false;
}
}
Batch Validation Validate multiple events at once:
$events = [
['user_id' => 1, 'email' => 'test@example.com'],
['user_id' => 2, 'email' => 'invalid-email']
];
$schema = new UserRegisteredSchema();
$results = array_map([$schema->getValidator(), 'validate'], $events);
Schema Registry Cache schemas for performance:
$schemaCache = [];
function getSchema($eventName) {
if (!isset($schemaCache[$eventName])) {
$schemaCache[$eventName] = new EventSchema($eventName);
// Load fields dynamically
}
return $schemaCache[$eventName];
}
Field Type Mismatches
string, integer, array, etc.). Ensure payload values match exactly (e.g., 1 vs "1" for integers).filter_var() or json_decode() to normalize types before validation.Circular Dependencies in Schemas
OrderSchema includes UserSchema), validation may fail or hang.Missing Default Values
default values in the schema won’t auto-populate in the validator. You must set them manually.array_merge() to apply defaults:
$payload = array_merge($schema->getDefaults(), $rawPayload);
Case Sensitivity
array_change_key_case()) or use a snake_case/camelCase converter.Detailed Validation Errors The validator returns a boolean by default. Enable detailed errors:
$errors = $schema->getValidator()->validate($payload, true);
// $errors is an array of field => error messages
Schema Dumping Debug schema definitions by dumping the structure:
dd($schema->getFields()); // Returns associative array of fields
Type Coercion Force type coercion during validation:
$validator = $schema->getValidator();
$validator->setCoerceTypes(true); // Attempts to cast values to schema types
Custom Field Types
Extend FieldSchema to support custom types (e.g., uuid):
class UuidFieldSchema extends FieldSchema {
public function validate($value) {
return filter_var($value, FILTER_VALIDATE_UUID) !== false;
}
}
Plugin System Add pre/post-validation hooks:
$validator = $schema->getValidator();
$validator->addPreValidator(function ($payload) {
// Sanitize or transform payload
});
$validator->addPostValidator(function ($payload) {
// Log or enrich payload
});
Integration with Laravel
$this->app->bind(UserRegisteredSchema::class, function () {
return new UserRegisteredSchema();
});
public function handle($request, Closure $next) {
$payload = $request->json()->all();
$schema = app(UserRegisteredSchema::class);
if (!$schema->getValidator()->validate($payload)) {
abort(422, 'Invalid event payload');
}
return $next($request);
}
Performance Optimization
$compiledSchema = $schema->compile();
// $compiledSchema is a frozen version of the schema
$cache = new \Symfony\Component\Cache\Adapter\ArrayAdapter();
$validator = $schema->getValidator();
$validator->setCache($cache);
How can I help you explore Laravel packages today?