Completed
Pull Request — master (#148)
by Anton
09:05
created

Recount::recountCounters()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
3
/*
4
 * This file is part of Laravel Love.
5
 *
6
 * (c) Anton Komarev <[email protected]>
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
declare(strict_types=1);
13
14
namespace Cog\Laravel\Love\Console\Commands;
15
16
use Cog\Contracts\Love\Reactable\Exceptions\ReactableInvalid;
17
use Cog\Contracts\Love\Reactable\Models\Reactable as ReactableContract;
18
use Cog\Laravel\Love\Reactant\Jobs\RebuildReactionAggregatesJob;
19
use Cog\Laravel\Love\Reactant\Models\Reactant;
20
use Cog\Laravel\Love\ReactionType\Models\ReactionType;
21
use Illuminate\Console\Command;
22
use Illuminate\Contracts\Bus\Dispatcher;
23
use Illuminate\Database\Eloquent\Relations\Relation;
24
use Symfony\Component\Console\Input\InputOption;
25
26
final class Recount extends Command
27
{
28
    /**
29
     * The console command name.
30
     *
31
     * @var string
32
     */
33
    protected $name = 'love:recount';
34
35
    /**
36
     * The console command description.
37
     *
38
     * @var string
39
     */
40
    protected $description = 'Recount reactions of the reactable models';
41
42
    /**
43
     * @var \Illuminate\Contracts\Bus\Dispatcher
44
     */
45
    private $dispatcher;
46
47
    protected function getOptions(
48
    ): array {
49
        return [
50
            ['model', null, InputOption::VALUE_OPTIONAL, 'The name of the reactable model'],
51
            ['type', null, InputOption::VALUE_OPTIONAL, 'The name of the reaction type'],
52
            ['queue-connection', null, InputOption::VALUE_OPTIONAL, 'The name of the queue connection'],
53
        ];
54
    }
55
56
    public function __construct(
57
        Dispatcher $dispatcher
58
    ) {
59
        parent::__construct();
60
        $this->dispatcher = $dispatcher;
61
    }
62
63
    /**
64
     * Execute the console command.
65
     *
66
     * @return void
67
     *
68
     * @throws \Cog\Contracts\Love\Reactable\Exceptions\ReactableInvalid
69
     */
70
    public function handle(
71
    ): void {
72
        if ($reactableType = $this->option('model')) {
73
            $reactableType = $this->normalizeReactableModelType($reactableType);
74
        }
75
76
        if ($reactionType = $this->option('type')) {
77
            $reactionType = ReactionType::fromName($reactionType);
78
        }
79
80
        $queueConnectionName = $this->option('queue-connection');
81
82
        $reactants = $this->collectReactants($reactableType);
83
84
        $this->getOutput()->progressStart($reactants->count());
85
        foreach ($reactants as $reactant) {
86
            $this->dispatcher->dispatch(
87
                (new RebuildReactionAggregatesJob($reactant, $reactionType))
88
                    ->onConnection($queueConnectionName)
0 ignored issues
show
Bug introduced by
It seems like $queueConnectionName can also be of type string[]; however, parameter $connection of Cog\Laravel\Love\Reactan...atesJob::onConnection() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

88
                    ->onConnection(/** @scrutinizer ignore-type */ $queueConnectionName)
Loading history...
89
            );
90
91
            $this->getOutput()->progressAdvance();
92
        }
93
        $this->getOutput()->progressFinish();
94
    }
95
96
    /**
97
     * Normalize reactable model type.
98
     *
99
     * @param string $modelType
100
     * @return string
101
     *
102
     * @throws \Cog\Contracts\Love\Reactable\Exceptions\ReactableInvalid
103
     */
104
    private function normalizeReactableModelType(
105
        string $modelType
106
    ): string {
107
        return $this
108
            ->reactableModelFromType($modelType)
109
            ->getMorphClass();
0 ignored issues
show
Bug introduced by
The method getMorphClass() does not exist on Cog\Contracts\Love\Reactable\Models\Reactable. Since it exists in all sub-types, consider adding an abstract or default implementation to Cog\Contracts\Love\Reactable\Models\Reactable. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
            ->/** @scrutinizer ignore-call */ getMorphClass();
Loading history...
110
    }
111
112
    /**
113
     * Instantiate model from type or morph map value.
114
     *
115
     * @param string $modelType
116
     * @return \Cog\Contracts\Love\Reactable\Models\Reactable|\Illuminate\Database\Eloquent\Model
117
     *
118
     * @throws \Cog\Contracts\Love\Reactable\Exceptions\ReactableInvalid
119
     */
120
    private function reactableModelFromType(
121
        string $modelType
122
    ): ReactableContract {
123
        if (!class_exists($modelType)) {
124
            $modelType = $this->findModelTypeInMorphMap($modelType);
125
        }
126
127
        $model = new $modelType();
128
129
        if (!$model instanceof ReactableContract) {
130
            throw ReactableInvalid::notImplementInterface($modelType);
131
        }
132
133
        return $model;
134
    }
135
136
    /**
137
     * Find model type in morph mappings registry.
138
     *
139
     * @param string $modelType
140
     * @return string
141
     *
142
     * @throws \Cog\Contracts\Love\Reactable\Exceptions\ReactableInvalid
143
     */
144
    private function findModelTypeInMorphMap(
145
        string $modelType
146
    ): string {
147
        $morphMap = Relation::morphMap();
148
149
        if (!isset($morphMap[$modelType])) {
150
            throw ReactableInvalid::classNotExists($modelType);
151
        }
152
153
        return $morphMap[$modelType];
154
    }
155
156
    /**
157
     * @param string|null $reactableType
158
     * @return \Cog\Contracts\Love\Reactant\Models\Reactant[]|\Illuminate\Database\Eloquent\Collection
159
     */
160
    private function collectReactants(
161
        ?string $reactableType = null
162
    ): iterable {
163
        $reactantsQuery = Reactant::query();
164
165
        if ($reactableType !== null) {
166
            $reactantsQuery->where('type', $reactableType);
167
        }
168
169
        return $reactantsQuery->get();
170
    }
171
}
172