AbstractAggregateEvent::occurred()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 5
rs 10
1
<?php
2
3
/*
4
 * event-sourcing (https://github.com/phpgears/event-sourcing).
5
 * Event Sourcing base.
6
 *
7
 * @license MIT
8
 * @link https://github.com/phpgears/event-sourcing
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
declare(strict_types=1);
13
14
namespace Gears\EventSourcing\Event;
15
16
use Gears\Event\Time\SystemTimeProvider;
17
use Gears\Event\Time\TimeProvider;
18
use Gears\EventSourcing\Aggregate\AggregateVersion;
19
use Gears\EventSourcing\Event\Exception\AggregateEventException;
20
use Gears\Identity\Identity;
21
22
/**
23
 * Abstract immutable aggregate event.
24
 */
25
abstract class AbstractAggregateEvent implements AggregateEvent
26
{
27
    use AggregateEventBehaviour;
28
29
    /**
30
     * Prevent aggregate event direct instantiation.
31
     *
32
     * @param Identity             $aggregateId
33
     * @param array<string, mixed> $payload
34
     * @param \DateTimeImmutable   $createdAt
35
     */
36
    final protected function __construct(Identity $aggregateId, array $payload, \DateTimeImmutable $createdAt)
37
    {
38
        $this->assertImmutable();
39
40
        $this->identity = $aggregateId;
41
        $this->version = new AggregateVersion(0);
42
        $this->setPayload($payload);
43
        $this->createdAt = $createdAt->setTimezone(new \DateTimeZone('UTC'));
0 ignored issues
show
Documentation Bug introduced by
It seems like $createdAt->setTimezone(new DateTimeZone('UTC')) can also be of type false. However, the property $createdAt is declared as type DateTimeImmutable. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function getEventType(): string
50
    {
51
        return static::class;
52
    }
53
54
    /**
55
     * Instantiate new aggregate event.
56
     *
57
     * @param Identity             $aggregateId
58
     * @param array<string, mixed> $payload
59
     * @param TimeProvider|null    $timeProvider
60
     *
61
     * @return mixed|self
62
     */
63
    final protected static function occurred(Identity $aggregateId, array $payload, ?TimeProvider $timeProvider = null)
64
    {
65
        $timeProvider = $timeProvider ?? new SystemTimeProvider();
66
67
        return new static($aggregateId, $payload, $timeProvider->getCurrentTime());
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     *
73
     * @throws AggregateEventException
74
     *
75
     * @return mixed|self
76
     */
77
    final public static function reconstitute(array $payload, \DateTimeImmutable $createdAt, array $attributes = [])
78
    {
79
        $event = new static($attributes['aggregateId'], $payload, $createdAt);
80
81
        if (!isset($attributes['aggregateVersion'])
82
            || !$attributes['aggregateVersion'] instanceof AggregateVersion
83
            || (new AggregateVersion(0))->isEqualTo($attributes['aggregateVersion'])
84
        ) {
85
            throw new AggregateEventException(\sprintf(
86
                'Invalid aggregate version, "%s" given',
87
                $attributes['aggregateVersion'] instanceof AggregateVersion
88
                    ? $attributes['aggregateVersion']->getValue()
89
                    : \gettype($attributes['aggregateVersion'])
90
            ));
91
        }
92
93
        $event->version = $attributes['aggregateVersion'];
94
95
        if (isset($attributes['metadata'])) {
96
            $event->addMetadata($attributes['metadata']);
97
        }
98
99
        return $event;
100
    }
101
102
    /**
103
     * @return string[]
104
     */
105
    final public function __sleep(): array
106
    {
107
        throw new AggregateEventException(\sprintf('Aggregate event "%s" cannot be serialized', static::class));
108
    }
109
110
    final public function __wakeup(): void
111
    {
112
        throw new AggregateEventException(\sprintf('Aggregate event "%s" cannot be unserialized', static::class));
113
    }
114
115
    /**
116
     * @return array<string, mixed>
117
     */
118
    final public function __serialize(): array
119
    {
120
        throw new AggregateEventException(\sprintf('Aggregate event "%s" cannot be serialized', static::class));
121
    }
122
123
    /**
124
     * @param array<string, mixed> $data
125
     *
126
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
127
     */
128
    final public function __unserialize(array $data): void
129
    {
130
        throw new AggregateEventException(\sprintf('Aggregate event "%s" cannot be unserialized', static::class));
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     *
136
     * @return string[]
137
     */
138
    final protected function getAllowedInterfaces(): array
139
    {
140
        return [AggregateEvent::class];
141
    }
142
}
143