Completed
Push — master ( 67ee93...84505b )
by Ivannis Suárez
07:55
created

AggregateRepository   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 134
Duplicated Lines 15.67 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 10
dl 21
loc 134
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A get() 0 9 1
A persist() 7 12 3
A persistAll() 0 6 2
A remove() 7 18 3
A loadHistory() 7 7 1
A saveHistory() 0 20 2
A streamName() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * This file is part of the Cubiche package.
5
 *
6
 * Copyright (c) Cubiche
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Cubiche\Domain\EventSourcing;
13
14
use Cubiche\Domain\EventPublisher\DomainEventPublisher;
15
use Cubiche\Domain\EventSourcing\Event\PostPersistEvent;
16
use Cubiche\Domain\EventSourcing\Event\PostRemoveEvent;
17
use Cubiche\Domain\EventSourcing\Event\PrePersistEvent;
18
use Cubiche\Domain\EventSourcing\Event\PreRemoveEvent;
19
use Cubiche\Domain\EventSourcing\Utils\NameResolver;
20
use Cubiche\Domain\EventSourcing\Versioning\VersionManager;
21
use Cubiche\Domain\EventSourcing\EventStore\EventStoreInterface;
22
use Cubiche\Domain\EventSourcing\EventStore\EventStream;
23
use Cubiche\Domain\Model\IdInterface;
24
use Cubiche\Domain\Repository\RepositoryInterface;
25
26
/**
27
 * AggregateRepository class.
28
 *
29
 * @author Ivannis Suárez Jerez <[email protected]>
30
 */
31
class AggregateRepository implements RepositoryInterface
32
{
33
    /**
34
     * @var EventStoreInterface
35
     */
36
    protected $eventStore;
37
38
    /**
39
     * @var string
40
     */
41
    protected $aggregateClassName;
42
43
    /**
44
     * AggregateRepository constructor.
45
     *
46
     * @param EventStoreInterface $eventStore
47
     * @param string              $aggregateClassName
48
     */
49
    public function __construct(EventStoreInterface $eventStore, $aggregateClassName)
50
    {
51
        $this->eventStore = $eventStore;
52
        $this->aggregateClassName = $aggregateClassName;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function get(IdInterface $id)
59
    {
60
        $eventStream = $this->loadHistory($id);
61
62
        return call_user_func(
63
            array($this->aggregateClassName, 'loadFromHistory'),
64
            $eventStream
65
        );
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function persist($element)
72
    {
73 View Code Duplication
        if (!$element instanceof EventSourcedAggregateRootInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74
            throw new \InvalidArgumentException(sprintf(
75
                'The object must be an instance of %s. Instance of %s given',
76
                EventSourcedAggregateRootInterface::class,
77
                is_object($element) ? get_class($element) : gettype($element)
78
            ));
79
        }
80
81
        $this->saveHistory($element);
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function persistAll($elements)
88
    {
89
        foreach ($elements as $element) {
90
            $this->persist($element);
91
        }
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function remove($element)
98
    {
99 View Code Duplication
        if (!$element instanceof EventSourcedAggregateRootInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
100
            throw new \InvalidArgumentException(sprintf(
101
                'The object must be an instance of %s. Instance of %s given',
102
                EventSourcedAggregateRootInterface::class,
103
                is_object($element) ? get_class($element) : gettype($element)
104
            ));
105
        }
106
107
        DomainEventPublisher::publish(new PreRemoveEvent($element));
108
109
        // remove the event stream
110
        $applicationVersion = VersionManager::currentApplicationVersion();
111
        $this->eventStore->remove($this->streamName(), $element->id(), $element->version(), $applicationVersion);
112
113
        DomainEventPublisher::publish(new PostRemoveEvent($element));
114
    }
115
116
    /**
117
     * Load a aggregate history from the storage.
118
     *
119
     * @param IdInterface $id
120
     *
121
     * @return EventStream
122
     */
123 View Code Duplication
    protected function loadHistory(IdInterface $id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
    {
125
        $applicationVersion = VersionManager::currentApplicationVersion();
126
        $aggregateVersion = VersionManager::versionOfClass($this->aggregateClassName, $applicationVersion);
127
128
        return $this->eventStore->load($this->streamName(), $id, $aggregateVersion, $applicationVersion);
129
    }
130
131
    /**
132
     * Save the aggregate history.
133
     *
134
     * @param EventSourcedAggregateRootInterface $aggregateRoot
135
     */
136
    protected function saveHistory(EventSourcedAggregateRootInterface $aggregateRoot)
137
    {
138
        $recordedEvents = $aggregateRoot->recordedEvents();
139
        if (count($recordedEvents) > 0) {
140
            DomainEventPublisher::publish(new PrePersistEvent($aggregateRoot));
141
142
            // clear events
143
            $aggregateRoot->clearEvents();
144
145
            // create the eventStream and persist it
146
            $applicationVersion = VersionManager::currentApplicationVersion();
147
            $eventStream = new EventStream($this->streamName(), $aggregateRoot->id(), $recordedEvents);
148
149
            $this->eventStore->persist($eventStream, $aggregateRoot->version(), $applicationVersion);
150
151
            DomainEventPublisher::publish(
152
                new PostPersistEvent($aggregateRoot, $this->aggregateClassName, $eventStream)
153
            );
154
        }
155
    }
156
157
    /**
158
     * @return string
159
     */
160
    protected function streamName()
161
    {
162
        return NameResolver::resolve($this->aggregateClassName);
163
    }
164
}
165