ApiMakeCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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