Completed
Push — master ( 33591a...530541 )
by Freek
09:49
created

ReplayEventsCommand::determineAfterEventId()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 2
nop 1
1
<?php
2
3
namespace Spatie\EventProjector\Console;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Collection;
7
use Spatie\EventProjector\EventProjectionist;
8
use Spatie\EventProjector\Models\StoredEvent;
9
use Spatie\EventProjector\Projectors\Projector;
10
use Spatie\EventProjector\Exceptions\InvalidEventHandler;
11
12
class ReplayEventsCommand extends Command
13
{
14
    protected $signature = 'event-projector:replay-events
15
                            {--projector=*} : The projector that should receive the event
16
                            {--only-new-events} : Only replay events that were not handled yet';
17
18
    protected $description = 'Replay stored events';
19
20
    /** @var \Spatie\EventProjector\EventProjectionist */
21
    protected $eventProjectionist;
22
23
    /** @var string */
24
    protected $storedEventModelClass;
25
26
    public function __construct(EventProjectionist $eventProjectionist, string $storedEventModelClass)
27
    {
28
        parent::__construct();
29
30
        $this->eventProjectionist = $eventProjectionist;
31
32
        $this->storedEventModelClass = $storedEventModelClass;
33
    }
34
35
    public function handle()
36
    {
37
        if (!$this->commandShouldRun()) {
38
            return;
39
        }
40
41
        $projectors = $this->getProjectors();
42
43
        if ($projectors->isEmpty()) {
44
            $this->warn('No projectors found to replay events to...');
45
46
            return;
47
        }
48
49
        $afterEventId = $this->determineAfterEventId($projectors);
50
51
        if ($afterEventId === StoredEvent::getMaxId()) {
52
            $this->warn("There are no events to replay.");
53
        }
54
55
        $afterEventId === 0
56
            ? $this->comment('Replaying all events...')
57
            : $this->comment("Replaying events after stored event id {$afterEventId}...");
58
        $this->emptyLine();
59
60
        $bar = $this->output->createProgressBar(StoredEvent::count());
61
        $onEventReplayed = function () use ($bar) {
62
            $bar->advance();
63
        };
64
65
        $this->eventProjectionist->replayEvents($projectors, $afterEventId, $onEventReplayed);
66
67
        $bar->finish();
68
69
        $this->emptyLine(2);
70
        $this->comment('All done!');
71
    }
72
73
    protected function getProjectors(): Collection
74
    {
75
        $onlyCallProjectors = $this->option('projector');
76
77
        $this->guardAgainstNonExistingProjectors($onlyCallProjectors);
0 ignored issues
show
Bug introduced by
It seems like $onlyCallProjectors defined by $this->option('projector') on line 75 can also be of type string; however, Spatie\EventProjector\Co...NonExistingProjectors() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
78
79
        $allProjectors = $this->eventProjectionist->getProjectors();
80
81
        if (count($onlyCallProjectors) === 0) {
82
            return $allProjectors;
83
        }
84
85
        return $allProjectors
86
            ->filter(function ($projector) use ($onlyCallProjectors) {
87
                if (!is_string($projector)) {
88
                    $projector = get_class($projector);
89
                }
90
91
                return in_array($projector, $onlyCallProjectors);
92
            });
93
    }
94
95
    protected function guardAgainstNonExistingProjectors(array $onlyCallProjectors)
96
    {
97
        foreach ($onlyCallProjectors as $projector) {
98
            if (!class_exists($projector)) {
99
                throw InvalidEventHandler::doesNotExist($projector);
100
            }
101
        }
102
    }
103
104
    protected function emptyLine(int $amount = 1)
105
    {
106
        foreach (range(1, $amount) as $i) {
107
            $this->line('');
108
        }
109
    }
110
111
    protected function commandShouldRun(): bool
112
    {
113
        if (count($this->option('projector') ?? []) === 0) {
114
            if (!$confirmed = $this->confirm('Are you sure you want to replay the events to all projectors?')) {
115
                $this->warn('No events replayed!');
116
117
                return false;
118
            }
119
        }
120
121
        return true;
122
    }
123
124
    protected function determineAfterEventId(Collection $projectors): int
125
    {
126
        //TODO: add test
127
        if (!$this->hasOption('only-new-events')) {
128
            return 0;
129
        }
130
131
        return $projectors
132
            ->map(function ($projector) {
133
                if (is_string($projector)) {
134
                    $projector = app($projector);
135
                }
136
137
                return $projector;
138
            })
139
            ->map(function (Projector $projector) {
140
                return $projector->getLastProcessedEventId();
141
            })
142
            ->min();
143
    }
144
}
145