-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
79f3882
commit ae4a5e3
Showing
9 changed files
with
238 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## What is Event Sourcing? | ||
|
||
Event sourcing is a software architecture pattern that emphasizes capturing and persisting the state of an application as a sequence of events rather than storing the current state directly. In event sourcing, every state-changing operation, or event, is stored in an append-only log. The current state of an entity is reconstructed by replaying these events in sequence. | ||
|
||
This approach provides a comprehensive audit trail of all changes, enabling traceability, versioning, and the ability to rebuild the system's state at any point in time. Event sourcing promotes a decentralized and scalable model, facilitating event-driven architectures and supporting the evolution of domain models over time, making it particularly suitable for complex business domains and systems where temporal aspects and historical data are crucial. | ||
|
||
## When to NOT use it | ||
|
||
Event sourcing comes with additional complexity. You should NOT use event sourcing when you don't need it. It is a powerful tool, but it is not a silver bullet. It is not a one-size-fits-all solution. Event sourcing is a good solution for scenarious like audit logging, undo/redo functionality, and complex business rules. | ||
|
||
If you have no good reason to use it, then don't. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
tests/Repository/EventPublisher/EventLoggerMiddlewareTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Phauthentic\EventSourcing\Test\Repository\EventPublisher; | ||
|
||
use Phauthentic\EventSourcing\Repository\EventPublisher\EventLoggerMiddleware; | ||
use PHPUnit\Framework\TestCase; | ||
use Psr\Log\LoggerInterface; | ||
|
||
/** | ||
* | ||
*/ | ||
class EventLoggerMiddlewareTest extends TestCase | ||
{ | ||
public function testHandleLogsEventInfo(): void | ||
{ | ||
$mockLogger = $this->createMock(LoggerInterface::class); | ||
|
||
$middleware = new EventLoggerMiddleware($mockLogger); | ||
|
||
$dummyEvent = new class () { | ||
}; | ||
|
||
$mockLogger->expects($this->once()) | ||
->method('info') | ||
->with($this->equalTo(sprintf('Event %s emitted.', get_class($dummyEvent)))); | ||
|
||
$middleware->handle($dummyEvent); | ||
} | ||
|
||
public function testIsInterrupting(): void | ||
{ | ||
$mockLogger = $this->createMock(LoggerInterface::class); | ||
|
||
$middleware = new EventLoggerMiddleware($mockLogger); | ||
|
||
$this->assertFalse($middleware->isInterrupting()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Phauthentic\EventSourcing\Test\Repository\EventPublisher; | ||
|
||
use Phauthentic\EventSourcing\Repository\EventPublisher\EventPublisher; | ||
use Phauthentic\EventSourcing\Repository\EventPublisher\EventPublisherMiddlewareInterface; | ||
use PHPUnit\Framework\TestCase; | ||
use ReflectionClass; | ||
use RuntimeException; | ||
|
||
/** | ||
* | ||
*/ | ||
class EventPublisherTest extends TestCase | ||
{ | ||
public function testConstructorWithEmptyMiddlewareArrayThrowsException(): void | ||
{ | ||
$this->expectException(RuntimeException::class); | ||
$this->expectExceptionMessage('No middleware registered!'); | ||
|
||
new EventPublisher([]); | ||
} | ||
|
||
public function testAddMiddleware(): void | ||
{ | ||
$publisher = new EventPublisher([ | ||
$this->createMock(EventPublisherMiddlewareInterface::class) | ||
]); | ||
|
||
$newMiddleware = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
$publisher->addMiddleware($newMiddleware); | ||
|
||
$reflectionClass = new ReflectionClass($publisher); | ||
$this->assertCount(2, $reflectionClass->getProperty('middlewares')->getValue($publisher)); | ||
} | ||
|
||
public function testEmitEventCallsAllMiddlewares(): void | ||
{ | ||
$middleware1 = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
$middleware2 = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
|
||
$middleware1->method('isInterrupting')->willReturn(false); | ||
$middleware2->method('isInterrupting')->willReturn(false); | ||
|
||
$publisher = new EventPublisher([$middleware1, $middleware2]); | ||
|
||
$event = new \stdClass(); | ||
|
||
$middleware1->expects($this->once())->method('handle')->with($event); | ||
$middleware2->expects($this->once())->method('handle')->with($event); | ||
|
||
$publisher->emitEvent($event); | ||
} | ||
|
||
public function testEmitEventStopsOnInterruptingMiddleware(): void | ||
{ | ||
$middleware1 = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
$middleware2 = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
|
||
$middleware1->method('isInterrupting')->willReturn(true); | ||
|
||
$publisher = new EventPublisher([$middleware1, $middleware2]); | ||
|
||
$event = new \stdClass(); | ||
|
||
$middleware1->expects($this->once())->method('handle')->with($event); | ||
$middleware2->expects($this->never())->method('handle'); | ||
|
||
$publisher->emitEvent($event); | ||
} | ||
|
||
public function testEmitEventsCallsEmitEventForEachEvent(): void | ||
{ | ||
$middleware = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
$middleware->method('isInterrupting')->willReturn(false); | ||
$publisher = new EventPublisher([$middleware]); | ||
|
||
$events = [new \stdClass(), new \stdClass(), new \stdClass()]; | ||
|
||
$middleware->expects($this->exactly(3))->method('handle'); | ||
|
||
$publisher->emitEvents($events); | ||
} | ||
|
||
public function testEmitEventsWorksWithIterator(): void | ||
{ | ||
$middleware = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
$middleware->method('isInterrupting')->willReturn(false); | ||
$publisher = new EventPublisher([$middleware]); | ||
|
||
$events = new \ArrayIterator([new \stdClass(), new \stdClass()]); | ||
|
||
$middleware->expects($this->exactly(2))->method('handle'); | ||
|
||
$publisher->emitEvents($events); | ||
} | ||
|
||
public function testEmitEventsWorksWithGenerator(): void | ||
{ | ||
$middleware = $this->createMock(EventPublisherMiddlewareInterface::class); | ||
$middleware->method('isInterrupting')->willReturn(false); | ||
$publisher = new EventPublisher([$middleware]); | ||
|
||
$events = (function () { | ||
yield new \stdClass(); | ||
yield new \stdClass(); | ||
})(); | ||
|
||
$middleware->expects($this->exactly(2))->method('handle'); | ||
|
||
$publisher->emitEvents($events); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
tests/Repository/EventPublisher/SymfonyMessageBusConnectorMiddlewareTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Phauthentic\EventSourcing\Test\Repository\EventPublisher; | ||
|
||
use Phauthentic\EventSourcing\Repository\EventPublisher\SymfonyMessageBusConnectorMiddleware; | ||
use PHPUnit\Framework\TestCase; | ||
use Symfony\Component\Messenger\Envelope; | ||
use Symfony\Component\Messenger\MessageBus; | ||
|
||
/** | ||
* | ||
*/ | ||
class SymfonyMessageBusConnectorMiddlewareTest extends TestCase | ||
{ | ||
public function testHandleDispatchesEventToMessageBus(): void | ||
{ | ||
$mockMessageBus = $this->createMock(MessageBus::class); | ||
|
||
$middleware = new SymfonyMessageBusConnectorMiddleware($mockMessageBus); | ||
|
||
$dummyEvent = new class () { | ||
}; | ||
|
||
$mockMessageBus->expects($this->once()) | ||
->method('dispatch') | ||
->with($this->identicalTo($dummyEvent)) | ||
->willReturn(new Envelope($dummyEvent)); | ||
|
||
$middleware->handle($dummyEvent); | ||
} | ||
|
||
public function testIsInterrupting(): void | ||
{ | ||
$mockMessageBus = $this->createMock(MessageBus::class); | ||
|
||
$middleware = new SymfonyMessageBusConnectorMiddleware($mockMessageBus); | ||
|
||
$this->assertFalse($middleware->isInterrupting()); | ||
} | ||
} |