Issues (28)

src/Console/Commands/ReactionTypeAdd.php (1 issue)

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\Laravel\Love\ReactionType\Models\ReactionType;
17
use Illuminate\Console\Command;
18
use Illuminate\Support\Str;
19
use Symfony\Component\Console\Attribute\AsCommand;
20
use Symfony\Component\Console\Input\InputOption;
21
22
#[AsCommand(name: 'love:reaction-type-add', description: 'Add Reaction Type to Laravel Love')]
23
final class ReactionTypeAdd extends Command
24
{
25
    /**
26
     * Execute the console command.
27
     */
28
    public function handle(): int
29
    {
30
        if ($this->option('default')) {
31
            $this->createDefaultReactionTypes();
32
33
            return self::SUCCESS;
34
        }
35
36
        $name = $this->resolveName();
37
        $name = $this->sanitizeName($name);
38
39
        if ($this->isNameInvalid($name)) {
40
            $this->error(
41
                sprintf(
42
                    'Reaction type with name `%s` is invalid.',
43
                    $name,
44
                ),
45
            );
46
47
            return self::FAILURE;
48
        }
49
50
        if ($this->isReactionTypeNameExists($name)) {
51
            $this->error(
52
                sprintf(
53
                    'Reaction type with name `%s` already exists.',
54
                    $name,
55
                ),
56
            );
57
58
            return self::FAILURE;
59
        }
60
61
        $this->createReactionType($name, $this->resolveMass());
62
63
        return self::SUCCESS;
64
    }
65
66
    /**
67
     * @return array<int, InputOption>
68
     */
69
    protected function getOptions(): array
70
    {
71
        return [
72
            new InputOption(
73
                name: 'default',
74
                mode: InputOption::VALUE_NONE,
75
                description: 'Create default Like & Dislike reactions',
76
            ),
77
            new InputOption(
78
                name: 'name',
79
                mode: InputOption::VALUE_OPTIONAL,
80
                description: 'The name of the reaction',
81
            ),
82
            new InputOption(
83
                name: 'mass',
84
                mode: InputOption::VALUE_OPTIONAL,
85
                description: 'The mass of the reaction',
86
            ),
87
        ];
88
    }
89
90
    private function createDefaultReactionTypes(): void
91
    {
92
        $types = [
93
            [
94
                'name' => 'Like',
95
                'mass' => 1,
96
            ],
97
            [
98
                'name' => 'Dislike',
99
                'mass' => -1,
100
            ],
101
        ];
102
103
        foreach ($types as $type) {
104
            if ($this->isReactionTypeNameExists($type['name'])) {
105
                $this->line(
106
                    sprintf(
107
                        'Reaction type with name `%s` already exists.',
108
                        $type['name'],
109
                    ),
110
                );
111
                continue;
112
            }
113
114
            $this->createReactionType($type['name'], $type['mass']);
115
        }
116
    }
117
118
    private function createReactionType(
119
        string $name,
120
        int $mass,
121
    ): void {
122
        ReactionType::query()->create([
123
            'name' => $name,
124
            'mass' => $mass,
125
        ]);
126
127
        $this->line(
128
            sprintf(
129
                'Reaction type with name `%s` and mass `%d` was added.',
130
                $name,
131
                $mass,
132
            ),
133
        );
134
    }
135
136
    private function resolveName(): string
137
    {
138
        return $this->option('name')
139
            ?? $this->ask('How to name reaction type?')
140
            ?? '';
141
    }
142
143
    private function resolveMass(): int
144
    {
145
        $mass = $this->option('mass')
146
            ?? $this->ask('What is the mass of this reaction type?')
147
            ?? ReactionType::MASS_DEFAULT;
148
149
        return intval($mass);
150
    }
151
152
    private function sanitizeName(
153
        string $name,
154
    ): string {
155
        $name = trim($name);
156
        $name = Str::studly($name);
157
158
        return $name;
159
    }
160
161
    private function isReactionTypeNameExists(
162
        string $name,
163
    ): bool {
164
        return ReactionType::query()
0 ignored issues
show
Bug Best Practice introduced by
The expression return Cog\Laravel\Love\...name', $name)->exists() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
165
            ->where('name', $name)
166
            ->exists();
167
    }
168
169
    private function isNameInvalid(
170
        string $name,
171
    ): bool {
172
        return preg_match('#^[A-Z][a-zA-Z0-9_]*$#', $name) === 0;
173
    }
174
}
175