Eenheid van werkpatroon
Overzicht
Section titled “Overzicht”Het Unit of Work-patroon houdt een lijst bij van objecten die door een zakelijke transactie worden beïnvloed en coördineert het uitschrijven van wijzigingen. Het zorgt ervoor dat alle gerelateerde wijzigingen samen worden vastgelegd of worden teruggedraaid bij een mislukking.
- Transactiebeheer - Groepsgerelateerde activiteiten
- Wijzigingen bijhouden - Volg gewijzigde entiteiten
- Batchbewerkingen - Optimaliseer databaseschrijfbewerkingen
- Consistentie - Zorg voor gegevensintegriteit
Implementatie
Section titled “Implementatie”Werkeenheid-interface
Section titled “Werkeenheid-interface”<?php
declare(strict_types=1);
namespace XoopsModules\MyModule\Infrastructure;
interface UnitOfWorkInterface{ public function begin(): void; public function commit(): void; public function rollback(): void; public function registerNew(object $entity): void; public function registerDirty(object $entity): void; public function registerDeleted(object $entity): void;}Basisimplementatie
Section titled “Basisimplementatie”<?php
declare(strict_types=1);
namespace XoopsModules\MyModule\Infrastructure;
final class UnitOfWork implements UnitOfWorkInterface{ private array $newEntities = []; private array $dirtyEntities = []; private array $deletedEntities = []; private bool $inTransaction = false;
public function __construct( private readonly \XoopsDatabase $db, private readonly EntityMapperRegistry $mappers ) {}
public function begin(): void { if ($this->inTransaction) { throw new \RuntimeException('Transaction already started'); }
$this->db->query('START TRANSACTION'); $this->inTransaction = true; }
public function commit(): void { if (!$this->inTransaction) { throw new \RuntimeException('No transaction in progress'); }
try { $this->insertNew(); $this->updateDirty(); $this->deleteRemoved();
$this->db->query('COMMIT'); $this->clear(); } catch (\Exception $e) { $this->rollback(); throw $e; } }
public function rollback(): void { if ($this->inTransaction) { $this->db->query('ROLLBACK'); $this->clear(); } }
public function registerNew(object $entity): void { $id = spl_object_id($entity); $this->newEntities[$id] = $entity; }
public function registerDirty(object $entity): void { $id = spl_object_id($entity); if (!isset($this->newEntities[$id])) { $this->dirtyEntities[$id] = $entity; } }
public function registerDeleted(object $entity): void { $id = spl_object_id($entity); unset($this->newEntities[$id], $this->dirtyEntities[$id]); $this->deletedEntities[$id] = $entity; }
private function insertNew(): void { foreach ($this->newEntities as $entity) { $mapper = $this->mappers->getMapper($entity::class); $mapper->insert($entity); } }
private function updateDirty(): void { foreach ($this->dirtyEntities as $entity) { $mapper = $this->mappers->getMapper($entity::class); $mapper->update($entity); } }
private function deleteRemoved(): void { foreach ($this->deletedEntities as $entity) { $mapper = $this->mappers->getMapper($entity::class); $mapper->delete($entity); } }
private function clear(): void { $this->newEntities = []; $this->dirtyEntities = []; $this->deletedEntities = []; $this->inTransaction = false; }}Gebruik in services
Section titled “Gebruik in services”final class ArticleService{ public function __construct( private readonly UnitOfWorkInterface $unitOfWork, private readonly ArticleRepository $articles, private readonly CommentRepository $comments ) {}
public function publishWithComments( Article $article, array $comments ): void { $this->unitOfWork->begin();
try { // Mark article as modified $article->publish(); $this->unitOfWork->registerDirty($article);
// Add new comments foreach ($comments as $comment) { $this->unitOfWork->registerNew($comment); }
// Commit all changes together $this->unitOfWork->commit();
} catch (\Exception $e) { $this->unitOfWork->rollback(); throw $e; } }}Met Repository-integratie
Section titled “Met Repository-integratie”final class ArticleRepository implements ArticleRepositoryInterface{ public function __construct( private readonly UnitOfWorkInterface $unitOfWork, private readonly ArticleMapper $mapper ) {}
public function add(Article $article): void { $this->unitOfWork->registerNew($article); }
public function update(Article $article): void { $this->unitOfWork->registerDirty($article); }
public function remove(Article $article): void { $this->unitOfWork->registerDeleted($article); }
public function findById(ArticleId $id): ?Article { return $this->mapper->findById($id); }}Beste praktijken
Section titled “Beste praktijken”- Korte transacties - Houd transacties kort
- Eén verantwoordelijkheid - Eén werkeenheid per bedrijfsactiviteit
- Duidelijke grenzen - Definieer de reikwijdte van de transactie duidelijk
- Foutafhandeling - Handel altijd terugdraaiscenario’s af
- Vermijd geneste: nest geen werkeenheden
Gerelateerde documentatie
Section titled “Gerelateerde documentatie”- Repository-laag - Repository-patroon
- Servicelaag - Servicepatroon
- ../Database/Database-Schema - Databasebewerkingen
- Domeinmodel - Domeinentiteiten