Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Routing\Console;
4
 
5
use Illuminate\Console\Concerns\CreatesMatchingTest;
6
use Illuminate\Console\GeneratorCommand;
7
use InvalidArgumentException;
8
use Symfony\Component\Console\Attribute\AsCommand;
399 lars 9
use Symfony\Component\Console\Input\InputInterface;
148 lars 10
use Symfony\Component\Console\Input\InputOption;
399 lars 11
use Symfony\Component\Console\Output\OutputInterface;
148 lars 12
 
13
#[AsCommand(name: 'make:controller')]
14
class ControllerMakeCommand extends GeneratorCommand
15
{
16
    use CreatesMatchingTest;
17
 
18
    /**
19
     * The console command name.
20
     *
21
     * @var string
22
     */
23
    protected $name = 'make:controller';
24
 
25
    /**
26
     * The name of the console command.
27
     *
28
     * This name is used to identify the command during lazy loading.
29
     *
30
     * @var string|null
31
     *
32
     * @deprecated
33
     */
34
    protected static $defaultName = 'make:controller';
35
 
36
    /**
37
     * The console command description.
38
     *
39
     * @var string
40
     */
41
    protected $description = 'Create a new controller class';
42
 
43
    /**
44
     * The type of class being generated.
45
     *
46
     * @var string
47
     */
48
    protected $type = 'Controller';
49
 
50
    /**
51
     * Get the stub file for the generator.
52
     *
53
     * @return string
54
     */
55
    protected function getStub()
56
    {
57
        $stub = null;
58
 
59
        if ($type = $this->option('type')) {
60
            $stub = "/stubs/controller.{$type}.stub";
61
        } elseif ($this->option('parent')) {
62
            $stub = $this->option('singleton')
63
                        ? '/stubs/controller.nested.singleton.stub'
64
                        : '/stubs/controller.nested.stub';
65
        } elseif ($this->option('model')) {
66
            $stub = '/stubs/controller.model.stub';
67
        } elseif ($this->option('invokable')) {
68
            $stub = '/stubs/controller.invokable.stub';
69
        } elseif ($this->option('singleton')) {
70
            $stub = '/stubs/controller.singleton.stub';
71
        } elseif ($this->option('resource')) {
72
            $stub = '/stubs/controller.stub';
73
        }
74
 
75
        if ($this->option('api') && is_null($stub)) {
76
            $stub = '/stubs/controller.api.stub';
77
        } elseif ($this->option('api') && ! is_null($stub) && ! $this->option('invokable')) {
78
            $stub = str_replace('.stub', '.api.stub', $stub);
79
        }
80
 
81
        $stub ??= '/stubs/controller.plain.stub';
82
 
83
        return $this->resolveStubPath($stub);
84
    }
85
 
86
    /**
87
     * Resolve the fully-qualified path to the stub.
88
     *
89
     * @param  string  $stub
90
     * @return string
91
     */
92
    protected function resolveStubPath($stub)
93
    {
94
        return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
95
                        ? $customPath
96
                        : __DIR__.$stub;
97
    }
98
 
99
    /**
100
     * Get the default namespace for the class.
101
     *
102
     * @param  string  $rootNamespace
103
     * @return string
104
     */
105
    protected function getDefaultNamespace($rootNamespace)
106
    {
107
        return $rootNamespace.'\Http\Controllers';
108
    }
109
 
110
    /**
111
     * Build the class with the given name.
112
     *
113
     * Remove the base controller import if we are already in the base namespace.
114
     *
115
     * @param  string  $name
116
     * @return string
117
     */
118
    protected function buildClass($name)
119
    {
120
        $controllerNamespace = $this->getNamespace($name);
121
 
122
        $replace = [];
123
 
124
        if ($this->option('parent')) {
125
            $replace = $this->buildParentReplacements();
126
        }
127
 
128
        if ($this->option('model')) {
129
            $replace = $this->buildModelReplacements($replace);
130
        }
131
 
132
        if ($this->option('creatable')) {
133
            $replace['abort(404);'] = '//';
134
        }
135
 
136
        $replace["use {$controllerNamespace}\Controller;\n"] = '';
137
 
138
        return str_replace(
139
            array_keys($replace), array_values($replace), parent::buildClass($name)
140
        );
141
    }
142
 
143
    /**
144
     * Build the replacements for a parent controller.
145
     *
146
     * @return array
147
     */
148
    protected function buildParentReplacements()
149
    {
150
        $parentModelClass = $this->parseModel($this->option('parent'));
151
 
152
        if (! class_exists($parentModelClass) &&
153
            $this->components->confirm("A {$parentModelClass} model does not exist. Do you want to generate it?", true)) {
154
            $this->call('make:model', ['name' => $parentModelClass]);
155
        }
156
 
157
        return [
158
            'ParentDummyFullModelClass' => $parentModelClass,
159
            '{{ namespacedParentModel }}' => $parentModelClass,
160
            '{{namespacedParentModel}}' => $parentModelClass,
161
            'ParentDummyModelClass' => class_basename($parentModelClass),
162
            '{{ parentModel }}' => class_basename($parentModelClass),
163
            '{{parentModel}}' => class_basename($parentModelClass),
164
            'ParentDummyModelVariable' => lcfirst(class_basename($parentModelClass)),
165
            '{{ parentModelVariable }}' => lcfirst(class_basename($parentModelClass)),
166
            '{{parentModelVariable}}' => lcfirst(class_basename($parentModelClass)),
167
        ];
168
    }
169
 
170
    /**
171
     * Build the model replacement values.
172
     *
173
     * @param  array  $replace
174
     * @return array
175
     */
176
    protected function buildModelReplacements(array $replace)
177
    {
178
        $modelClass = $this->parseModel($this->option('model'));
179
 
180
        if (! class_exists($modelClass) && $this->components->confirm("A {$modelClass} model does not exist. Do you want to generate it?", true)) {
181
            $this->call('make:model', ['name' => $modelClass]);
182
        }
183
 
184
        $replace = $this->buildFormRequestReplacements($replace, $modelClass);
185
 
186
        return array_merge($replace, [
187
            'DummyFullModelClass' => $modelClass,
188
            '{{ namespacedModel }}' => $modelClass,
189
            '{{namespacedModel}}' => $modelClass,
190
            'DummyModelClass' => class_basename($modelClass),
191
            '{{ model }}' => class_basename($modelClass),
192
            '{{model}}' => class_basename($modelClass),
193
            'DummyModelVariable' => lcfirst(class_basename($modelClass)),
194
            '{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
195
            '{{modelVariable}}' => lcfirst(class_basename($modelClass)),
196
        ]);
197
    }
198
 
199
    /**
200
     * Get the fully-qualified model class name.
201
     *
202
     * @param  string  $model
203
     * @return string
204
     *
205
     * @throws \InvalidArgumentException
206
     */
207
    protected function parseModel($model)
208
    {
209
        if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
210
            throw new InvalidArgumentException('Model name contains invalid characters.');
211
        }
212
 
213
        return $this->qualifyModel($model);
214
    }
215
 
216
    /**
217
     * Build the model replacement values.
218
     *
219
     * @param  array  $replace
220
     * @param  string  $modelClass
221
     * @return array
222
     */
223
    protected function buildFormRequestReplacements(array $replace, $modelClass)
224
    {
225
        [$namespace, $storeRequestClass, $updateRequestClass] = [
226
            'Illuminate\\Http', 'Request', 'Request',
227
        ];
228
 
229
        if ($this->option('requests')) {
230
            $namespace = 'App\\Http\\Requests';
231
 
232
            [$storeRequestClass, $updateRequestClass] = $this->generateFormRequests(
233
                $modelClass, $storeRequestClass, $updateRequestClass
234
            );
235
        }
236
 
237
        $namespacedRequests = $namespace.'\\'.$storeRequestClass.';';
238
 
239
        if ($storeRequestClass !== $updateRequestClass) {
240
            $namespacedRequests .= PHP_EOL.'use '.$namespace.'\\'.$updateRequestClass.';';
241
        }
242
 
243
        return array_merge($replace, [
244
            '{{ storeRequest }}' => $storeRequestClass,
245
            '{{storeRequest}}' => $storeRequestClass,
246
            '{{ updateRequest }}' => $updateRequestClass,
247
            '{{updateRequest}}' => $updateRequestClass,
248
            '{{ namespacedStoreRequest }}' => $namespace.'\\'.$storeRequestClass,
249
            '{{namespacedStoreRequest}}' => $namespace.'\\'.$storeRequestClass,
250
            '{{ namespacedUpdateRequest }}' => $namespace.'\\'.$updateRequestClass,
251
            '{{namespacedUpdateRequest}}' => $namespace.'\\'.$updateRequestClass,
252
            '{{ namespacedRequests }}' => $namespacedRequests,
253
            '{{namespacedRequests}}' => $namespacedRequests,
254
        ]);
255
    }
256
 
257
    /**
258
     * Generate the form requests for the given model and classes.
259
     *
260
     * @param  string  $modelClass
261
     * @param  string  $storeRequestClass
262
     * @param  string  $updateRequestClass
263
     * @return array
264
     */
265
    protected function generateFormRequests($modelClass, $storeRequestClass, $updateRequestClass)
266
    {
267
        $storeRequestClass = 'Store'.class_basename($modelClass).'Request';
268
 
269
        $this->call('make:request', [
270
            'name' => $storeRequestClass,
271
        ]);
272
 
273
        $updateRequestClass = 'Update'.class_basename($modelClass).'Request';
274
 
275
        $this->call('make:request', [
276
            'name' => $updateRequestClass,
277
        ]);
278
 
279
        return [$storeRequestClass, $updateRequestClass];
280
    }
281
 
282
    /**
283
     * Get the console command options.
284
     *
285
     * @return array
286
     */
287
    protected function getOptions()
288
    {
289
        return [
290
            ['api', null, InputOption::VALUE_NONE, 'Exclude the create and edit methods from the controller'],
291
            ['type', null, InputOption::VALUE_REQUIRED, 'Manually specify the controller stub file to use'],
292
            ['force', null, InputOption::VALUE_NONE, 'Create the class even if the controller already exists'],
293
            ['invokable', 'i', InputOption::VALUE_NONE, 'Generate a single method, invokable controller class'],
294
            ['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a resource controller for the given model'],
295
            ['parent', 'p', InputOption::VALUE_OPTIONAL, 'Generate a nested resource controller class'],
296
            ['resource', 'r', InputOption::VALUE_NONE, 'Generate a resource controller class'],
297
            ['requests', 'R', InputOption::VALUE_NONE, 'Generate FormRequest classes for store and update'],
298
            ['singleton', 's', InputOption::VALUE_NONE, 'Generate a singleton resource controller class'],
299
            ['creatable', null, InputOption::VALUE_NONE, 'Indicate that a singleton resource should be creatable'],
300
        ];
301
    }
399 lars 302
 
303
    /**
304
     * Interact further with the user if they were prompted for missing arguments.
305
     *
306
     * @param  \Symfony\Component\Console\Input\InputInterface  $input
307
     * @param  \Symfony\Component\Console\Output\OutputInterface  $output
308
     * @return void
309
     */
310
    protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output)
311
    {
312
        if ($this->didReceiveOptions($input)) {
313
            return;
314
        }
315
 
316
        $type = $this->components->choice('Which type of controller would you like', [
317
            'empty',
318
            'api',
319
            'invokable',
320
            'resource',
321
            'singleton',
322
        ], default: 0);
323
 
324
        if ($type !== 'empty') {
325
            $input->setOption($type, true);
326
        }
327
 
328
        if (in_array($type, ['api', 'resource', 'singleton'])) {
329
            $model = $this->components->askWithCompletion(
330
                "What model should this $type controller be for?",
331
                $this->possibleModels(),
332
                'none'
333
            );
334
 
335
            if ($model && $model !== 'none') {
336
                $input->setOption('model', $model);
337
            }
338
        }
339
    }
148 lars 340
}