Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 399 | Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Console;
4
 
5
use Illuminate\Console\Concerns\CreatesMatchingTest;
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Str;
8
use Symfony\Component\Console\Input\InputArgument;
9
 
10
abstract class GeneratorCommand extends Command
11
{
12
    /**
13
     * The filesystem instance.
14
     *
15
     * @var \Illuminate\Filesystem\Filesystem
16
     */
17
    protected $files;
18
 
19
    /**
20
     * The type of class being generated.
21
     *
22
     * @var string
23
     */
24
    protected $type;
25
 
26
    /**
27
     * Reserved names that cannot be used for generation.
28
     *
29
     * @var string[]
30
     */
31
    protected $reservedNames = [
32
        '__halt_compiler',
33
        'abstract',
34
        'and',
35
        'array',
36
        'as',
37
        'break',
38
        'callable',
39
        'case',
40
        'catch',
41
        'class',
42
        'clone',
43
        'const',
44
        'continue',
45
        'declare',
46
        'default',
47
        'die',
48
        'do',
49
        'echo',
50
        'else',
51
        'elseif',
52
        'empty',
53
        'enddeclare',
54
        'endfor',
55
        'endforeach',
56
        'endif',
57
        'endswitch',
58
        'endwhile',
59
        'enum',
60
        'eval',
61
        'exit',
62
        'extends',
63
        'false',
64
        'final',
65
        'finally',
66
        'fn',
67
        'for',
68
        'foreach',
69
        'function',
70
        'global',
71
        'goto',
72
        'if',
73
        'implements',
74
        'include',
75
        'include_once',
76
        'instanceof',
77
        'insteadof',
78
        'interface',
79
        'isset',
80
        'list',
81
        'match',
82
        'namespace',
83
        'new',
84
        'or',
85
        'print',
86
        'private',
87
        'protected',
88
        'public',
89
        'readonly',
90
        'require',
91
        'require_once',
92
        'return',
93
        'static',
94
        'switch',
95
        'throw',
96
        'trait',
97
        'true',
98
        'try',
99
        'unset',
100
        'use',
101
        'var',
102
        'while',
103
        'xor',
104
        'yield',
105
        '__CLASS__',
106
        '__DIR__',
107
        '__FILE__',
108
        '__FUNCTION__',
109
        '__LINE__',
110
        '__METHOD__',
111
        '__NAMESPACE__',
112
        '__TRAIT__',
113
    ];
114
 
115
    /**
116
     * Create a new controller creator command instance.
117
     *
118
     * @param  \Illuminate\Filesystem\Filesystem  $files
119
     * @return void
120
     */
121
    public function __construct(Filesystem $files)
122
    {
123
        parent::__construct();
124
 
125
        if (in_array(CreatesMatchingTest::class, class_uses_recursive($this))) {
126
            $this->addTestOptions();
127
        }
128
 
129
        $this->files = $files;
130
    }
131
 
132
    /**
133
     * Get the stub file for the generator.
134
     *
135
     * @return string
136
     */
137
    abstract protected function getStub();
138
 
139
    /**
140
     * Execute the console command.
141
     *
142
     * @return bool|null
143
     *
144
     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
145
     */
146
    public function handle()
147
    {
148
        // First we need to ensure that the given name is not a reserved word within the PHP
149
        // language and that the class name will actually be valid. If it is not valid we
150
        // can error now and prevent from polluting the filesystem using invalid files.
151
        if ($this->isReservedName($this->getNameInput())) {
152
            $this->components->error('The name "'.$this->getNameInput().'" is reserved by PHP.');
153
 
154
            return false;
155
        }
156
 
157
        $name = $this->qualifyClass($this->getNameInput());
158
 
159
        $path = $this->getPath($name);
160
 
161
        // Next, We will check to see if the class already exists. If it does, we don't want
162
        // to create the class and overwrite the user's code. So, we will bail out so the
163
        // code is untouched. Otherwise, we will continue generating this class' files.
164
        if ((! $this->hasOption('force') ||
165
             ! $this->option('force')) &&
166
             $this->alreadyExists($this->getNameInput())) {
167
            $this->components->error($this->type.' already exists.');
168
 
169
            return false;
170
        }
171
 
172
        // Next, we will generate the path to the location where this class' file should get
173
        // written. Then, we will build the class and make the proper replacements on the
174
        // stub files so that it gets the correctly formatted namespace and class name.
175
        $this->makeDirectory($path);
176
 
177
        $this->files->put($path, $this->sortImports($this->buildClass($name)));
178
 
179
        $info = $this->type;
180
 
181
        if (in_array(CreatesMatchingTest::class, class_uses_recursive($this))) {
182
            if ($this->handleTestCreation($path)) {
183
                $info .= ' and test';
184
            }
185
        }
186
 
187
        $this->components->info(sprintf('%s [%s] created successfully.', $info, $path));
188
    }
189
 
190
    /**
191
     * Parse the class name and format according to the root namespace.
192
     *
193
     * @param  string  $name
194
     * @return string
195
     */
196
    protected function qualifyClass($name)
197
    {
198
        $name = ltrim($name, '\\/');
199
 
200
        $name = str_replace('/', '\\', $name);
201
 
202
        $rootNamespace = $this->rootNamespace();
203
 
204
        if (Str::startsWith($name, $rootNamespace)) {
205
            return $name;
206
        }
207
 
208
        return $this->qualifyClass(
209
            $this->getDefaultNamespace(trim($rootNamespace, '\\')).'\\'.$name
210
        );
211
    }
212
 
213
    /**
214
     * Qualify the given model class base name.
215
     *
216
     * @param  string  $model
217
     * @return string
218
     */
219
    protected function qualifyModel(string $model)
220
    {
221
        $model = ltrim($model, '\\/');
222
 
223
        $model = str_replace('/', '\\', $model);
224
 
225
        $rootNamespace = $this->rootNamespace();
226
 
227
        if (Str::startsWith($model, $rootNamespace)) {
228
            return $model;
229
        }
230
 
231
        return is_dir(app_path('Models'))
232
                    ? $rootNamespace.'Models\\'.$model
233
                    : $rootNamespace.$model;
234
    }
235
 
236
    /**
237
     * Get the default namespace for the class.
238
     *
239
     * @param  string  $rootNamespace
240
     * @return string
241
     */
242
    protected function getDefaultNamespace($rootNamespace)
243
    {
244
        return $rootNamespace;
245
    }
246
 
247
    /**
248
     * Determine if the class already exists.
249
     *
250
     * @param  string  $rawName
251
     * @return bool
252
     */
253
    protected function alreadyExists($rawName)
254
    {
255
        return $this->files->exists($this->getPath($this->qualifyClass($rawName)));
256
    }
257
 
258
    /**
259
     * Get the destination class path.
260
     *
261
     * @param  string  $name
262
     * @return string
263
     */
264
    protected function getPath($name)
265
    {
266
        $name = Str::replaceFirst($this->rootNamespace(), '', $name);
267
 
268
        return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php';
269
    }
270
 
271
    /**
272
     * Build the directory for the class if necessary.
273
     *
274
     * @param  string  $path
275
     * @return string
276
     */
277
    protected function makeDirectory($path)
278
    {
279
        if (! $this->files->isDirectory(dirname($path))) {
280
            $this->files->makeDirectory(dirname($path), 0777, true, true);
281
        }
282
 
283
        return $path;
284
    }
285
 
286
    /**
287
     * Build the class with the given name.
288
     *
289
     * @param  string  $name
290
     * @return string
291
     *
292
     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
293
     */
294
    protected function buildClass($name)
295
    {
296
        $stub = $this->files->get($this->getStub());
297
 
298
        return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name);
299
    }
300
 
301
    /**
302
     * Replace the namespace for the given stub.
303
     *
304
     * @param  string  $stub
305
     * @param  string  $name
306
     * @return $this
307
     */
308
    protected function replaceNamespace(&$stub, $name)
309
    {
310
        $searches = [
311
            ['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'],
312
            ['{{ namespace }}', '{{ rootNamespace }}', '{{ namespacedUserModel }}'],
313
            ['{{namespace}}', '{{rootNamespace}}', '{{namespacedUserModel}}'],
314
        ];
315
 
316
        foreach ($searches as $search) {
317
            $stub = str_replace(
318
                $search,
319
                [$this->getNamespace($name), $this->rootNamespace(), $this->userProviderModel()],
320
                $stub
321
            );
322
        }
323
 
324
        return $this;
325
    }
326
 
327
    /**
328
     * Get the full namespace for a given class, without the class name.
329
     *
330
     * @param  string  $name
331
     * @return string
332
     */
333
    protected function getNamespace($name)
334
    {
335
        return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
336
    }
337
 
338
    /**
339
     * Replace the class name for the given stub.
340
     *
341
     * @param  string  $stub
342
     * @param  string  $name
343
     * @return string
344
     */
345
    protected function replaceClass($stub, $name)
346
    {
347
        $class = str_replace($this->getNamespace($name).'\\', '', $name);
348
 
349
        return str_replace(['DummyClass', '{{ class }}', '{{class}}'], $class, $stub);
350
    }
351
 
352
    /**
353
     * Alphabetically sorts the imports for the given stub.
354
     *
355
     * @param  string  $stub
356
     * @return string
357
     */
358
    protected function sortImports($stub)
359
    {
360
        if (preg_match('/(?P<imports>(?:^use [^;{]+;$\n?)+)/m', $stub, $match)) {
361
            $imports = explode("\n", trim($match['imports']));
362
 
363
            sort($imports);
364
 
365
            return str_replace(trim($match['imports']), implode("\n", $imports), $stub);
366
        }
367
 
368
        return $stub;
369
    }
370
 
371
    /**
372
     * Get the desired class name from the input.
373
     *
374
     * @return string
375
     */
376
    protected function getNameInput()
377
    {
378
        return trim($this->argument('name'));
379
    }
380
 
381
    /**
382
     * Get the root namespace for the class.
383
     *
384
     * @return string
385
     */
386
    protected function rootNamespace()
387
    {
388
        return $this->laravel->getNamespace();
389
    }
390
 
391
    /**
392
     * Get the model for the default guard's user provider.
393
     *
394
     * @return string|null
395
     */
396
    protected function userProviderModel()
397
    {
398
        $config = $this->laravel['config'];
399
 
400
        $provider = $config->get('auth.guards.'.$config->get('auth.defaults.guard').'.provider');
401
 
402
        return $config->get("auth.providers.{$provider}.model");
403
    }
404
 
405
    /**
406
     * Checks whether the given name is reserved.
407
     *
408
     * @param  string  $name
409
     * @return bool
410
     */
411
    protected function isReservedName($name)
412
    {
413
        $name = strtolower($name);
414
 
415
        return in_array($name, $this->reservedNames);
416
    }
417
 
418
    /**
419
     * Get the first view directory path from the application configuration.
420
     *
421
     * @param  string  $path
422
     * @return string
423
     */
424
    protected function viewPath($path = '')
425
    {
426
        $views = $this->laravel['config']['view.paths'][0] ?? resource_path('views');
427
 
428
        return $views.($path ? DIRECTORY_SEPARATOR.$path : $path);
429
    }
430
 
431
    /**
432
     * Get the console command arguments.
433
     *
434
     * @return array
435
     */
436
    protected function getArguments()
437
    {
438
        return [
439
            ['name', InputArgument::REQUIRED, 'The name of the class'],
440
        ];
441
    }
442
}