Completed
Push — master ( b3304b...4a03c4 )
by Freek
11s
created

ProjectsEvents::getStoredEventClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Spatie\EventProjector\Projectors;
4
5
use Carbon\Carbon;
6
use Illuminate\Support\Collection;
7
use Spatie\EventProjector\Models\StoredEvent;
8
use Spatie\EventProjector\Models\ProjectorStatus;
9
use Spatie\EventProjector\EventHandlers\HandlesEvents;
10
use Spatie\EventProjector\Exceptions\CouldNotResetProjector;
11
12
trait ProjectsEvents
13
{
14
    use HandlesEvents;
15
16
    public function getName(): string
17
    {
18
        if (isset($this->name)) {
19
            return $this->name;
0 ignored issues
show
Bug introduced by
The property name does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
20
        }
21
22
        return get_class($this);
23
    }
24
25
    public function rememberReceivedEvent(StoredEvent $storedEvent)
26
    {
27
        foreach ($this->getEventStreamFullNames($storedEvent) as $streamName) {
28
            $status = $this->getStatus($streamName);
29
30
            $status->rememberLastProcessedEvent($storedEvent, $this);
0 ignored issues
show
Unused Code introduced by
The call to ProjectorStatus::rememberLastProcessedEvent() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
31
32
            $streams = $this->getEventStreams($storedEvent);
33
34
            if ($streams->isEmpty()) {
35
                $lastStoredEvent = $this->getStoredEventClass()::query()
0 ignored issues
show
Bug introduced by
The method query cannot be called on $this->getStoredEventClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
36
                    ->whereIn('event_class', $this->handles())
37
                    ->orderBy('id', 'desc')
38
                    ->first();
39
40
                $lastStoredEventId = (int) optional($lastStoredEvent)->id ?? 0;
41
42
                $status = $this->getStatus();
43
44
                $status->last_processed_event_id === $lastStoredEventId
0 ignored issues
show
Documentation introduced by
The property last_processed_event_id does not exist on object<Spatie\EventProje...Models\ProjectorStatus>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
45
                    ? $status->markAsReceivedAllEvents()
46
                    : $status->markasAsNotReceivedAllEvents();
47
48
                return;
49
            }
50
51
            foreach ($streams as $streamName => $streamValue) {
52
                $streamFullName = "{$streamName}-{$streamValue}";
53
                $whereJsonClause = str_replace('.', '->', $streamName);
54
55
                $lastStoredEvent = $this->getStoredEventClass()::query()
0 ignored issues
show
Bug introduced by
The method query cannot be called on $this->getStoredEventClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
56
                    ->whereIn('event_class', $this->handles())
57
                    ->where("event_properties->{$whereJsonClause}", $streamValue)
58
                    ->orderBy('id', 'desc')
59
                    ->first();
60
61
                $lastStoredEventId = (int) optional($lastStoredEvent)->id ?? 0;
62
63
                $status = $this->getStatus($streamFullName);
64
65
                $status->last_processed_event_id === $lastStoredEventId
0 ignored issues
show
Documentation introduced by
The property last_processed_event_id does not exist on object<Spatie\EventProje...Models\ProjectorStatus>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
66
                    ? $status->markAsReceivedAllEvents()
67
                    : $status->markasAsNotReceivedAllEvents();
68
            }
69
        }
70
    }
71
72
    public function hasAlreadyReceivedEvent(StoredEvent $storedEvent): bool
73
    {
74
        foreach ($this->getEventStreamFullNames($storedEvent) as $streamFullName) {
75
            $status = $this->getStatus($streamFullName);
76
77
            $lastProcessedEventId = (int) optional($status)->last_processed_event_id ?? 0;
78
79
            if ($storedEvent->id <= $lastProcessedEventId) {
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Spatie\EventProjector\Models\StoredEvent>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
80
                return true;
81
            }
82
        }
83
84
        return false;
85
    }
86
87
    public function hasReceivedAllPriorEvents(StoredEvent $storedEvent): bool
88
    {
89
        $streams = $this->getEventStreams($storedEvent);
90
91
        if ($streams->isEmpty()) {
92
            $lastStoredEvent = $this->getStoredEventClass()::query()
0 ignored issues
show
Bug introduced by
The method query cannot be called on $this->getStoredEventClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
93
                ->whereIn('event_class', $this->handles())
94
                ->where('id', '<', $storedEvent->id)
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Spatie\EventProjector\Models\StoredEvent>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
95
                ->orderBy('id', 'desc')
96
                ->first();
97
98
            $lastStoredEventId = (int) optional($lastStoredEvent)->id ?? 0;
99
100
            $status = $this->getStatus();
101
102
            $lastProcessedEventId = (int) $status->last_processed_event_id ?? 0;
0 ignored issues
show
Documentation introduced by
The property last_processed_event_id does not exist on object<Spatie\EventProje...Models\ProjectorStatus>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
103
104
            if ($lastStoredEventId !== $lastProcessedEventId) {
105
                return false;
106
            }
107
108
            return true;
109
        }
110
111
        foreach ($streams as $streamName => $streamValue) {
112
            $streamFullName = "{$streamName}-{$streamValue}";
113
            $whereJsonClause = str_replace('.', '->', $streamName);
114
115
            $lastStoredEvent = $this->getStoredEventClass()::query()
0 ignored issues
show
Bug introduced by
The method query cannot be called on $this->getStoredEventClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
116
                ->whereIn('event_class', $this->handles())
117
                ->where('id', '<', $storedEvent->id)
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Spatie\EventProjector\Models\StoredEvent>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
118
                ->where("event_properties->{$whereJsonClause}", $streamValue)
119
                ->orderBy('id', 'desc')
120
                ->first();
121
122
            $lastStoredEventId = (int) optional($lastStoredEvent)->id ?? 0;
123
124
            $status = $this->getStatus($streamFullName);
125
            $lastProcessedEventId = (int) $status->last_processed_event_id ?? 0;
0 ignored issues
show
Documentation introduced by
The property last_processed_event_id does not exist on object<Spatie\EventProje...Models\ProjectorStatus>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
126
127
            if ($lastStoredEventId !== $lastProcessedEventId) {
128
                return false;
129
            }
130
        }
131
132
        return true;
133
    }
134
135
    public function hasReceivedAllEvents(): bool
136
    {
137
        return $this->getProjectorStatusClass()::hasReceivedAllEvents($this);
0 ignored issues
show
Bug introduced by
The method hasReceivedAllEvents cannot be called on $this->getProjectorStatusClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
138
    }
139
140
    public function markAsNotUpToDate(StoredEvent $storedEvent)
141
    {
142
        foreach ($this->getEventStreamFullNames($storedEvent) as $streamName) {
143
            $status = $this->getStatus($streamName);
144
145
            $status->markasAsNotReceivedAllEvents();
146
        }
147
    }
148
149
    public function getLastProcessedEventId(): int
150
    {
151
        return $this->getStatus()->last_processed_event_id ?? 0;
0 ignored issues
show
Documentation introduced by
The property last_processed_event_id does not exist on object<Spatie\EventProje...Models\ProjectorStatus>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
152
    }
153
154
    public function lastEventProcessedAt(): Carbon
155
    {
156
        return $this->getStatus()->updated_at;
0 ignored issues
show
Documentation introduced by
The property updated_at does not exist on object<Spatie\EventProje...Models\ProjectorStatus>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
157
    }
158
159
    public function reset()
160
    {
161
        if (! method_exists($this, 'resetState')) {
162
            throw CouldNotResetProjector::doesNotHaveResetStateMethod($this);
163
        }
164
165
        $this->resetState();
0 ignored issues
show
Bug introduced by
It seems like resetState() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
166
167
        $this->getAllStatuses()->each->delete();
168
    }
169
170
    public function shouldBeCalledImmediately(): bool
171
    {
172
        return ! $this instanceof QueuedProjector;
173
    }
174
175
    protected function getEventStreams(StoredEvent $storedEvent): Collection
176
    {
177
        $streams = method_exists($this, 'streamEventsBy')
178
            ? $this->streamEventsBy($storedEvent)
0 ignored issues
show
Bug introduced by
It seems like streamEventsBy() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
179
            : [];
180
181
        return collect(array_wrap($streams))
182
            ->mapWithKeys(function ($streamValue, $streamName) use ($storedEvent) {
183
                if (is_numeric($streamName)) {
184
                    $streamName = $streamValue;
185
186
                    $streamValue = array_get($storedEvent->event_properties, $streamName);
0 ignored issues
show
Documentation introduced by
The property event_properties does not exist on object<Spatie\EventProjector\Models\StoredEvent>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
187
                }
188
189
                return [$streamName => $streamValue];
190
            });
191
    }
192
193
    protected function getEventStreamFullNames(StoredEvent $storedEvent): array
194
    {
195
        $streamFullNames = $this->getEventStreams($storedEvent)
196
            ->map(function ($streamValue, $streamName) {
197
                return "{$streamName}-{$streamValue}";
198
            })
199
            ->toArray();
200
201
        if (count($streamFullNames) === 0) {
202
            $streamFullNames = ['main'];
203
        }
204
205
        return $streamFullNames;
206
    }
207
208
    protected function getStatus(string $stream = 'main'): ProjectorStatus
209
    {
210
        return $this->getProjectorStatusClass()::getForProjector($this, $stream);
0 ignored issues
show
Bug introduced by
The method getForProjector cannot be called on $this->getProjectorStatusClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
211
    }
212
213
    protected function getAllStatuses(): Collection
214
    {
215
        return $this->getProjectorStatusClass()::getAllForProjector($this);
0 ignored issues
show
Bug introduced by
The method getAllForProjector cannot be called on $this->getProjectorStatusClass() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
216
    }
217
218
    protected function getStoredEventClass(): string
219
    {
220
        return config('event-projector.stored_event_model');
221
    }
222
223
    protected function getProjectorStatusClass(): string
224
    {
225
        return config('event-projector.projector_status_model');
226
    }
227
}
228