1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpDDD\Domain; |
4
|
|
|
|
5
|
|
|
use BadMethodCallException; |
6
|
|
|
use PhpDDD\Domain\Event\EventInterface; |
7
|
|
|
use PhpDDD\Domain\Event\Utils\EventName; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* An AggregateRoot is the starting point of an Aggregate. |
11
|
|
|
* It's the only class from an Aggregate that should be known by the outside world. |
12
|
|
|
*/ |
13
|
|
|
abstract class AbstractAggregateRoot |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* @var int |
17
|
|
|
*/ |
18
|
|
|
protected $id; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* List of events that occurred. |
22
|
|
|
* |
23
|
|
|
* @var EventInterface[] |
24
|
|
|
*/ |
25
|
|
|
private $events = array(); |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @return int |
29
|
|
|
*/ |
30
|
|
|
public function getId() |
31
|
|
|
{ |
32
|
|
|
return $this->id; |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* This allows you to get every events raised by the aggregate and clear the stack. |
37
|
|
|
* It's helpful when you do event sourcing because once an event is raised you may need to do some actions in other |
38
|
|
|
* bounded contexts. So the events is fired once. |
39
|
|
|
* |
40
|
|
|
* @return EventInterface[] |
41
|
|
|
*/ |
42
|
|
|
public function pullEvents() |
43
|
|
|
{ |
44
|
|
|
$this->safelyPopulateEventsWithAggregateId(); |
45
|
|
|
$events = $this->events; |
46
|
|
|
$this->events = array(); |
47
|
|
|
|
48
|
|
|
return $events; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Used when somebody is trying to modify an Aggregate. |
53
|
|
|
* You should check that the input is good then create an event and call this method. |
54
|
|
|
* |
55
|
|
|
* @param EventInterface $event |
56
|
|
|
*/ |
57
|
|
|
protected function apply(EventInterface $event) |
58
|
|
|
{ |
59
|
|
|
$this->executeEvent($event); |
60
|
|
|
$this->events[] = $event; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @param EventInterface $event |
65
|
|
|
* |
66
|
|
|
* @throws BadMethodCallException |
67
|
|
|
*/ |
68
|
|
|
private function executeEvent(EventInterface $event) |
69
|
|
|
{ |
70
|
|
|
$eventName = new EventName($event); |
71
|
|
|
$method = sprintf('apply%s', (string) $eventName); |
72
|
|
|
|
73
|
|
|
if (!method_exists($this, $method)) { |
74
|
|
|
throw new BadMethodCallException( |
75
|
|
|
sprintf( |
76
|
|
|
'You must define the %s::%s method(%s $event) in order to apply event named "%s". ', |
77
|
|
|
get_class($this), |
78
|
|
|
$method, |
79
|
|
|
get_class($event), |
80
|
|
|
$eventName |
81
|
|
|
) |
82
|
|
|
); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
$this->$method($event); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* |
90
|
|
|
*/ |
91
|
|
|
private function safelyPopulateEventsWithAggregateId() |
92
|
|
|
{ |
93
|
|
|
foreach ($this->events as $event) { |
94
|
|
|
if (null === $event->getAggregateRootId()) { |
95
|
|
|
$event->setAggregateRootId($this->id); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
} |
100
|
|
|
|