Passed
Push — master ( bb25ac...f8d231 )
by Ilya
03:01
created

HandlerMakeCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
namespace Hivokas\LaravelHandlers\Commands;
4
5
use Illuminate\Filesystem\Filesystem;
6
use Illuminate\Console\GeneratorCommand;
7
use Hivokas\LaravelHandlers\Support\ActionsBag;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Hivokas\LaravelHandlers\Exceptions\CommandException;
11
12
class HandlerMakeCommand extends GeneratorCommand
13
{
14
    /**
15
     * The console command name.
16
     *
17
     * @var string
18
     */
19
    protected $name = 'make:handler';
20
21
    /**
22
     * The console command description.
23
     *
24
     * @var string
25
     */
26
    protected $description = 'Handler generator.';
27
28
    /**
29
     * HandlerMakeCommand constructor.
30
     *
31
     * @param Filesystem $files
32
     */
33 17
    public function __construct(Filesystem $files)
34
    {
35 17
        parent::__construct($files);
36 17
    }
37
38
    /**
39
     * Execute the console command.
40
     *
41
     * @return bool
42
     */
43 16
    public function handle(): bool
44
    {
45
        try {
46 16
            $bag = new ActionsBag;
47
48 16
            $this->processResourceOption($bag);
49 16
            $this->processActionsOption($bag);
50 15
            $this->processExceptOption($bag);
51 14
            $this->processApiOption($bag);
52
53 14
            $classNames = $this->generateClassNames($bag, $this->getValidatedNameArgument());
54
55 13
            $finalNamespace = $this->getFinalNamespace();
56
57 12
            foreach ($classNames as $className) {
58 12
                $fullClassName = $finalNamespace.'\\'.$className;
59
60 12
                $type = $className.' handler';
61
62 12
                $path = $this->getPath($fullClassName);
63
64 12
                if ((! $this->hasOption('force') ||
65 12
                        ! $this->option('force')) &&
66 12
                    $this->alreadyExists($fullClassName)) {
67 1
                    $this->error($type.' already exists!');
68
69 1
                    continue;
70
                }
71
72 11
                $this->makeDirectory($path);
73
74 11
                $this->files->put($path, $this->buildClass($fullClassName));
75
76 11
                $this->info($type.' created successfully.');
77
            }
78 5
        } catch (CommandException $exception) {
79 5
            $this->error($exception->getMessage());
80
81 5
            return false;
82
        }
83
84 11
        return true;
85
    }
86
87
    /**
88
     * Get final namespace determined by default and specified by user namespaces.
89
     *
90
     * @return string
91
     * @throws CommandException
92
     */
93 13
    protected function getFinalNamespace(): string
94
    {
95 13
        $defaultNamespace = $this->laravel->getNamespace().'Http\\Handlers';
96
97 13
        if (! is_null($namespaceOption = $this->getValidatedAndNormalizedNamespaceOption())) {
98 2
            if (starts_with($namespaceOption, '\\')) {
99 1
                return $namespaceOption;
100
            }
101
102 1
            return $defaultNamespace.'\\'.$namespaceOption;
103
        }
104
105 10
        return $defaultNamespace;
106
    }
107
108
    /**
109
     * Get validated and normalized namespace option.
110
     *
111
     * @return string|null
112
     * @throws CommandException
113
     */
114 13
    protected function getValidatedAndNormalizedNamespaceOption(): ?string
115
    {
116 13
        $namespace = (string) $this->option('namespace');
117
118 13
        if (! $namespace) {
119 10
            return null;
120
        }
121
122 3
        $namespaceWithNormalizedSlashes = preg_replace('/[\/\\\]+/', '\\', $namespace);
123
124 3
        if (! preg_match('/^(\\\|(\\\?\w+)+)$/', $namespaceWithNormalizedSlashes)) {
125 1
            throw new CommandException('['.$namespace.'] is not a valid namespace.');
126
        }
127
128 2
        return $namespaceWithNormalizedSlashes;
129
    }
130
131
    /**
132
     * Generate class names by specified name and actions.
133
     *
134
     * @param ActionsBag $bag
135
     * @param string $name
136
     * @return array
137
     */
138 13
    protected function generateClassNames(ActionsBag $bag, string $name): array
139
    {
140 13
        $name = studly_case($name);
141
142 13
        if ($bag->isEmpty()) {
143 9
            return [$name];
144
        } else {
145
            return array_map(function (string $action) use ($name) {
146 4
                return studly_case($action).$name;
147 4
            }, $bag->get());
148
        }
149
    }
150
151
    /**
152
     * Get validated name argument.
153
     *
154
     * @return string
155
     * @throws CommandException
156
     */
157 14
    protected function getValidatedNameArgument(): string
158
    {
159 14
        $name = (string) $this->argument('name');
160 14
        if (! preg_match('/^\w+$/', $name)) {
161 1
            throw new CommandException('Name can\'t contain any non-word characters.');
162
        }
163
164 13
        return $name;
165
    }
166
167
    /**
168
     * Process --resource option.
169
     *
170
     * @param ActionsBag $bag
171
     * @return void
172
     */
173 16
    protected function processResourceOption(ActionsBag $bag): void
174
    {
175 16
        if ($this->option('resource')) {
176 4
            foreach (['index', 'show', 'create', 'store', 'edit', 'update', 'destroy'] as $action) {
177 4
                $bag->addIfNotExists($action);
178
            }
179
        }
180 16
    }
181
182
    /**
183
     * Process --actions option.
184
     *
185
     * @param ActionsBag $bag
186
     * @return void
187
     * @throws CommandException
188
     */
189 16
    protected function processActionsOption(ActionsBag $bag): void
190
    {
191 16
        if ($actions = (string) $this->option('actions')) {
192 2
            foreach (explode(',', $actions) as $action) {
193 2
                $bag->addIfNotExists(
194 2
                    $this->getValidatedAndNormalizedActionName($action)
195
                );
196
            }
197
        }
198 15
    }
199
200
    /**
201
     * Process --except option.
202
     *
203
     * @param ActionsBag $bag
204
     * @return void
205
     * @throws CommandException
206
     */
207 15
    protected function processExceptOption(ActionsBag $bag): void
208
    {
209 15
        if ($except = (string) $this->option('except')) {
210 2
            foreach (explode(',', $except) as $action) {
211 2
                $bag->deleteIfExists(
212 2
                    $this->getValidatedAndNormalizedActionName($action)
213
                );
214
            }
215
        }
216 14
    }
217
218
    /**
219
     * Process an --api option.
220
     *
221
     * @param ActionsBag $bag
222
     * @return void
223
     */
224 14
    protected function processApiOption(ActionsBag $bag): void
225
    {
226 14
        if ($this->option('api')) {
227 1
            foreach (['edit', 'create'] as $action) {
228 1
                $bag->deleteIfExists($action);
229
            }
230
        }
231 14
    }
232
233
    /**
234
     * Get validated and normalized action name.
235
     *
236
     * @param string $action
237
     * @return string
238
     * @throws CommandException
239
     */
240 4
    protected function getValidatedAndNormalizedActionName(string $action): string
241
    {
242 4
        if (preg_match('/^\w+$/', $action)) {
243 4
            return snake_case($action);
244
        }
245
246 2
        throw new CommandException('['.$action.'] is not a valid action name.');
247
    }
248
249
    /**
250
     * Get the name input.
251
     *
252
     * @return null|string
253
     */
254
    public function getNameInput(): ?string
255
    {
256
        return $this->nameInput;
0 ignored issues
show
Bug Best Practice introduced by
The property nameInput does not exist on Hivokas\LaravelHandlers\...ands\HandlerMakeCommand. Did you maybe forget to declare it?
Loading history...
257
    }
258
259
    /**
260
     * Get the stub file for the generator.
261
     *
262
     * @return string
263
     */
264 11
    protected function getStub(): string
265
    {
266 11
        return __DIR__.'/../../stubs/handler.stub';
267
    }
268
269
    /**
270
     * Get the class name of the base handler.
271
     *
272
     * @return string
273
     * @throws CommandException
274
     */
275 11
    protected function getBaseHandlerClassName(): string
276
    {
277 11
        if (class_exists($base = config('handlers.base'))) {
278 10
            return $base;
279
        }
280
281 1
        throw new CommandException('The ['.$base.'] class specified as the base handler doesn\'t exist.');
282
    }
283
284
    /**
285
     * Replace the namespace for the given stub.
286
     *
287
     * @param  string $stub
288
     * @param  string $name
289
     * @return $this
290
     * @throws CommandException
291
     */
292 11
    protected function replaceNamespace(&$stub, $name)
293
    {
294 11
        $stub = str_replace(
295 11
            ['DummyNamespace', 'DummyBaseHandlerNamespace'],
296 11
            [$this->getNamespace($name), $this->getBaseHandlerClassName()],
297 10
            $stub
298
        );
299
300 10
        return $this;
301
    }
302
303
    /**
304
     * Get the console command arguments.
305
     *
306
     * @return array
307
     */
308 17
    protected function getArguments(): array
309
    {
310
        return [
311 17
            ['name', InputArgument::REQUIRED, 'The name of the class'],
312
        ];
313
    }
314
315
    /**
316
     * Get the console command options.
317
     *
318
     * @return array
319
     */
320 17
    protected function getOptions(): array
321
    {
322
        return [
323 17
            ['resource', 'r', InputOption::VALUE_NONE, 'Generate handlers for all resource actions.'],
324 17
            ['api', 'a', InputOption::VALUE_NONE, 'Exclude the create and edit actions.'],
325 17
            ['namespace', null, InputOption::VALUE_REQUIRED, 'The namespace for generated handler(-s).'],
326 17
            ['force', 'f', InputOption::VALUE_NONE, 'Override existing handlers.'],
327 17
            ['actions', null, InputOption::VALUE_REQUIRED, 'Generate handlers for all specified actions separated by coma.'],
328 17
            ['except', null, InputOption::VALUE_REQUIRED, 'Exclude specified actions separated by coma.'],
329
        ];
330
    }
331
}
332