-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUnsubscribeStudentFromCourse.php
105 lines (89 loc) · 3.4 KB
/
UnsubscribeStudentFromCourse.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?php
declare(strict_types=1);
namespace Gember\ExampleEventSourcingDcb\Domain\StudentToCourseSubscription;
use Gember\EventSourcing\DomainContext\Attribute\DomainEventSubscriber;
use Gember\EventSourcing\DomainContext\Attribute\DomainId;
use Gember\EventSourcing\DomainContext\EventSourcedDomainContext;
use Gember\EventSourcing\DomainContext\EventSourcedDomainContextBehaviorTrait;
use Gember\ExampleEventSourcingDcb\Domain\Course\CourseCreatedEvent;
use Gember\ExampleEventSourcingDcb\Domain\Course\CourseId;
use Gember\ExampleEventSourcingDcb\Domain\Course\CourseNotFoundException;
use Gember\ExampleEventSourcingDcb\Domain\Student\StudentCreatedEvent;
use Gember\ExampleEventSourcingDcb\Domain\Student\StudentId;
use Gember\ExampleEventSourcingDcb\Domain\Student\StudentNotFoundException;
/**
* Business decision model based on multiple domain identifiers.
*/
final class UnsubscribeStudentFromCourse implements EventSourcedDomainContext
{
use EventSourcedDomainContextBehaviorTrait;
/*
* Define to which domain identifiers this context belongs to.
*/
#[DomainId]
private CourseId $courseId;
#[DomainId]
private StudentId $studentId;
/*
* Use private properties to guard idempotency and protect invariants.
*/
private bool $isStudentSubscribedToCourse;
/**
* @throws CourseNotFoundException
* @throws StudentNotFoundException
*/
public function unsubscribe(): void
{
/*
* Guard for idempotency.
*/
if (!($this->isStudentSubscribedToCourse ?? false)) {
return;
}
/*
* Protect invariants (business rules).
*/
if (!isset($this->courseId)) {
throw CourseNotFoundException::create();
}
if (!isset($this->studentId)) {
throw StudentNotFoundException::create();
}
/*
* Apply events when all business rules are met.
*/
$this->apply(new StudentUnsubscribedFromCourseEvent((string) $this->courseId, (string) $this->studentId));
}
/*
* Change internal state by subscribing to relevant domain events for any of the domain identifiers,
* so that this context can apply its business rules.
*/
#[DomainEventSubscriber]
private function onCourseCreatedEvent(CourseCreatedEvent $event): void
{
$this->courseId = new CourseId($event->courseId);
}
#[DomainEventSubscriber]
private function onStudentCreatedEvent(StudentCreatedEvent $event): void
{
$this->studentId = new StudentId($event->studentId);
}
#[DomainEventSubscriber]
private function onStudentSubscribedToCourseEvent(StudentSubscribedToCourseEvent $event): void
{
$studentId = $this->studentId ?? null;
$courseId = $this->courseId ?? null;
if ($studentId?->equals(new StudentId($event->studentId)) && $courseId?->equals(new CourseId($event->courseId))) {
$this->isStudentSubscribedToCourse = true;
}
}
#[DomainEventSubscriber]
private function onStudentUnsubscribedFromCourseEvent(StudentUnsubscribedFromCourseEvent $event): void
{
$studentId = $this->studentId ?? null;
$courseId = $this->courseId ?? null;
if ($studentId?->equals(new StudentId($event->studentId)) && $courseId?->equals(new CourseId($event->courseId))) {
$this->isStudentSubscribedToCourse = false;
}
}
}