Completed
Push — master ( 84505b...5678fc )
by Ivannis Suárez
02:56
created

EventSourcedAggregateRoot.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
namespace Cubiche\Domain\EventSourcing;
12
13
use Cubiche\Core\Validator\Validator;
14
use Cubiche\Domain\EventPublisher\DomainEventPublisher;
15
use Cubiche\Domain\EventSourcing\Versioning\Version;
16
use Cubiche\Domain\EventSourcing\Versioning\VersionIncrementType;
17
use Cubiche\Domain\EventSourcing\Versioning\VersionManager;
18
use Cubiche\Domain\EventSourcing\EventStore\EventStream;
19
20
/**
21
 * EventSourcedAggregateRoot trait.
22
 *
23
 * @author Ivannis Suárez Jerez <[email protected]>
24
 */
25
trait EventSourcedAggregateRoot
26
{
27
    /**
28
     * @var Version
29
     */
30
    protected $version;
31
32
    /**
33
     * @var DomainEventInterface[]
34
     */
35
    protected $recordedEvents = [];
36
37
    /**
38
     * @param DomainEventInterface $event
39
     */
40
    protected function recordApplyAndPublishEvent(DomainEventInterface $event)
41
    {
42
        Validator::assert($event);
43
44
        $this->version()->increment(VersionIncrementType::PATCH());
45
        $event->setVersion($this->version()->patch());
46
47
        $this->recordEvent($event);
48
        $this->applyEvent($event);
49
        $this->publishEvent($event);
50
    }
51
52
    /**
53
     * @param DomainEventInterface $event
54
     */
55
    protected function applyEvent(DomainEventInterface $event)
56
    {
57
        $classParts = explode('\\', get_class($event));
58
        $method = 'apply'.end($classParts);
59
60
        if (!method_exists($this, $method)) {
61
            throw new \BadMethodCallException(
62
                "There is no method named '$method' that can be applied to '".get_class($this)."'. "
63
            );
64
        }
65
66
        $this->$method($event);
67
        $this->version()->setPatch($event->version());
68
    }
69
70
    /**
71
     * @param DomainEventInterface $event
72
     */
73
    protected function publishEvent(DomainEventInterface $event)
74
    {
75
        DomainEventPublisher::publish($event);
76
    }
77
78
    /**
79
     * @param DomainEventInterface $event
80
     */
81
    protected function recordEvent(DomainEventInterface $event)
82
    {
83
        $this->recordedEvents[] = $event;
84
    }
85
86
    /**
87
     * @return DomainEventInterface[]
88
     */
89
    public function recordedEvents()
90
    {
91
        return $this->recordedEvents;
92
    }
93
94
    /**
95
     * Clear recorded events.
96
     */
97
    public function clearEvents()
98
    {
99
        $this->recordedEvents = [];
100
    }
101
102
    /**
103
     * @param EventStream $history
104
     *
105
     * @return AggregateRootInterface
106
     */
107
    public static function loadFromHistory(EventStream $history)
108
    {
109
        $reflector = new \ReflectionClass(static::class);
110
111
        /** @var EventSourcedAggregateRootInterface $aggregateRoot */
112
        $aggregateRoot = $reflector->newInstanceWithoutConstructor();
113
        $aggregateRoot->id = $history->aggregateId();
0 ignored issues
show
Accessing id on the interface Cubiche\Domain\EventSour...dAggregateRootInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
114
        $aggregateRoot->replay($history);
115
116
        return $aggregateRoot;
117
    }
118
119
    /**
120
     * @param EventStream $history
121
     */
122
    public function replay(EventStream $history)
123
    {
124
        foreach ($history->events() as $event) {
125
            $this->applyEvent($event);
126
        }
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function version()
133
    {
134
        if ($this->version === null) {
135
            $this->version = VersionManager::versionOf($this);
136
        }
137
138
        return $this->version;
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    public function setVersion(Version $version)
145
    {
146
        $this->version = $version;
147
    }
148
}
149