Issues (28)

src/Console/Commands/RegisterReacters.php (2 issues)

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\Reacterable\Exceptions\ReacterableInvalid;
17
use Cog\Contracts\Love\Reacterable\Models\Reacterable as ReacterableInterface;
18
use Illuminate\Console\Command;
19
use Illuminate\Database\Eloquent\Collection;
20
use Illuminate\Database\Eloquent\Relations\Relation;
21
use Symfony\Component\Console\Attribute\AsCommand;
22
use Symfony\Component\Console\Input\InputOption;
23
24
#[AsCommand(name: 'love:register-reacters', description: 'Register Reacterable models as Reacters')]
25
final class RegisterReacters extends Command
26
{
27
    /**
28
     * @return array<int, InputOption>
29
     */
30
    protected function getOptions(): array
31
    {
32
        return [
33
            new InputOption(
34
                name: 'model',
35
                mode: InputOption::VALUE_REQUIRED,
36
                description: 'The name of the Reacterable model',
37
            ),
38
            new InputOption(
39
                name: 'ids',
40
                mode: InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
41
                description: '(optional) Comma-separated list of model IDs (e.g. `--ids=1,2,16,34`)',
42
            ),
43
        ];
44
    }
45
46
    /**
47
     * Execute the console command.
48
     */
49
    public function handle(): int
50
    {
51
        $reacterableType = $this->option('model');
52
        if ($reacterableType === null) {
53
            $this->error('Option `--model` is required!');
54
55
            return self::FAILURE;
56
        }
57
58
        try {
59
            $reacterableModel = $this->reacterableModelFromType($reacterableType);
60
61
            $modelIds = $this->option('ids');
62
            $modelIds = $this->normalizeIds($modelIds);
0 ignored issues
show
It seems like $modelIds can also be of type boolean and null and string; however, parameter $modelIds of Cog\Laravel\Love\Console...eacters::normalizeIds() does only seem to accept array, 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

62
            $modelIds = $this->normalizeIds(/** @scrutinizer ignore-type */ $modelIds);
Loading history...
63
64
            $models = $this->collectModels($reacterableModel, $modelIds);
65
66
            $this->info(sprintf('Models registering as Reacters %s', PHP_EOL));
67
            $this->line(sprintf('Model Type: <fg=Cyan>%s</>', get_class($reacterableModel)));
68
69
            $this->registerModelsAsReacters($models);
70
71
            $this->info('Models has been registered as Reacters');
72
        } catch (ReacterableInvalid $exception) {
73
            $this->error($exception->getMessage());
74
75
            return self::FAILURE;
76
        }
77
78
        return self::SUCCESS;
79
    }
80
81
    /**
82
     * Instantiate model from type or morph map value.
83
     *
84
     * @param string $modelType
85
     * @return \Cog\Contracts\Love\Reacterable\Models\Reacterable|\Illuminate\Database\Eloquent\Model
86
     *
87
     * @throws \Cog\Contracts\Love\Reacterable\Exceptions\ReacterableInvalid
88
     */
89
    private function reacterableModelFromType(
90
        string $modelType,
91
    ): ReacterableInterface {
92
        if (!class_exists($modelType)) {
93
            $modelType = $this->findModelTypeInMorphMap($modelType);
94
        }
95
96
        $model = new $modelType();
97
98
        if (!$model instanceof ReacterableInterface) {
99
            throw ReacterableInvalid::notImplementInterface($modelType);
100
        }
101
102
        return $model;
103
    }
104
105
    /**
106
     * Find model type in morph mappings registry.
107
     *
108
     * @throws \Cog\Contracts\Love\Reacterable\Exceptions\ReacterableInvalid
109
     */
110
    private function findModelTypeInMorphMap(
111
        string $modelType,
112
    ): string {
113
        $morphMap = Relation::morphMap();
114
115
        if (!isset($morphMap[$modelType])) {
116
            throw ReacterableInvalid::classNotExists($modelType);
117
        }
118
119
        return $morphMap[$modelType];
120
    }
121
122
    private function normalizeIds(
123
        array $modelIds,
124
    ): array {
125
        if (!isset($modelIds[0])) {
126
            return $modelIds;
127
        }
128
129
        $firstItem = $modelIds[0];
130
131
        if (is_string($firstItem) && strpos($firstItem, ',')) {
132
            $modelIds = explode(',', $firstItem);
133
        }
134
135
        return $modelIds;
136
    }
137
138
    /**
139
     * @param \Cog\Contracts\Love\Reacterable\Models\Reacterable|\Illuminate\Database\Eloquent\Model $reacterableModel
140
     * @param array $modelIds
141
     * @return Collection
142
     */
143
    private function collectModels(
144
        ReacterableInterface $reacterableModel,
145
        array $modelIds,
146
    ): Collection {
147
        $query = $reacterableModel
148
            ->query()
0 ignored issues
show
The method query() does not exist on Cog\Contracts\Love\Reacterable\Models\Reacterable. Since it exists in all sub-types, consider adding an abstract or default implementation to Cog\Contracts\Love\Reacterable\Models\Reacterable. ( Ignorable by Annotation )

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

148
            ->/** @scrutinizer ignore-call */ query()
Loading history...
149
            ->whereNull('love_reacter_id');
150
151
        if (!empty($modelIds)) {
152
            $query->whereKey($modelIds);
153
        }
154
155
        return $query->get();
156
    }
157
158
    private function registerModelsAsReacters(
159
        Collection $models,
160
    ): void {
161
        $collectedCount = $models->count();
162
        $progressBar = $this->output->createProgressBar($collectedCount);
163
164
        foreach ($models as $model) {
165
            $model->registerAsLoveReacter();
166
            $progressBar->advance();
167
        }
168
169
        $progressBar->finish();
170
        $this->line(PHP_EOL);
171
    }
172
}
173