ModuleMakeCommand   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 3
dl 0
loc 173
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A handle() 0 24 2
A makeDirectory() 0 8 2
A generateSamples() 0 19 1
A processStubs() 0 29 2
A getNameInput() 0 10 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cortex\Foundation\Console\Commands;
6
7
use Illuminate\Console\Command;
8
use Illuminate\Filesystem\Filesystem;
9
use Illuminate\Console\ConfirmableTrait;
10
11
class ModuleMakeCommand extends Command
12
{
13
    use ConfirmableTrait;
14
15
    /**
16
     * The filesystem instance.
17
     *
18
     * @var \Illuminate\Filesystem\Filesystem
19
     */
20
    protected $files;
21
22
    /**
23
     * The console command signature.
24
     *
25
     * @var string
26
     */
27
    protected $signature = 'make:module {name : The name of the module.}';
28
29
    /**
30
     * The console command description.
31
     *
32
     * @var string
33
     */
34
    protected $description = 'Create a new module structure';
35
36
    /**
37
     * The type of class being generated.
38
     *
39
     * @var string
40
     */
41
    protected $type = 'Module';
42
43
    /**
44
     * Create a new controller creator command instance.
45
     *
46
     * @param \Illuminate\Filesystem\Filesystem $files
47
     *
48
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
49
     */
50
    public function __construct(Filesystem $files)
51
    {
52
        parent::__construct();
53
54
        $this->files = $files;
55
    }
56
57
    /**
58
     * Execute the console command.
59
     *
60
     * @return void
61
     */
62
    public function handle(): void
63
    {
64
        $name = $this->getNameInput();
65
66
        $path = app_path($name);
67
68
        // First we will check to see if the class already exists. If it does, we don't want
69
        // to create the class and overwrite the user's code. So, we will bail out so the
70
        // code is untouched. Otherwise, we will continue generating this class' files.
71
        if ($this->files->exists($path)) {
72
            $this->error($this->type.' already exists!');
73
74
            return;
75
        }
76
77
        // Next, we will generate the path to the location where this class' file should get
78
        // written. Then, we will build the class and make the proper replacements on the
79
        // stub files so that it gets the correctly formatted namespace and class name.
80
        $stubs = __DIR__.'/../../../resources/stubs/module';
81
        $this->processStubs($stubs, $path);
82
        $this->generateSamples();
83
84
        $this->info($this->type.' created successfully.');
85
    }
86
87
    /**
88
     * Build the directory for the class if necessary.
89
     *
90
     * @param string $path
91
     *
92
     * @return string
93
     */
94
    protected function makeDirectory($path): string
95
    {
96
        if (! $this->files->isDirectory($path)) {
97
            $this->files->makeDirectory($path, 0777, true, true);
98
        }
99
100
        return $path;
101
    }
102
103
    /**
104
     * Generate code samples.
105
     *
106
     * @return void
107
     */
108
    protected function generateSamples(): void
109
    {
110
        $module = str_after($this->getNameInput(), '/');
0 ignored issues
show
Deprecated Code introduced by
The function str_after() has been deprecated with message: Str::after() should be used directly instead. Will be removed in Laravel 6.0.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
111
112
        $this->call('make:config', ['name' => 'config', '--module' => $this->getNameInput()]);
113
        $this->call('make:model', ['name' => 'Example', '--module' => $this->getNameInput()]);
114
        $this->call('make:policy', ['name' => 'ExamplePolicy', '--module' => $this->getNameInput()]);
115
        $this->call('make:provider', ['name' => ucfirst($module).'ServiceProvider', '--module' => $this->getNameInput()]);
116
        $this->call('make:command', ['name' => 'ExampleCommand', '--module' => $this->getNameInput()]);
117
        $this->call('make:controller', ['name' => 'ExampleController', '--module' => $this->getNameInput()]);
118
        $this->call('make:request', ['name' => 'ExampleRequest', '--module' => $this->getNameInput()]);
119
        $this->call('make:middleware', ['name' => 'ExampleMiddleware', '--module' => $this->getNameInput()]);
120
        $this->call('make:transformer', ['name' => 'ExampleTransformer', '--model' => 'Example', '--module' => $this->getNameInput()]);
121
        $this->call('make:datatable', ['name' => 'ExampleDatatable', '--model' => 'Example', '--transformer' => 'ExampleTransformer', '--module' => $this->getNameInput()]);
122
123
        $this->warn('Optionally create migrations and seeds (it may take some time):');
124
        $this->warn("artisan make:migration create_{$module}_example_table --module {$this->getNameInput()}");
125
        $this->warn("artisan make:seeder ExampleSeeder --module {$this->getNameInput()}");
126
    }
127
128
    /**
129
     * Process stubs placeholders.
130
     *
131
     * @param string $stubs
132
     * @param string $path
133
     *
134
     * @return void
135
     */
136
    protected function processStubs($stubs, $path): void
137
    {
138
        $this->makeDirectory($path);
139
        $this->files->copyDirectory($stubs, $path);
140
141
        $files = [
142
            ($phpunit = $path.DIRECTORY_SEPARATOR.'phpunit.xml.dist') => $this->files->get($phpunit),
143
            ($composer = $path.DIRECTORY_SEPARATOR.'composer.json') => $this->files->get($composer),
144
            ($changelog = $path.DIRECTORY_SEPARATOR.'CHANGELOG.md') => $this->files->get($changelog),
145
            ($readme = $path.DIRECTORY_SEPARATOR.'README.md') => $this->files->get($readme),
146
        ];
147
148
        $module = ucfirst(str_after($this->getNameInput(), '/'));
0 ignored issues
show
Deprecated Code introduced by
The function str_after() has been deprecated with message: Str::after() should be used directly instead. Will be removed in Laravel 6.0.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
149
        $name = implode(' ', array_map('ucfirst', explode('/', $this->getNameInput())));
150
        $jsonNamespace = implode('\\\\', array_map('ucfirst', explode('/', $this->getNameInput())));
151
152
        foreach ($files as $key => &$file) {
153
            $file = str_replace('DummyModuleName', $name, $file);
154
            $file = str_replace('Dummy\\\\Module', $jsonNamespace, $file);
155
            $file = str_replace('DummyModuleServiceProvider', $jsonNamespace."\\\\Providers\\\\{$module}ServiceProvider", $file);
156
157
            $file = str_replace('dummy/module', $this->getNameInput(), $file);
158
            $file = str_replace('dummy-module', str_replace('/', '-', $this->getNameInput()), $file);
159
            $file = str_replace('dummy:module', str_replace('/', ':', $this->getNameInput()), $file);
160
            $file = str_replace('dummy.module', str_replace('/', '.', $this->getNameInput()), $file);
161
162
            $this->files->put($key, $file);
163
        }
164
    }
165
166
    /**
167
     * Get the desired class name from the input.
168
     *
169
     * @throws \Exception
170
     *
171
     * @return string
172
     */
173
    protected function getNameInput(): string
174
    {
175
        $name = trim($this->argument('name'));
176
177
        if (mb_strpos($name, '/') === false) {
178
            throw new \Exception('Module name must consist of two segments: vendor/module');
179
        }
180
181
        return $name;
182
    }
183
}
184