Passed
Push — master ( ff4e9f...624a9a )
by Arthur
35:46
created

AbstractGeneratorCommand   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Test Coverage

Coverage 84.62%

Importance

Changes 0
Metric Value
eloc 73
dl 0
loc 252
ccs 77
cts 91
cp 0.8462
rs 9.68
c 0
b 0
f 0
wmc 34

22 Methods

Rating   Name   Duplication   Size   Complexity  
A afterGeneration() 0 2 1
A beforeGeneration() 0 2 1
A getGeneratorName() 0 3 1
A getFilteredPath() 0 3 1
A getOption() 0 3 1
A getOptions() 0 5 1
A getDestinationFilePath() 0 3 1
A handle() 0 23 4
A getOriginalArgumentInput() 0 6 1
A __call() 0 5 2
A stubName() 0 3 1
A getModule() 0 3 1
A getModuleName() 0 8 2
A handleModuleArgument() 0 3 1
A getArguments() 0 6 1
A handleArguments() 0 9 4
A isOverwriteable() 0 3 1
A defaultStubOptions() 0 7 1
A getOriginalOptionInput() 0 6 1
A getArgument() 0 3 1
A handleOptions() 0 9 4
A handleOverwriteOption() 0 6 2
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: arthur
5
 * Date: 09.03.19
6
 * Time: 17:15.
7
 */
8
9
namespace Foundation\Generator\Abstracts;
10
11
use Foundation\Core\Larapi;
12
use Foundation\Core\Module;
13
use Foundation\Exceptions\Exception;
14
use Foundation\Generator\Support\Stub;
15
use Illuminate\Console\Command;
16
use Illuminate\Contracts\Filesystem\FileExistsException;
17
use Illuminate\Support\Str;
18
use ReflectionClass;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputOption;
21
22
abstract class AbstractGeneratorCommand extends Command
23
{
24
    /**
25
     * The name of the generated resource.
26
     *
27
     * @var string
28
     */
29
    protected $generatorName;
30
31
    /**
32
     * The stub name.
33
     *
34
     * @var string
35
     */
36
    protected $stub;
37
38
    /**
39
     * The file path.
40
     *
41
     * @var string
42
     */
43
    protected $filePath;
44
45
    /**
46
     * The event that will fire when the file is created.
47
     *
48
     * @var string
49
     */
50
    protected $event;
51
52
53
    /**
54
     * The data that is inputted from the options.
55
     *
56
     * @var array
57
     */
58
    protected $optionData = [];
59
60
    /**
61
     * The data that is inputted from the arguments.
62
     *
63
     * @var array
64
     */
65
    protected $argumentData = [];
66
67 25
    public function handle()
68
    {
69 25
        $this->handleArguments();
70 25
        $this->handleOptions();
71
72 25
        $path = $this->getFilteredPath();
73
74 25
        if (file_exists($path) && !$this->isOverwriteable()) {
75
            $this->error("File : {$path} already exists.");
76
            throw new FileExistsException();
77
        }
78
79 25
        $stub = new Stub($this->stubName(), array_merge($this->defaultStubOptions(), $this->stubOptions()));
80
81 25
        $this->beforeGeneration();
82
83 25
        if ($this->event === null)
84
            throw new Exception("No Generator event specified on " . static::class);
85
86 25
        event(new $this->event($path, $stub));
87 25
        $this->info("Created : {$path}");
88
89 25
        $this->afterGeneration();
90 25
    }
91
92 25
    private function getFilteredPath(): string
93
    {
94 25
        return str_replace('\\', '/', $this->getDestinationFilePath());
95
    }
96
97
    /**
98
     * @return string
99
     */
100 23
    protected function getDestinationFilePath(): string
101
    {
102 23
        return $this->getModule()->getPath() . $this->filePath . '/' . $this->getFileName();
103
    }
104
105
    /**
106
     * @return string
107
     */
108
    protected abstract function getFileName(): string;
109
110 5
    protected function isOverwriteable(): bool
111
    {
112 5
        return $this->getOption('overwrite');
113
    }
114
115 25
    protected function getModule(): Module
116
    {
117 25
        return Larapi::getModule($this->getModuleName());
118
    }
119
120 25
    protected function beforeGeneration(): void
121
    {
122 25
    }
123
124 21
    protected function afterGeneration(): void
125
    {
126 21
    }
127
128
    abstract protected function stubOptions(): array;
129
130 25
    protected final function defaultStubOptions(): array
131
    {
132
        return [
133 25
            "LOWER_MODULE" => strtolower($this->getModuleName()),
134 25
            "MODULE" => $this->getModuleName(),
135 25
            "PLURAL_MODULE" => Str::plural($this->getModuleName()),
136 25
            "PLURAL_LOWER_MODULE" => strtolower(Str::plural($this->getModuleName()))
137
        ];
138
    }
139
140
    /**
141
     * Get the console command options.
142
     *
143
     * @return array
144
     */
145 112
    final protected function getOptions()
146
    {
147 112
        $options = $this->setOptions();
148 112
        $options[] = ['overwrite', null, InputOption::VALUE_NONE, 'Overwrite this file if it already exists?'];
149 112
        return $options;
150
    }
151
152
    /**
153
     * Get the console command arguments.
154
     *
155
     * @return array
156
     */
157 112
    final protected function getArguments()
158
    {
159 112
        return array_merge([
160 112
            ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
161
        ],
162 112
            $this->setArguments());
163
    }
164
165
    /**
166
     * Set the console command arguments.
167
     *
168
     * @return array
169
     */
170
    protected abstract function setArguments(): array;
171
172
    /**
173
     * Set the console command options.
174
     *
175
     * @return array
176
     */
177
    protected abstract function setOptions(): array;
178
179
180 112
    protected function getGeneratorName(): string
181
    {
182 112
        return $this->generatorName ?? 'class';
183
    }
184
185
    /**
186
     * Get the stub file name.
187
     * @return string
188
     */
189 18
    protected function stubName()
190
    {
191 18
        return $this->stub;
192
    }
193
194 25
    protected function handleOptions()
195
    {
196 25
        foreach ($this->getOptions() as $option) {
197 25
            $method = 'handle' . ucfirst(strtolower($option[0])) . 'Option';
198 25
            $originalInput = $this->getOriginalOptionInput();
199 25
            if (isset($originalInput[$option[0]])) {
200 25
                $this->optionData[$option[0]] = $originalInput[$option[0]];
201
            } else {
202 1
                $this->optionData[$option[0]] = method_exists($this, $method) ? $this->$method($option[1], $option[2], $option[3], $option[4] ?? null) : $this->option($option[0]);
203
            }
204
        }
205 25
    }
206
207
    protected function handleModuleArgument()
208
    {
209
        return $this->anticipate('For what module would you like to generate a ' . $this->getGeneratorName() . '.', Larapi::getModuleNames());
210
    }
211
212 25
    protected function getModuleName()
213
    {
214 25
        $moduleName = $this->getArgument('module');
215 25
        if ($moduleName === null) {
216
            $this->error('module not specified');
217
            throw new \Exception('Name of module not specified.');
218
        }
219 25
        return $moduleName;
220
    }
221
222 25
    protected function handleArguments()
223
    {
224 25
        foreach ($this->getArguments() as $argument) {
225 25
            $method = 'handle' . ucfirst(strtolower($argument[0])) . 'Argument';
226 25
            $originalInput = $this->getOriginalArgumentInput();
227 25
            if (isset($originalInput[$argument[0]])) {
228 25
                $this->argumentData[$argument[0]] = $originalInput[$argument[0]];
229
            } else {
230
                $this->argumentData[$argument[0]] = method_exists($this, $method) ? $this->$method($argument[1], $argument[2], $argument[3] ?? null) : $this->option($argument[0]);
231
            }
232
        }
233 25
    }
234
235 25
    protected function getArgument(string $argument)
236
    {
237 25
        return $this->argumentData[$argument];
238
    }
239
240 11
    protected function getOption(string $name)
241
    {
242 11
        return $this->optionData[$name];
243
    }
244
245 25
    private function getOriginalOptionInput()
246
    {
247 25
        $reflection = new ReflectionClass($this->input);
248 25
        $property = $reflection->getProperty('options');
249 25
        $property->setAccessible(true);
250 25
        return $property->getValue($this->input);
251
    }
252
253 25
    private function getOriginalArgumentInput()
254
    {
255 25
        $reflection = new ReflectionClass($this->input);
256 25
        $property = $reflection->getProperty('arguments');
257 25
        $property->setAccessible(true);
258 25
        return $property->getValue($this->input);
259
    }
260
261
    public function __call($method, $parameters)
262
    {
263
        $key = str_replace('get', '', $method);
264
        if (array_key_exists(strtolower($method), $this->optionData))
265
            return $this->optionData[$key];
266
    }
267
268 1
    protected function handleOverwriteOption($shortcut, $type, $question, $default)
269
    {
270 1
        if (file_exists($this->getFilteredPath())) {
271
            return $this->confirm('The file exists already. Would you like to overwrite it?', false);
272
        }
273 1
        return false;
274
    }
275
}
276