Completed
Push — master ( 9f2738...4e0e24 )
by Freek
01:29
created

EventProjectionist::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
namespace Spatie\EventProjector;
4
5
use Illuminate\Support\Collection;
6
use Spatie\EventProjector\Events\FinishedEventReplay;
7
use Spatie\EventProjector\Events\StartingEventReplay;
8
use Spatie\EventProjector\Exceptions\InvalidEventHandler;
9
10
class EventProjectionist
11
{
12
    /** @var \Illuminate\Support\Collection */
13
    public $projectors;
14
15
    /** @var \Illuminate\Support\Collection */
16
    public $reactors;
17
18
    /** @var boolean */
19
    protected $isReplayingEvents = false;
20
21
    public function __construct()
22
    {
23
        $this->projectors = collect();
24
25
        $this->reactors = collect();
26
    }
27
28
    public function isReplayingEvents(): bool
29
    {
30
        return $this->isReplayingEvents;
31
    }
32
33
    public function addProjector($projector): self
34
    {
35
        $this->guardAgainstInvalidEventHandler($projector);
36
37
        $this->projectors->push($projector);
38
39
        return $this;
40
    }
41
42
    public function registerProjectors(array $projectors): self
43
    {
44
        collect($projectors)->each(function ($projector) {
45
            $this->addProjector($projector);
46
        });
47
48
        return $this;
49
    }
50
51
    public function addReactor($reactor): self
52
    {
53
        $this->guardAgainstInvalidEventHandler($reactor);
54
55
        $this->reactors->push($reactor);
56
57
        return $this;
58
    }
59
60
    public function registerReactors(array $reactors): self
61
    {
62
        collect($reactors)->each(function ($reactor) {
63
            $this->addReactor($reactor);
64
        });
65
66
        return $this;
67
    }
68
69
    public function callEventHandlers(Collection $eventHandlers, ShouldBeStored $event): self
70
    {
71
        $eventHandlers
72
            ->pipe(function(Collection $eventHandler) {
73
                return $this->instanciate($eventHandler);
74
            })
75
            ->each(function (object $eventHandler) use ($event) {
76
                $this->callEventHandler($eventHandler, $event);
77
            });
78
79
        return $this;
80
    }
81
82
    protected function callEventHandler(object $eventHandler, ShouldBeStored $event)
83
    {
84
        if (!isset($eventHandler->handlesEvents)) {
85
            throw InvalidEventHandler::cannotHandleEvents($eventHandler);
86
        }
87
88
        if (!$method = $eventHandler->handlesEvents[get_class($event)] ?? false) {
89
            return;
90
        }
91
92
        if (!method_exists($eventHandler, $method)) {
93
            throw InvalidEventHandler::eventHandlingMethodDoesNotExist($eventHandler, $event, $method);
94
        }
95
96
        app()->call([$eventHandler, $method], compact('event'));
97
    }
98
99
    public function replayEvents(Collection $projectors, callable $onEventReplayed)
100
    {
101
        $projectors = $this->instanciate($projectors);
102
103
        $this->isReplayingEvents = true;
104
105
        event(new StartingEventReplay());
106
107
        $this->callMethod($projectors, 'onStartingEventReplay');
108
109
        StoredEvent::chunk(1000, function (Collection $storedEvents) use ($projectors, $onEventReplayed) {
110
            $storedEvents->each(function (StoredEvent $storedEvent) use ($projectors, $onEventReplayed) {
111
                $this->callEventHandlers($projectors, $storedEvent->event);
112
113
                $onEventReplayed($storedEvent);
114
            });
115
        });
116
117
        $this->isReplayingEvents = false;
118
119
        event(new FinishedEventReplay());
120
121
        $this->callMethod($projectors, 'onFinishedEventReplay');
122
    }
123
124
    protected function guardAgainstInvalidEventHandler($projector)
125
    {
126
        if (!is_string($projector)) {
127
            return;
128
        }
129
130
        if (!class_exists($projector)) {
131
            throw InvalidEventHandler::doesNotExist($projector);
132
        }
133
    }
134
135
    protected function instanciate(Collection $eventHandlers)
136
    {
137
        return $eventHandlers->map(function ($eventHandler) {
138
            if (is_string($eventHandler)) {
139
                $eventHandler = app($eventHandler);
140
            }
141
142
            return $eventHandler;
143
        });
144
    }
145
146
    protected function callMethod(Collection $eventHandlers, string $method): self
147
    {
148
        $eventHandlers
149
            ->filter(function (object $eventHandler) use ($method) {
150
                return method_exists($eventHandler, $method);
151
            })
152
            ->each(function (object $eventHandler) use ($method) {
153
                return app()->call([$eventHandler, $method]);
154
            });
155
156
        return $this;
157
    }
158
}
159