-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUnsubscribeStudentFromCourse.php
More file actions
123 lines (106 loc) · 3.85 KB
/
UnsubscribeStudentFromCourse.php
File metadata and controls
123 lines (106 loc) · 3.85 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?php
declare(strict_types=1);
namespace Gember\ExampleEventSourcingDcb\Domain\UnsubscribeStudentFromCourse;
use Gember\EventSourcing\UseCase\Attribute\DomainCommandHandler;
use Gember\EventSourcing\UseCase\Attribute\DomainEventSubscriber;
use Gember\EventSourcing\UseCase\Attribute\DomainTag;
use Gember\EventSourcing\UseCase\EventSourcedUseCase;
use Gember\EventSourcing\UseCase\EventSourcedUseCaseBehaviorTrait;
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;
use Gember\ExampleEventSourcingDcb\Domain\SubscribeStudentToCourse\StudentSubscribedToCourseEvent;
/**
* Use case based on multiple domain tags.
*/
final class UnsubscribeStudentFromCourse implements EventSourcedUseCase
{
use EventSourcedUseCaseBehaviorTrait;
/*
* Define to which domain tags this use case belongs to.
*/
#[DomainTag]
private CourseId $courseId;
#[DomainTag]
private StudentId $studentId;
/*
* Use private properties to guard idempotency and protect invariants.
*/
private bool $isStudentSubscribedToCourse;
/**
* @throws CourseNotFoundException
* @throws StudentNotFoundException
*/
#[DomainCommandHandler]
public function __invoke(UnsubscribeStudentFromCourseCommand $command): void
{
/*
* Guard for idempotency.
*/
if (!($this->isStudentSubscribedToCourse ?? false)) {
return;
}
/*
* Protect invariants (business rules).
*/
$this->assertCourseExists();
$this->assertStudentExists();
/*
* Apply events when all business rules are met.
*/
$this->apply(new StudentUnsubscribedFromCourseEvent((string) $this->courseId, (string) $this->studentId));
}
/**
* @throws CourseNotFoundException
*/
private function assertCourseExists(): void
{
if (!isset($this->courseId)) {
throw CourseNotFoundException::create();
}
}
/**
* @throws StudentNotFoundException
*/
private function assertStudentExists(): void
{
if (!isset($this->studentId)) {
throw StudentNotFoundException::create();
}
}
/*
* Change internal state by subscribing to relevant domain events for any of the domain tags,
* so that this use case 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;
}
}
}