Completed
Push — master ( ce62e6...a2dd34 )
by Song
03:32
created

GenerateCommand::generate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 0
dl 0
loc 33
rs 9.392
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Console;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Str;
8
9
class GenerateCommand extends Command
10
{
11
    /**
12
     * The console command name.
13
     *
14
     * @var string
15
     */
16
    protected $signature = 'admin:generate {name} {--model=} {--O|output}';
17
18
    /**
19
     * The console command description.
20
     *
21
     * @var string
22
     */
23
    protected $description = 'laravel-admin code generator';
24
25
    /**
26
     * @var ResourceGenerator
27
     */
28
    protected $generator;
29
30
    /**
31
     * The filesystem instance.
32
     *
33
     * @var \Illuminate\Filesystem\Filesystem
34
     */
35
    protected $files;
36
37
    /**
38
     * Create a new controller creator command instance.
39
     *
40
     * @param  \Illuminate\Filesystem\Filesystem  $files
41
     */
42
    public function __construct(Filesystem $files)
43
    {
44
        parent::__construct();
45
46
        $this->files = $files;
47
    }
48
49
    /**
50
     * Execute the console command.
51
     *
52
     * @return void
53
     */
54
    public function handle()
55
    {
56
        $modelName = $this->option('model');
57
58
        $this->generator = new ResourceGenerator($modelName);
59
60
        if ($this->option('output')) {
61
            return $this->output($modelName);
0 ignored issues
show
Bug introduced by
It seems like $modelName defined by $this->option('model') on line 56 can also be of type array or null; however, Encore\Admin\Console\GenerateCommand::output() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
62
        }
63
64
        $this->generate();
65
    }
66
67
    /**
68
     * @param string $modelName
69
     */
70
    protected function output($modelName)
71
    {
72
        $this->alert("laravel-admin resource code for model [{$modelName}]");
73
74
        $this->info($this->generator->generateGrid());
75
        $this->info($this->generator->generateShow());
76
        $this->info($this->generator->generateForm());
77
    }
78
79
    /**
80
     * @return bool
81
     */
82
    protected function generate()
83
    {
84
        $controllerName = $this->qualifyClass($this->getControllerName());
85
        $controllerPath = $this->getPath($controllerName);
86
87
        if ($this->alreadyExists($this->getControllerName())) {
88
            $this->error($controllerName.' already exists!');
89
90
            return false;
91
        }
92
93
        $resourceName = $this->qualifyClass($this->getResourceName(), 'Resources');
94
        $resourcePath = $this->getPath($resourceName);
95
96
        if ($this->alreadyExists($this->getControllerName())) {
97
            $this->error($resourceName.' already exists!');
98
99
            return false;
100
        }
101
102
        $this->makeDirectory($controllerPath);
103
        $this->makeDirectory($resourcePath);
104
105
        $this->files->put($controllerPath, $this->buildControllerClass($controllerName, $resourceName));
106
        $this->info($controllerName.' created successfully.');
107
108
        $this->files->put($resourcePath, $this->buildResourceClass($resourceName));
109
        $this->info($resourceName.' created successfully.');
110
111
        $this->info(' Add a route in app/Admin/routes.php');
112
113
        $this->info(sprintf("\$router->resource('%s', %s::class);", $this->argument('name'), class_basename($controllerName)));
114
    }
115
116
    /**
117
     * @param string $name
118
     * @param string $resource
119
     * @return mixed
120
     */
121
    protected function buildControllerClass($name, $resource)
122
    {
123
        $stub = __DIR__.'/stubs/controller.resource.stub';
124
125
        $stub = file_get_contents($stub);
126
127
        $code = str_replace(
128
            ['DummyNamespace', 'DummyResourceNamespace', 'DummyClass', 'DummyResource'],
129
            [$this->getNamespace($name), $resource, class_basename($name), class_basename($resource)],
130
            $stub
131
        );
132
133
        return $code;
134
    }
135
136
    /**
137
     * @param string $name
138
     * @return mixed
139
     */
140
    protected function buildResourceClass($name)
141
    {
142
        $stub = __DIR__.'/stubs/resource.stub';
143
144
        $stub = file_get_contents($stub);
145
146
        $code = str_replace(
147
            ['DummyNamespace', 'DummyModelNamespace', 'DummyClass', 'DummyModel'],
148
            [$this->getNamespace($name), $this->option('model'), class_basename($name), class_basename($this->option('model'))],
0 ignored issues
show
Bug introduced by
It seems like $this->option('model') targeting Illuminate\Console\Command::option() can also be of type array or null; however, class_basename() does only seem to accept string|object, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
149
            $stub
150
        );
151
152
        $code = str_replace(
153
            ['DummyGrid', 'DummyShow', 'DummyForm'],
154
            [
155
                $this->indentCodes($this->generator->generateGrid()),
156
                $this->indentCodes($this->generator->generateShow()),
157
                $this->indentCodes($this->generator->generateForm())
158
            ],
159
            $code
160
        );
161
162
        return $code;
163
    }
164
165
    /**
166
     * @param string $code
167
     * @return string
168
     */
169
    protected function indentCodes($code)
170
    {
171
        $indent = str_repeat(' ',  8);
172
173
        return $indent. preg_replace("/\r\n/", "\r\n{$indent}", $code);
174
    }
175
176
    /**
177
     * Get the default namespace for the class.
178
     *
179
     * @param string $rootNamespace
180
     * @param string $dir
181
     *
182
     * @return string
183
     */
184
    protected function getDefaultNamespace($rootNamespace, $dir = 'Controllers')
185
    {
186
        $directory = config('admin.directory');
187
188
        $namespace = ucfirst(basename($directory));
189
190
        return $rootNamespace."\\$namespace\\$dir";
191
    }
192
193
    /**
194
     * Parse the class name and format according to the root namespace.
195
     *
196
     * @param  string  $name
197
     * @param  string  $dir
198
     *
199
     * @return string
200
     */
201
    protected function qualifyClass($name, $dir = 'Controllers')
202
    {
203
        $name = ltrim($name, '\\/');
204
205
        $rootNamespace = $this->rootNamespace();
206
207
        if (Str::startsWith($name, $rootNamespace)) {
208
            return $name;
209
        }
210
211
        $name = str_replace('/', '\\', $name);
212
213
        return $this->qualifyClass(
214
            $this->getDefaultNamespace(trim($rootNamespace, '\\'), $dir).'\\'.$name,
215
            $dir
216
        );
217
    }
218
219
    /**
220
     * Determine if the class already exists.
221
     *
222
     * @param  string  $rawName
223
     * @return bool
224
     */
225
    protected function alreadyExists($rawName)
226
    {
227
        return $this->files->exists($this->getPath($this->qualifyClass($rawName)));
228
    }
229
230
    /**
231
     * Get the destination class path.
232
     *
233
     * @param  string  $name
234
     * @return string
235
     */
236
    protected function getPath($name)
237
    {
238
        $name = Str::replaceFirst($this->rootNamespace(), '', $name);
239
240
        return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php';
241
    }
242
243
    /**
244
     * Build the directory for the class if necessary.
245
     *
246
     * @param  string  $path
247
     * @return string
248
     */
249
    protected function makeDirectory($path)
250
    {
251
        if (! $this->files->isDirectory(dirname($path))) {
252
            $this->files->makeDirectory(dirname($path), 0777, true, true);
253
        }
254
255
        return $path;
256
    }
257
258
    /**
259
     * Get the full namespace for a given class, without the class name.
260
     *
261
     * @param  string  $name
262
     * @return string
263
     */
264
    protected function getNamespace($name)
265
    {
266
        return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
267
    }
268
269
    /**
270
     * @return string
271
     */
272
    protected function getResourceName()
273
    {
274
        return ucfirst(trim($this->argument('name'))).'Resource';
275
    }
276
277
    /**
278
     * @return string
279
     */
280
    protected function getControllerName()
281
    {
282
        return ucfirst(trim($this->argument('name'))).'Controller';
283
    }
284
285
    /**
286
     * Get the root namespace for the class.
287
     *
288
     * @return string
289
     */
290
    protected function rootNamespace()
291
    {
292
        return $this->laravel->getNamespace();
293
    }
294
}
295