ApiMakeCommand::handle()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Arrilot\Api\Generator;
4
5
use Illuminate\Console\DetectsApplicationNamespace;
6
use Illuminate\Console\Command;
7
use Illuminate\Filesystem\Filesystem;
8
use Symfony\Component\Console\Input\InputArgument;
9
10
class ApiMakeCommand extends Command
11
{
12
    use DetectsApplicationNamespace;
13
14
    /**
15
     * The filesystem instance.
16
     *
17
     * @var \Illuminate\Filesystem\Filesystem
18
     */
19
    protected $files;
20
21
    /**
22
     * The console command name.
23
     *
24
     * @var string
25
     */
26
    protected $name = 'make:api';
27
28
    /**
29
     * The console command description.
30
     *
31
     * @var string
32
     */
33
    protected $description = 'Create api controller, transformer and api routes for a given model (arrilot/laravel-api-generator)';
34
35
    /**
36
     * The array of variables available in stubs.
37
     *
38
     * @var array
39
     */
40
    protected $stubVariables = [
41
        'app'         => [],
42
        'model'       => [],
43
        'controller'  => [],
44
        'transformer' => [],
45
        'route'       => [],
46
    ];
47
48
    protected $modelsBaseNamespace;
49
50
    /**
51
     * Create a new controller creator command instance.
52
     *
53
     * @param \Illuminate\Filesystem\Filesystem $files
54
     */
55
    public function __construct(Filesystem $files)
56
    {
57
        parent::__construct();
58
59
        $this->files = $files;
60
    }
61
62
    /**
63
     * Execute the console command.
64
     *
65
     * @return void
66
     */
67
    public function handle()
68
    {
69
        $this->prepareVariablesForStubs($this->argument('name'));
70
71
        $this->createController();
72
73
        $this->createTransformer();
74
75
        $this->addRoutes();
76
    }
77
78
    /**
79
     * Prepare names, paths and namespaces for stubs.
80
     *
81
     * @param $name
82
     */
83
    protected function prepareVariablesForStubs($name)
84
    {
85
        $this->stubVariables['app']['namespace'] = $this->getAppNamespace();
86
87
        $baseDir = config('laravel-api-generator.models_base_dir');
88
89
        $this->modelsBaseNamespace = $baseDir ? trim($baseDir, '\\').'\\' : '';
90
91
        $this->setModelData($name)
92
            ->setControllerData()
93
            ->setRouteData()
94
            ->setTransformerData();
95
    }
96
97
    /**
98
     * Set the model name and namespace.
99
     *
100
     * @return $this
101
     */
102
    protected function setModelData($name)
103
    {
104
        if (str_contains($name, '/')) {
105
            $name = $this->convertSlashes($name);
106
        }
107
108
        $name = trim($name, '\\');
109
110
        $this->stubVariables['model']['fullNameWithoutRoot'] = $name;
111
        $this->stubVariables['model']['fullName'] = $this->stubVariables['app']['namespace'].$this->modelsBaseNamespace.$name;
112
113
        $exploded = explode('\\', $this->stubVariables['model']['fullName']);
114
        $this->stubVariables['model']['name'] = array_pop($exploded);
115
        $this->stubVariables['model']['namespace'] = implode('\\', $exploded);
116
117
        $exploded = explode('\\', $this->stubVariables['model']['fullNameWithoutRoot']);
118
        array_pop($exploded);
119
        $this->stubVariables['model']['additionalNamespace'] = implode('\\', $exploded);
120
121
        return $this;
122
    }
123
124
    /**
125
     * Set the controller names and namespaces.
126
     *
127
     * @return $this
128
     */
129
    protected function setControllerData()
130
    {
131
        return $this->setDataForEntity('controller');
132
    }
133
134
    /**
135
     * Set route data for a given model.
136
     * "Profile\Payer" -> "profile_payers".
137
     *
138
     * @return $this
139
     */
140
    protected function setRouteData()
141
    {
142
        $name = str_replace('\\', '', $this->stubVariables['model']['fullNameWithoutRoot']);
143
        $name = snake_case($name);
144
145
        $this->stubVariables['route']['name'] = str_plural($name);
146
147
        return $this;
148
    }
149
150
    /**
151
     * Set the transformer names and namespaces.
152
     *
153
     * @return $this
154
     */
155
    protected function setTransformerData()
156
    {
157
        return $this->setDataForEntity('transformer');
158
    }
159
160
    /**
161
     *  Set entity's names and namespaces.
162
     *
163
     * @param string $entity
164
     *
165
     * @return $this
166
     */
167
    protected function setDataForEntity($entity)
168
    {
169
        $entityNamespace = $this->convertSlashes(config("laravel-api-generator.{$entity}s_dir"));
170
        $this->stubVariables[$entity]['name'] = $this->stubVariables['model']['name'].ucfirst($entity);
171
172
        $this->stubVariables[$entity]['namespaceWithoutRoot'] = implode('\\', array_filter([
173
            $entityNamespace,
174
            $this->stubVariables['model']['additionalNamespace'],
175
        ]));
176
177
        $this->stubVariables[$entity]['namespaceBase'] = $this->stubVariables['app']['namespace'].$entityNamespace;
178
179
        $this->stubVariables[$entity]['namespace'] = $this->stubVariables['app']['namespace'].$this->stubVariables[$entity]['namespaceWithoutRoot'];
180
181
        $this->stubVariables[$entity]['fullNameWithoutRoot'] = $this->stubVariables[$entity]['namespaceWithoutRoot'].'\\'.$this->stubVariables[$entity]['name'];
182
183
        $this->stubVariables[$entity]['fullName'] = $this->stubVariables[$entity]['namespace'].'\\'.$this->stubVariables[$entity]['name'];
184
185
        return $this;
186
    }
187
188
    /**
189
     *  Create controller class file from a stub.
190
     */
191
    protected function createController()
192
    {
193
        $this->createClass('controller');
194
    }
195
196
    /**
197
     *  Create controller class file from a stub.
198
     */
199
    protected function createTransformer()
200
    {
201
        $this->createClass('transformer');
202
    }
203
204
    /**
205
     *  Add routes to routes file.
206
     */
207
    protected function addRoutes()
208
    {
209
        $stub = $this->constructStub(base_path(config('laravel-api-generator.route_stub')));
210
211
        $routesFile = app_path(config('laravel-api-generator.routes_file'));
212
213
        // read file
214
        $lines = file($routesFile);
215
        $lastLine = trim($lines[count($lines) - 1]);
216
217
        // modify file
218
        if (strcmp($lastLine, '});') === 0) {
219
            $lines[count($lines) - 1] = '    '.$stub;
220
            $lines[] = "\r\n});\r\n";
221
        } else {
222
            $lines[] = "$stub\r\n";
223
        }
224
225
        // save file
226
        $fp = fopen($routesFile, 'w');
227
        fwrite($fp, implode('', $lines));
228
        fclose($fp);
229
230
        $this->info('Routes added successfully.');
231
    }
232
233
    /**
234
     * Create class with a given type.
235
     *
236
     * @param $type
237
     *
238
     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
239
     */
240
    protected function createClass($type)
241
    {
242
        $path = $this->getPath($this->stubVariables[$type]['fullNameWithoutRoot']);
243
        if ($this->files->exists($path)) {
244
            $this->error(ucfirst($type).' already exists!');
245
246
            return;
247
        }
248
249
        $this->makeDirectoryIfNeeded($path);
250
251
        $this->files->put($path, $this->constructStub(base_path(config('laravel-api-generator.'.$type.'_stub'))));
252
253
        $this->info(ucfirst($type).' created successfully.');
254
    }
255
256
    /**
257
     * Get the destination file path.
258
     *
259
     * @param string $name
260
     *
261
     * @return string
262
     */
263
    protected function getPath($name)
264
    {
265
        $name = str_replace($this->stubVariables['app']['namespace'], '', $name);
266
267
        return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php';
268
    }
269
270
    /**
271
     * Build the directory for the class if needed.
272
     *
273
     * @param string $path
274
     *
275
     * @return string
276
     */
277
    protected function makeDirectoryIfNeeded($path)
278
    {
279
        if (!$this->files->isDirectory(dirname($path))) {
280
            $this->files->makeDirectory(dirname($path), 0777, true, true);
281
        }
282
    }
283
284
    /**
285
     * Get stub content and replace all stub placeholders
286
     * with data from $this->stubData.
287
     *
288
     * @param string $path
289
     *
290
     * @return string
291
     */
292
    protected function constructStub($path)
293
    {
294
        $stub = $this->files->get($path);
295
296
        foreach ($this->stubVariables as $entity => $fields) {
297
            foreach ($fields as $field => $value) {
298
                $stub = str_replace("{{{$entity}.{$field}}}", $value, $stub);
299
            }
300
        }
301
302
        return $stub;
303
    }
304
305
    /**
306
     * Get the console command arguments.
307
     *
308
     * @return array
309
     */
310
    protected function getArguments()
311
    {
312
        return [
313
            ['name', InputArgument::REQUIRED, 'The name of the model'],
314
        ];
315
    }
316
317
    /**
318
     * Convert "/" to "\".
319
     *
320
     * @param $string
321
     *
322
     * @return string
323
     */
324
    protected function convertSlashes($string)
325
    {
326
        return str_replace('/', '\\', $string);
327
    }
328
}
329