Completed
Push — master ( 515813...89ccca )
by Sergi Tur
03:19
created

MakeRoute::createMenu()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 2
eloc 10
nc 2
nop 0
1
<?php
2
3
namespace Acacha\AdminLTETemplateLaravel\Console;
4
5
use Acacha\AdminLTETemplateLaravel\Compiler\StubFileCompiler;
6
use Acacha\AdminLTETemplateLaravel\Console\Routes\Controller;
7
use Acacha\AdminLTETemplateLaravel\Console\Routes\ControllerResourceRoute;
8
use Acacha\AdminLTETemplateLaravel\Console\Routes\ControllerRoute;
9
use Acacha\AdminLTETemplateLaravel\Console\Routes\GeneratesCode;
10
use Acacha\AdminLTETemplateLaravel\Console\Routes\RegularRoute;
11
use Acacha\AdminLTETemplateLaravel\Exceptions\RouteTypeNotValid;
12
use Acacha\AdminLTETemplateLaravel\Exceptions\SpatieMenuDoesNotExists;
13
use Acacha\AdminLTETemplateLaravel\Filesystem\Filesystem;
14
use Illuminate\Console\Command;
15
use Illuminate\Routing\Router;
16
use Illuminate\Support\Facades\Artisan;
17
use Route;
18
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
19
20
/**
21
 * Class MakeRoute.
22
 */
23
class MakeRoute extends Command
24
{
25
     use Controller;
26
27
    /**
28
     * Path to web routes file.
29
     *
30
     * @var string
31
     */
32
    protected $web_routes_path = 'routes/web.php';
33
34
    /**
35
     * Path to api routes file.
36
     *
37
     * @var string
38
     */
39
    protected $api_routes_path = 'routes/api.php';
40
41
    /**
42
     * Compiler for stub file.
43
     *
44
     * @var StubFileCompiler
45
     */
46
    protected $compiler;
47
48
    /**
49
     * Compiler for stub file.
50
     *
51
     * @var Filesystem
52
     */
53
    protected $filesystem;
54
55
    /**
56
     * @var array
57
     */
58
    protected static $lookup = [
59
        'regular' => RegularRoute::class,
60
        'controller' => ControllerRoute::class,
61
        'resource' => ControllerResourceRoute::class,
62
    ];
63
64
    /**
65
     * The name and signature of the console command.
66
     */
67
    protected $signature = 'make:route {link : The route link} {action? : View or controller to create} 
68
    {--t|type=regular : Type of route to create (regular,controller,resource)} {--m|method=get : HTTP method} 
69
    {--api : Route is an api route} {--a|createaction : Create view or controller after route}
70
    {--menu : Create also menu entry using make:menu command}';
71
72
    /**
73
     * The console command description.
74
     *
75
     * @var string
76
     */
77
    protected $description = 'Insert a route to routes/web.php file';
78
79
    /**
80
     * AdminLTERoute constructor.
81
     *
82
     * @param StubFileCompiler $compiler
83
     * @param Filesystem $filesystem
84
     */
85
    public function __construct(StubFileCompiler $compiler, Filesystem $filesystem)
86
    {
87
        parent::__construct();
88
        $this->compiler = $compiler;
89
        $this->filesystem = $filesystem;
90
    }
91
92
    /**
93
     * Execute the console command.
94
     */
95 View Code Duplication
    public function handle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
    {
97
        $this->processInput();
98
        $this->warnIfRouteAlreadyExists($link = $this->argument('link'));
99
        $tmpfile = $this->createTmpFileWithRoute();
100
        $path = $this->getPath($tmpfile);
101
        add_file_into_file($this->mountpoint(), $path, $dstFile = $this->destinationFile());
102
        $this->info('Route ' . $link . ' added to ' .  $dstFile . '.');
103
        $this->postActions();
104
    }
105
106
    /**
107
     * Get mountpoint.
108
     *
109
     * @return string
110
     */
111
    protected function mountpoint()
112
    {
113
        if ($this->option('api')) {
114
            return '#adminlte_api_routes';
115
        }
116
        return '#adminlte_routes';
117
    }
118
119
    /**
120
     * Destination route file.
121
     *
122
     * @return string
123
     */
124
    protected function destinationFile()
125
    {
126
        if ($this->option('api')) {
127
            return base_path($this->api_routes_path);
128
        }
129
        return base_path($this->web_routes_path);
130
    }
131
132
    /**
133
     * Warn if route already exists.
134
     *
135
     * @param $link
136
     */
137
    protected function warnIfRouteAlreadyExists($link)
138
    {
139
        if ($this->routeExists($link)) {
140
            if ($this->confirm('Route already exists. Do you wish to continue?')) {
141
                return;
142
            }
143
            die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method warnIfRouteAlreadyExists() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
144
        }
145
    }
146
147
    /**
148
     * Check if route exists.
149
     *
150
     * @param $link
151
     * @return mixed
152
     */
153
    protected function routeExists($link)
154
    {
155
        if ($this->option('api')) {
156
            return $this->apiRouteExists($link);
157
        }
158
        return $this->webRouteExists($link);
159
    }
160
161
    /**
162
     * Check if web route exists.
163
     *
164
     * @param $link
165
     * @return mixed
166
     */
167
    protected function webRouteExists($link)
168
    {
169
        $link = $this->removeTrailingSlashIfExists($link);
170
        $link = $this->removeDuplicatedTrailingSlashes($link);
171
        foreach (Route::getRoutes() as $value) {
172
            if (in_array(strtoupper($this->option('method')), array_merge($value->getMethods(), ['ANY'])) &&
173
                $value->getPath() === $link) {
174
                return true;
175
            }
176
        }
177
        return false;
178
    }
179
180
    /**
181
     * Remove (if exists) trailing slash from link.
182
     *
183
     * @param $link
184
     * @return string
185
     */
186
    protected function removeTrailingSlashIfExists($link)
187
    {
188
        if (starts_with($link, '/')) {
189
            return substr($link, 1);
190
        }
191
        return $link;
192
    }
193
194
    /**
195
     * Remove duplicated trailing slashes.
196
     *
197
     * @param $link
198
     * @return mixed
199
     */
200
    protected function removeDuplicatedTrailingSlashes($link)
201
    {
202
        return preg_replace('/(\/+)/', '/', $link);
203
    }
204
205
    /**
206
     * Check if api route exists.
207
     *
208
     * @param $link
209
     * @return mixed
210
     */
211
    protected function apiRouteExists($link)
212
    {
213
        return $this->webRouteExists('api/v1/' . $link);
214
    }
215
216
    /**
217
     * Crete tmp file with route to add.
218
     *
219
     * @return mixed
220
     */
221
    protected function createTmpFileWithRoute()
222
    {
223
        $temp = tmpfile();
224
        fwrite($temp, $this->getRouteCode());
225
        return $temp;
226
    }
227
228
    /**
229
     * Get path from file resource.
230
     *
231
     * @param $tmpfile
232
     * @return mixed
233
     */
234
    protected function getPath($tmpfile)
235
    {
236
        return stream_get_meta_data($tmpfile)['uri'];
237
    }
238
239
    /**
240
     * Get route code to insert depending on type.
241
     *
242
     * @return mixed
243
     */
244 View Code Duplication
    protected function getRouteCode()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
    {
246
        $type = $this->option('type');
247
        $class = isset(static::$lookup[$type])
248
            ? static::$lookup[$type]
249
            : RegularRoute::class;
250
        /** @var GeneratesCode $route */
251
        $route = new $class($this->compiler, $this->filesystem);
252
        $route->setReplacements([
253
            $this->argument('link'),
254
            $this->action(),
255
            $this->method()
256
        ]);
257
        return $route->code();
258
    }
259
260
    /**
261
     * Get method.
262
     *
263
     * @return string
264
     */
265 View Code Duplication
    protected function method()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
266
    {
267
        if (strtolower($this->option('method')) == 'head') {
268
            return 'get';
269
        }
270
        return strtolower($this->option('method'));
271
    }
272
273
    /**
274
     * Get the action replacement.
275
     *
276
     * @return array|string
277
     */
278
    protected function action()
279
    {
280
        if ($this->argument('action') != null) {
281
            return $this->argument('action');
282
        }
283
        if (strtolower($this->option('type')) != 'regular' ) return $this->argument('link') . 'Controller';
284
        return $this->argument('link');
285
    }
286
287
    /**
288
     * Process input.
289
     */
290
    protected function processInput()
291
    {
292
        $this->validateMethod();
293
        $this->validateType();
294
    }
295
296
    /**
297
     * Validate option method.
298
     */
299
    protected function validateMethod()
300
    {
301
        if (! in_array(strtoupper($this->option('method')), $methods = array_merge(Router::$verbs, ['ANY']))) {
302
            throw new MethodNotAllowedException($methods);
303
        }
304
    }
305
306
    /**
307
     * Validate option type.
308
     */
309
    protected function validateType()
310
    {
311
        if (! in_array(strtolower($this->option('type')), ['regular','controller','resource'])) {
312
            throw new RouteTypeNotValid();
313
        }
314
    }
315
316
    /**
317
     * Execute post actions (if exists)
318
     */
319
    protected function postActions()
320
    {
321
        if ($this->option('createaction') != null) {
322
            $this->createAction();
323
        }
324
        if ($this->option('menu') != null) {
325
            $this->createMenu();
326
        }
327
    }
328
329
    /**
330
     * Create menu.
331
     */
332
    protected function createMenu()
333
    {
334
        try {
335
            $this->warnIfSpatieMenuIsNotInstalled();
336
        } catch (\Exception $e) {
337
            //Skip installation of menu
338
            $this->error($e->getMessage());
339
            return;
340
        }
341
        Artisan::call('make:menu', [
342
            'link' => $link = $this->argument('link'),
343
            'name' => ucfirst($link),
344
        ]);
345
        $this->info('Menu entry ' . $link .' added to config/menu.php file.');
346
    }
347
348
    protected function warnIfSpatieMenuIsNotInstalled()
349
    {
350
        if (!(app()->getProvider('Spatie\Menu\Laravel\MenuServiceProvider'))) {
351
            throw new SpatieMenuDoesNotExists();
352
        }
353
    }
354
355
    /**
356
     * Create action (view|controller).
357
     */
358
    protected function createAction()
359
    {
360
        if (strtolower($this->option('type')) == 'regular' || $this->option('type') == null) {
361
            return $this->createView();
362
        }
363
        if (strtolower($this->option('type')) == 'controller') {
364
            return $this->createController();
365
        }
366
        return $this->createResourceController();
367
    }
368
369
    /**
370
     * Create View.
371
     *
372
     * @param null $name
373
     */
374
    protected function createView($name = null)
375
    {
376
        if ($name == null) $name = $this->action();
377
        Artisan::call('make:view', [
378
            'name' => $name
379
        ]);
380
        $this->info('View ' . $name .'.blade.php created.');
381
    }
382
383
    /**
384
     * Create regular controller.
385
     */
386
    protected function createController()
387
    {
388
        Artisan::call('make:controller', [
389
            'name' => $controller = $this->controllerWithoutMethod($this->action())
390
        ]);
391
        $this->addMethodToController($controller, $this->controllerMethod($this->action()));
392
        $this->info('Controller ' . $controller .' created.');
393
        $this->createView($this->argument('link'));
394
    }
395
396
    /**
397
     * Create resource controller.
398
     */
399
    protected function createResourceController()
400
    {
401
        Artisan::call('make:controller', [
402
            'name' => $controller = $this->controllerWithoutMethod($this->action()),
403
            '--resource' => true
404
        ]);
405
        $this->info('Resource Controller ' . $controller .' created.');
406
        $this->createView($this->argument('link'));
407
    }
408
409
    /**
410
     * Add method to controller.
411
     *
412
     * @param $controller
413
     * @param $controllerMethod     *
414
     */
415
    protected function addMethodToController($controller, $controllerMethod)
416
    {
417
        $tmpfile = $this->createTmpFileWithMethod($controllerMethod);
418
        $path = $this->getPath($tmpfile);
419
        add_file_into_file('\/\/', $path, app_path('Http/Controllers/' . $controller . '.php'));
420
    }
421
422
    /**
423
     * Crete tmp file with route to add.
424
     *
425
     * @param $controllerMethod
426
     * @return mixed
427
     */
428
    protected function createTmpFileWithMethod($controllerMethod)
429
    {
430
        $temp = tmpfile();
431
        fwrite($temp, $this->getMethodCode($controllerMethod));
432
        return $temp;
433
    }
434
435
    /**
436
     * Get method code.
437
     *
438
     * @param $controllerMethod
439
     * @return mixed
440
     */
441
    protected function getMethodCode($controllerMethod)
442
    {
443
        return $this->compiler->compile(
444
            $this->filesystem->get($this->getMethodStubPath()),
445
            [
446
                'METHOD' => $controllerMethod,
447
                'VIEW' => $this->argument('link')
448
            ]
449
        );
450
    }
451
452
    /**
453
     * Get method stub path.
454
     *
455
     * @return string
456
     */
457
    protected function getMethodStubPath()
458
    {
459
        return __DIR__ . '/stubs/method.stub';
460
    }
461
462
}
463