Contracts
Alle Interfaces der Jardis-Plattform, ein Package, null Implementierung.
Einführung
In einer hexagonalen Architektur hängt alles an den Interfaces: Domain-Code importiert nur Contracts, Adapter implementieren sie, und zur Bootzeit wird verdrahtet. Wenn diese Interfaces über dutzende Packages verstreut sind, entstehen zirkuläre Abhängigkeiten und Release-Chaos.
jardissupport/contracts löst das radikal: Ein einziges Package enthält alle Interfaces, Enums, Value Objects und Exceptions der gesamten Jardis-Plattform. Keine einzige Implementierung. Jedes Jardis-Package (ob Core, Adapter, Support oder Tools) importiert jardissupport/contracts und findet dort seine Contracts.
- Null Implementierung — nur Interfaces, Enums und Basis-Exceptions
- Single Source of Truth — eine Abhängigkeit statt dutzender
- PSR-first — PSR-3 (Log), PSR-11 (Container), PSR-14 (Events), PSR-16 (Cache), PSR-18 (HTTP) wo Standards existieren
- Interface Segregation — Reader/Writer-Trennung, granulare Query-Builder-Interfaces
Installation
composer require jardissupport/contractsGitHub: jardisSupport/contracts
Dieses Package wird automatisch als Abhängigkeit aller Jardis-Packages installiert.
Namespace-Struktur
Alle Interfaces liegen unter JardisSupport\Contract\:
JardisSupport\Contract\
├── Auth\ ← Authentifizierung, RBAC, Sessions, Tokens
├── ClassVersion\ ← Versionierte Klassen-Auflösung
├── Connection\ ← Basis-Lifecycle (connect/disconnect)
├── Data\ ← Hydration, Identity, FieldMapper
├── DbConnection\ ← PDO-Verbindungen, Connection-Pool
├── DbQuery\ ← SQL Query-Builder
├── DbSchema\ ← Schema-Analyse
├── DotEnv\ ← Environment-Variablen
├── EventListener\ ← Event-Listener-Registrierung
├── Filesystem\ ← Dateisystem-Abstraktion
├── Kernel\ ← DDD-Kernel, BoundedContext, Responses
├── Mailer\ ← E-Mail-Versand
├── Messaging\ ← Multi-Transport Messaging
├── Repository\ ← Generic CRUD
├── Scheduling\ ← Cron und Task-Scheduling
├── Secret\ ← Verschlüsselung
├── Validation\ ← Objekt-Validierung
└── Workflow\ ← Multi-Step-ProzesseInterface-Übersicht nach Domain
Kernel
Das Herz der DDD-Architektur:
| Interface | Beschreibung |
|---|---|
DomainKernelInterface | Service-Locator für BoundedContexts — nullable PSR-Services + Jardis-Services |
BoundedContextInterface | handle(className, ...params): mixed — Pass-Through-Resolver, erbt Payload+Version. context(className, payload, version): mixed — frischer BC-Einstieg, akzeptiert nur BC-Subklassen |
ContextResponseInterface | Mutable Carrier für Daten, Events, Errors und Sub-Ergebnisse |
DomainResponseInterface | Immutable Final-Response mit HTTP-ähnlichem Status |
Auth
| Interface / Enum | Beschreibung |
|---|---|
AuthenticatorInterface | authenticate(Credential): AuthResult |
GuardInterface | check(session, permission): bool, authorize(session, permission): void |
SessionInterface | Authentifizierte Session mit Identity und Metadata |
PasswordHasherInterface | hash(), verify() |
TokenStoreInterface | Token-Persistenz: store(), find(), revoke(), revokeAllForSubject() |
HashedTokenInterface | Gespeicherter Token-Hash |
CredentialInterface | Login-Credential (Password, ApiKey, Token) |
CredentialType | Enum: Password, ApiKey, Token |
TokenType | Enum: Access, Refresh, ApiKey, Verification, PasswordReset |
Data
| Interface | Beschreibung |
|---|---|
HydrationInterface | Entity-Hydration, Change-Tracking, Clone, Diff, toArray |
IdentityInterface | UUID v4/v5/v7, NanoID |
FieldMapperInterface | Bidirektionale Key-Übersetzung |
Repository
| Interface / Klasse | Beschreibung |
|---|---|
RepositoryInterface | insert(), update(), delete(), findById(), findByQuery(), exists() |
PkStrategy | Enum: AUTOINCREMENT, INTEGER, NONE |
PersistException | Exception bei Write-Fehlern |
RecordNotFoundException | Exception bei fehlendem Record |
DbConnection
| Interface | Beschreibung |
|---|---|
DbConnectionInterface | PDO-Wrapper mit Transactions und Reconnect |
ConnectionPoolInterface | Read/Write-Splitting mit Health-Checks |
DatabaseConfigInterface | DSN, Credentials, Options |
DbQuery
Granulare Interfaces für den SQL-Builder:
| Interface | Beschreibung |
|---|---|
DbQueryBuilderInterface | SELECT (CTE, Window, Subquery, Union, ...) |
DbInsertBuilderInterface | INSERT |
DbUpdateBuilderInterface | UPDATE + WHERE |
DbDeleteBuilderInterface | DELETE + WHERE |
DbWhereConditionInterface | WHERE, AND, OR, JSON-Conditions |
DbQueryConditionBuilderInterface | Vergleichsoperatoren |
DbJoinInterface | INNER/LEFT JOIN |
DbOrderLimitInterface | ORDER BY, LIMIT, OFFSET |
DbWindowBuilderInterface | Window Functions |
DbSqlGeneratorInterface | toSql(), getBindings() |
Filesystem
| Interface | Beschreibung |
|---|---|
FilesystemInterface | Kombiniert Reader + Writer |
FilesystemReaderInterface | read(), readStream(), exists(), size(), mimeType(), listContents() |
FilesystemWriterInterface | write(), writeStream(), delete(), copy(), move(), createDirectory() |
FilesystemServiceInterface | Factory für Filesystem-Instanzen |
FileInfoInterface | DTO für Verzeichnislisting |
Messaging
| Interface / Klasse | Beschreibung |
|---|---|
MessagingServiceInterface | Facade: publish() + consume() |
MessagePublisherInterface | Publisher |
MessageConsumerInterface | Consumer |
MessageHandlerInterface | Callback-Contract |
MessageException | Basis-Exception |
ConnectionException | Broker-Verbindungsfehler |
PublishException | Publish-Fehler |
ConsumerException | Consume-Fehler |
Weitere Domains
| Domain | Interfaces |
|---|---|
| Scheduling | ScheduleInterface, ScheduledTaskInterface, CronExpressionInterface, ConstraintInterface, ScheduleViolation |
| Validation | ValidatorInterface, ValueValidatorInterface, ValidationResult |
| Workflow | WorkflowInterface, WorkflowBuilderInterface, WorkflowNodeBuilderInterface, WorkflowConfigInterface, WorkflowContextInterface, WorkflowResultInterface |
| Mailer | MailerInterface, MailMessageInterface, MailTransportInterface, MailerExceptionInterface |
| DotEnv | DotEnvInterface |
| Secret | SecretResolverInterface, SecretResolutionException |
| ClassVersion | ClassVersionInterface, ClassVersionConfigInterface |
| Connection | ConnectionInterface (Basis-Lifecycle) |
| EventListener | EventListenerRegistryInterface (Lücke in PSR-14: Listener-Registrierung) |
Design-Prinzipien
PSR-first
DomainKernelInterface injiziert direkt PSR-Interfaces:
- PSR-3
LoggerInterfacefür Logging - PSR-11
ContainerInterfacefür Service-Auflösung - PSR-14
EventDispatcherInterfacefür Events - PSR-16
CacheInterfacefür Caching - PSR-18
ClientInterfacefür HTTP
Jardis-Contracts existieren nur, wo kein PSR-Standard greift.
Nullable Services
Alle Infrastructure-Services im Kernel sind nullable:
$cache = $kernel->cache(); // ?CacheInterface
$logger = $kernel->logger(); // ?LoggerInterface
$mailer = $kernel->mailer(); // ?MailerInterfaceDomain-Code muss Verfügbarkeit prüfen. Kein Service ist garantiert.
Reader/Writer-Trennung
// Read-only BoundedContext bekommt nur den Reader
public function __construct(
private readonly FilesystemReaderInterface $storage,
) {}
// Full-Access Service bekommt beides
public function __construct(
private readonly FilesystemInterface $storage,
) {}Enum-basierte Strategien
use JardisSupport\Contract\Repository\PrimaryKey\PkStrategy;
$repository->insert('users', 'id', $values, PkStrategy::NONE);Statt String-Konstanten verwenden alle Strategien und Typen PHP 8.1+ Enums.
Abhängigkeitsrichtung
JardisTools → JardisAdapter → JardisSupport → JardisCore
| | |
JardisSupport\Contract ←←←←←←←←←←←←←←←←←←Alle Pfeile zeigen nach innen zum Contract-Package. Domain-Code importiert niemals Adapter-Code direkt.