AggregateRootRepository   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 56
c 2
b 1
f 0
dl 0
loc 190
rs 10
wmc 16

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 25 1
A persist() 0 3 1
A storeSnapshot() 0 3 1
A getMessageRepository() 0 7 1
A instanciate() 0 7 2
A assertAggregateClassIsValid() 0 8 3
A retrieveFromSnapshot() 0 3 1
A getConsumerHandlerClass() 0 3 1
A getSnapshotRepository() 0 7 1
A getConnection() 0 7 1
A getInstanciatedDecorators() 0 3 1
A retrieve() 0 3 1
A persistEvents() 0 3 1
1
<?php
2
3
namespace Chocofamily\LaravelEventSauce;
4
5
use Chocofamily\LaravelEventSauce\Exceptions\AggregateRootRepositoryInstanciationFailed;
6
use EventSauce\EventSourcing\AggregateRoot;
7
use EventSauce\EventSourcing\AggregateRootId;
8
use EventSauce\EventSourcing\ConstructingAggregateRootRepository;
9
use EventSauce\EventSourcing\DefaultHeadersDecorator;
10
use EventSauce\EventSourcing\MessageDecorator;
11
use EventSauce\EventSourcing\MessageDecoratorChain;
12
use EventSauce\EventSourcing\MessageDispatcherChain;
13
use EventSauce\EventSourcing\MessageRepository as EventSauceMessageRepository;
14
use EventSauce\EventSourcing\Snapshotting\AggregateRootRepositoryWithSnapshotting as EventSauceAggregateRootRepository;
15
use EventSauce\EventSourcing\Snapshotting\AggregateRootWithSnapshotting;
16
use EventSauce\EventSourcing\Snapshotting\ConstructingAggregateRootRepositoryWithSnapshotting;
17
use EventSauce\EventSourcing\Snapshotting\SnapshotRepository as EventSauceSnapshotRepository;
18
use Illuminate\Database\ConnectionInterface;
19
use Illuminate\Support\Facades\DB;
20
21
abstract class AggregateRootRepository implements EventSauceAggregateRootRepository
22
{
23
    /** @var string */
24
    protected $aggregateRoot;
25
26
    /** @var array */
27
    protected $consumers = [];
28
29
    /** @var string */
30
    protected $connection;
31
32
    /** @var string */
33
    protected $table;
34
35
    /** @var string */
36
    protected $messageRepository;
37
38
    /** @var string */
39
    protected $snapshotRepository;
40
41
    /** @var string */
42
    protected $snapshotTable;
43
44
    /** @var array */
45
    protected $decorators = [];
46
47
    /** @var ConstructingAggregateRootRepositoryWithSnapshotting */
48
    protected $repository;
49
50
    /** @var string */
51
    protected $consumerHandlerClass;
52
53
    /**
54
     * AggregateRootRepository constructor.
55
     * @throws AggregateRootRepositoryInstanciationFailed
56
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
57
     */
58
    public function __construct()
59
    {
60
        $this->assertAggregateClassIsValid();
61
62
        $aggregateRepository = new ConstructingAggregateRootRepository(
63
            $this->aggregateRoot,
64
            $this->getMessageRepository(),
65
            new MessageDispatcherChain(
66
                new MessageDispatcher(
67
                    $this->getConsumerHandlerClass(),
68
                    $this->consumers
69
                ),
70
                new EventMessageDispatcher()
71
            ),
72
            new MessageDecoratorChain(
73
                new DefaultHeadersDecorator(),
74
                ...$this->getInstanciatedDecorators()
75
            )
76
        );
77
78
        $this->repository = new ConstructingAggregateRootRepositoryWithSnapshotting(
79
            $this->aggregateRoot,
80
            $this->getMessageRepository(),
81
            $this->getSnapshotRepository(),
82
            $aggregateRepository
83
        );
84
    }
85
86
    /**
87
     * @param AggregateRootId $aggregateRootId
88
     * @return object
89
     */
90
    public function retrieve(AggregateRootId $aggregateRootId): object
91
    {
92
        return $this->repository->retrieve($aggregateRootId);
93
    }
94
95
    /**
96
     * @param object $aggregateRoot
97
     */
98
    public function persist(object $aggregateRoot)
99
    {
100
        $this->repository->persist($aggregateRoot);
101
    }
102
103
    /**
104
     * @param AggregateRootId $aggregateRootId
105
     * @param int $aggregateRootVersion
106
     * @param object ...$events
107
     */
108
    public function persistEvents(AggregateRootId $aggregateRootId, int $aggregateRootVersion, object ...$events)
109
    {
110
        $this->repository->persistEvents($aggregateRootId, $aggregateRootVersion, ...$events);
111
    }
112
113
    /**
114
     * @param AggregateRootId $aggregateRootId
115
     * @return object
116
     */
117
    public function retrieveFromSnapshot(AggregateRootId $aggregateRootId): object
118
    {
119
        return $this->repository->retrieveFromSnapshot($aggregateRootId);
120
    }
121
122
    /**
123
     * @param AggregateRootWithSnapshotting $aggregateRoot
124
     */
125
    public function storeSnapshot(AggregateRootWithSnapshotting $aggregateRoot): void
126
    {
127
        $this->repository->storeSnapshot($aggregateRoot);
128
    }
129
130
    /**
131
     * @throws AggregateRootRepositoryInstanciationFailed
132
     */
133
    protected function assertAggregateClassIsValid()
134
    {
135
        if (is_null($this->aggregateRoot)) {
0 ignored issues
show
introduced by
The condition is_null($this->aggregateRoot) is always false.
Loading history...
136
            throw AggregateRootRepositoryInstanciationFailed::aggregateRootClassDoesNotExist();
137
        }
138
139
        if (! is_a($this->aggregateRoot, AggregateRoot::class, true)) {
140
            throw AggregateRootRepositoryInstanciationFailed::aggregateRootClassIsNotValid();
141
        }
142
    }
143
144
    /**
145
     * @return ConnectionInterface
146
     */
147
    protected function getConnection(): ConnectionInterface
148
    {
149
        $connection = $this->connection
150
            ?? config('eventsauce.connection')
151
            ?? config('database.default');
152
153
        return DB::connection($connection);
154
    }
155
156
    /**
157
     * @return EventSauceMessageRepository
158
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
159
     */
160
    protected function getMessageRepository(): EventSauceMessageRepository
161
    {
162
        $messageRepository = $this->messageRepository ?? config('eventsauce.message_repository');
163
164
        return app()->make($messageRepository, [
165
            'connection'    =>  $this->getConnection(),
166
            'table'         =>  $this->table ?? config('eventsauce.table'),
167
        ]);
168
    }
169
170
    /**
171
     * @return EventSauceSnapshotRepository
172
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
173
     */
174
    protected function getSnapshotRepository(): EventSauceSnapshotRepository
175
    {
176
        $snapshotRepository = $this->snapshotRepository ?? config('eventsauce.snapshot_repository');
177
178
        return app()->make($snapshotRepository, [
179
            'connection'    =>  $this->getConnection(),
180
            'table'         =>  $this->snapshotTable ?? config('eventsauce.snapshot_table'),
181
        ]);
182
    }
183
184
    /**
185
     * @return string
186
     */
187
    protected function getConsumerHandlerClass(): string
188
    {
189
        return $this->consumerHandlerClass ?? config('eventsauce.consumer_handler');
190
    }
191
192
    /**
193
     * @return MessageDecorator[]
194
     */
195
    protected function getInstanciatedDecorators(): array
196
    {
197
        return $this->instanciate($this->decorators);
198
    }
199
200
    /**
201
     * @param array $classes
202
     * @return array
203
     */
204
    protected function instanciate(array $classes): array
205
    {
206
        return array_map(function ($class) {
207
            return is_string($class)
208
                ? app()->make($class)
209
                : $class;
210
        }, $classes);
211
    }
212
}
213