Completed
Push — master ( f9866e...fa91dc )
by Song
02:51
created

src/Console/ExtendCommand.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Encore\Admin\Console;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Filesystem\Filesystem;
7
8
class ExtendCommand extends Command
9
{
10
    /**
11
     * The console command name.
12
     *
13
     * @var string
14
     */
15
    protected $signature = 'admin:extend {extension} {--namespace=}';
16
17
    /**
18
     * The console command description.
19
     *
20
     * @var string
21
     */
22
    protected $description = 'Build a Laravel-admin extension';
23
24
    /**
25
     * @var string
26
     */
27
    protected $basePath = '';
28
29
    /**
30
     * @var Filesystem
31
     */
32
    protected $filesystem;
33
34
    /**
35
     * @var string
36
     */
37
    protected $namespace;
38
39
    /**
40
     * @var string
41
     */
42
    protected $className;
43
44
    /**
45
     * @var string
46
     */
47
    protected $package;
48
49
    /**
50
     * @var string
51
     */
52
    protected $extensionDir;
53
54
    /**
55
     * @var array
56
     */
57
    protected $dirs = [
58
        'database/migrations',
59
        'database/seeds',
60
        'resources/assets',
61
        'resources/views',
62
        'src/Http/Controllers',
63
        'routes',
64
    ];
65
66
    /**
67
     * Execute the console command.
68
     *
69
     * @return void
70
     */
71
    public function handle(Filesystem $filesystem)
72
    {
73
        $this->filesystem = $filesystem;
74
75
        $this->extensionDir = config('admin.extension_dir');
76
77
        InputExtensionDir:
78
        if (empty($this->extensionDir)) {
79
            $this->extensionDir = $this->ask('Please input a directory to store your extension:');
80
        }
81
82
        if (!file_exists($this->extensionDir)) {
83
            $this->makeDir();
84
        }
85
86
        $this->package = $this->argument('extension');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->argument('extension') can also be of type array. However, the property $package is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
87
88
        InputExtensionName:
89
        if (!$this->validateExtensionName($this->package)) {
90
            $this->package = $this->ask("[$this->package] is not a valid package name, please input a name like (<vendor>/<name>)");
91
            goto InputExtensionName;
92
        }
93
94
        $this->makeDirs();
95
        $this->makeFiles();
96
97
        $this->info("The extension scaffolding generated successfully. \r\n");
98
        $this->showTree();
99
    }
100
101
    /**
102
     * Show extension scaffolding with tree structure.
103
     */
104
    protected function showTree()
105
    {
106
        $tree = <<<TREE
107
{$this->extensionPath()}
108
    ├── LICENSE
109
    ├── README.md
110
    ├── composer.json
111
    ├── database
112
    │   ├── migrations
113
    │   └── seeds
114
    ├── resources
115
    │   ├── assets
116
    │   └── views
117
    │       └── index.blade.php
118
    ├── routes
119
    │   └── web.php
120
    └── src
121
        ├── {$this->className}.php
122
        ├── {$this->className}ServiceProvider.php
123
        └── Http
124
            └── Controllers
125
                └── {$this->className}Controller.php
126
TREE;
127
128
        $this->info($tree);
129
    }
130
131
    /**
132
     * Make extension files.
133
     */
134
    protected function makeFiles()
135
    {
136
        $this->namespace = $this->getRootNameSpace();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getRootNameSpace() can also be of type array. However, the property $namespace is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
137
138
        $this->className = $this->getClassName();
139
140
        // copy files
141
        $this->copy([
142
            __DIR__.'/stubs/extension/view.stub'       => 'resources/views/index.blade.php',
143
            __DIR__.'/stubs/extension/.gitignore.stub' => '.gitignore',
144
            __DIR__.'/stubs/extension/README.md.stub'  => 'README.md',
145
            __DIR__.'/stubs/extension/LICENSE.stub'    => 'LICENSE',
146
        ]);
147
148
        // make composer.json
149
        $composerContents = str_replace(
150
            [':package', ':namespace', ':class_name'],
151
            [$this->package, str_replace('\\', '\\\\', $this->namespace).'\\\\', $this->className],
152
            file_get_contents(__DIR__.'/stubs/extension/composer.json.stub')
153
        );
154
        $this->putFile('composer.json', $composerContents);
155
156
        // make class
157
        $classContents = str_replace(
158
            [':namespace', ':class_name', ':title', ':path', ':base_package'],
159
            [$this->namespace, $this->className, title_case($this->className), basename($this->package), basename($this->package)],
160
            file_get_contents(__DIR__.'/stubs/extension/extension.stub')
161
        );
162
        $this->putFile("src/{$this->className}.php", $classContents);
163
164
        // make service provider
165
        $providerContents = str_replace(
166
            [':namespace', ':class_name', ':base_package', ':package'],
167
            [$this->namespace, $this->className, basename($this->package), $this->package],
168
            file_get_contents(__DIR__.'/stubs/extension/service-provider.stub')
169
        );
170
        $this->putFile("src/{$this->className}ServiceProvider.php", $providerContents);
171
172
        // make controller
173
        $controllerContent = str_replace(
174
            [':namespace', ':class_name', ':base_package'],
175
            [$this->namespace, $this->className, basename($this->package)],
176
            file_get_contents(__DIR__.'/stubs/extension/controller.stub')
177
        );
178
        $this->putFile("src/Http/Controllers/{$this->className}Controller.php", $controllerContent);
179
180
        // make routes
181
        $routesContent = str_replace(
182
            [':namespace', ':class_name', ':path'],
183
            [$this->namespace, $this->className, basename($this->package)],
184
            file_get_contents(__DIR__.'/stubs/extension/routes.stub')
185
        );
186
        $this->putFile('routes/web.php', $routesContent);
187
    }
188
189
    /**
190
     * Get root namespace for this package.
191
     *
192
     * @return array|null|string
193
     */
194
    protected function getRootNameSpace()
195
    {
196
        if (!$namespace = $this->option('namespace')) {
197
            list($vendor, $name) = explode('/', $this->package);
198
199
            $default = str_replace(['-', '-'], '', title_case($vendor).'\\'.title_case($name));
200
201
            $namespace = $this->ask('Root namespace', $default);
202
        }
203
204
        return $namespace;
205
    }
206
207
    /**
208
     * Get extension class name.
209
     *
210
     * @return string
211
     */
212
    protected function getClassName()
213
    {
214
        return class_basename($this->namespace);
215
    }
216
217
    /**
218
     * Create package dirs.
219
     */
220
    protected function makeDirs()
221
    {
222
        $this->basePath = rtrim($this->extensionDir, '/').'/'.ltrim($this->package, '/');
223
224
        $this->makeDir($this->dirs);
225
    }
226
227
    /**
228
     * Validate extension name.
229
     *
230
     * @param string $name
231
     *
232
     * @return int
233
     */
234
    protected function validateExtensionName($name)
235
    {
236
        return preg_match('/^[\w\-_]+\/[\w\-_]+$/', $name);
237
    }
238
239
    /**
240
     * Extension path.
241
     *
242
     * @param string $path
243
     *
244
     * @return string
245
     */
246
    protected function extensionPath($path = '')
247
    {
248
        $path = rtrim($path, '/');
249
250
        if (empty($path)) {
251
            return rtrim($this->basePath, '/');
252
        }
253
254
        return rtrim($this->basePath, '/').'/'.ltrim($path, '/');
255
    }
256
257
    /**
258
     * Put contents to file.
259
     *
260
     * @param string $to
261
     * @param string $content
262
     */
263
    protected function putFile($to, $content)
264
    {
265
        $to = $this->extensionPath($to);
266
267
        $this->filesystem->put($to, $content);
268
    }
269
270
    /**
271
     * Copy files to extension path.
272
     *
273
     * @param string|array $from
274
     * @param string|null  $to
275
     */
276
    protected function copy($from, $to = null)
277
    {
278
        if (is_array($from) && is_null($to)) {
279
            foreach ($from as $key => $value) {
280
                $this->copy($key, $value);
281
            }
282
283
            return;
284
        }
285
286
        if (!file_exists($from)) {
287
            return;
288
        }
289
290
        $to = $this->extensionPath($to);
291
292
        $this->filesystem->copy($from, $to);
293
    }
294
295
    /**
296
     * Make new directory.
297
     *
298
     * @param array|string $paths
299
     */
300
    protected function makeDir($paths = '')
301
    {
302
        foreach ((array) $paths as $path) {
303
            $path = $this->extensionPath($path);
304
305
            $this->filesystem->makeDirectory($path, 0755, true, true);
306
        }
307
    }
308
}
309