Issues (27)

src/Console/Commands/ControllerMakeCommand.php (3 issues)

Labels
Severity
1
<?php
2
3
namespace Larafast\Fastapi\Console\Commands;
4
5
use Illuminate\Support\Str;
6
use InvalidArgumentException;
7
use Larafast\Fastapi\Console\Contracts\GeneratorCommand;
8
use Symfony\Component\Console\Input\InputOption;
9
10
class ControllerMakeCommand extends GeneratorCommand
11
{
12
    /**
13
     * The console command name.
14
     *
15
     * @var string
16
     */
17
    protected $name = 'fastApi:controller';
18
19
    /**
20
     * The console command description.
21
     *
22
     * @var string
23
     */
24
    protected $description = 'Create a new controller class';
25
26
    /**
27
     * The type of class being generated.
28
     *
29
     * @var string
30
     */
31
    protected $type = 'Controller';
32
33
    /**
34
     * Get the stub file for the generator.
35
     *
36
     * @return string
37
     */
38
    protected function getStub()
39
    {
40
        return config('fastApi.stubs_dir') . '/controller.api.stub';
41
    }
42
43
    /**
44
     * Get the default namespace for the class.
45
     *
46
     * @param string $rootNamespace
47
     *
48
     * @return string
49
     */
50
    protected function getDefaultNamespace($rootNamespace)
51
    {
52
        $dir = $this->hasOption('controller-dir') && trim($this->option('controller-dir')) != ''
0 ignored issues
show
It seems like $this->option('controller-dir') can also be of type string[]; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

52
        $dir = $this->hasOption('controller-dir') && trim(/** @scrutinizer ignore-type */ $this->option('controller-dir')) != ''
Loading history...
53
            ? $this->option('controller-dir')
54
            : null;
55
        if ($dir) {
56
            return $rootNamespace . '\Http\Controllers\\' . Str::studly(strtolower($dir));
57
        }
58
59
        return $rootNamespace . '\Http\Controllers';
60
    }
61
62
    /**
63
     * Build the class with the given name.
64
     *
65
     * Remove the base controller import if we are already in base namespace.
66
     *
67
     * @param string $name
68
     *
69
     * @return string
70
     */
71
    protected function buildClass($name)
72
    {
73
        $controllerNamespace = $this->getNamespace($name);
74
75
        $replace = [];
76
77
        if ($this->option('parent')) {
78
            $replace = $this->buildParentReplacements();
79
        }
80
81
        if ($this->option('model')) {
82
            $replace = $this->buildModelReplacements($replace);
83
            if ($model = $this->option('model')) {
84
                $replace = str_replace('$modelSlug$', Str::slug(str_to_words($model), '-'), $replace);
85
            }
86
        }
87
88
89
        $replace["use {$controllerNamespace}\Controller;\n"] = '';
90
91
        return str_replace(
92
            array_keys($replace), array_values($replace), parent::buildClass($name)
93
        );
94
    }
95
96
    /**
97
     * Build the replacements for a parent controller.
98
     *
99
     * @return array
100
     */
101
    protected function buildParentReplacements()
102
    {
103
        $parentModelClass = $this->parseModel($this->option('parent'));
0 ignored issues
show
It seems like $this->option('parent') can also be of type string[]; however, parameter $model of Larafast\Fastapi\Console...keCommand::parseModel() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
        $parentModelClass = $this->parseModel(/** @scrutinizer ignore-type */ $this->option('parent'));
Loading history...
104
105
        if (!class_exists($parentModelClass)) {
106
            if ($this->confirm("A {$parentModelClass} model does not exist. Do you want to generate it?", true)) {
107
                $this->call('fastApi:model', ['name' => $parentModelClass]);
108
            }
109
        }
110
111
        return [
112
            'ParentDummyFullModelClass' => $parentModelClass,
113
            'ParentDummyModelClass' => class_basename($parentModelClass),
114
            'ParentDummyModelVariable' => lcfirst(class_basename($parentModelClass)),
115
        ];
116
    }
117
118
    /**
119
     * Get the fully-qualified model class name.
120
     *
121
     * @param string $model
122
     *
123
     * @return string
124
     */
125
    protected function parseModel($model)
126
    {
127
        if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
128
            throw new InvalidArgumentException('Model name contains invalid characters.');
129
        }
130
131
        $model = trim(str_replace('/', '\\', $model), '\\');
132
133
        if (!Str::startsWith($model, $rootNamespace = $this->laravel->getNamespace())) {
134
            $model = $rootNamespace . $model;
135
        }
136
137
        return $model;
138
    }
139
140
    /**
141
     * Build the model replacement values.
142
     *
143
     * @param array $replace
144
     *
145
     * @return array
146
     */
147
    protected function buildModelReplacements(array $replace)
148
    {
149
        $modelClass = $this->parseModel($this->option('model'));
0 ignored issues
show
It seems like $this->option('model') can also be of type string[]; however, parameter $model of Larafast\Fastapi\Console...keCommand::parseModel() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

149
        $modelClass = $this->parseModel(/** @scrutinizer ignore-type */ $this->option('model'));
Loading history...
150
151
        if (!class_exists($modelClass)) {
152
153
            $this->call('fastApi:model', ['name' => $modelClass]);
154
        }
155
156
        $label = str_to_words(class_basename($modelClass));
157
158
        $modelSlug = Str::slug(Str::plural($label, 2));
159
        $routeBase = $modelSlug;
160
        $dir = $this->appendModelToViewDir($this->option('views-dir'), $modelSlug);
161
        $dir = str_replace('/', '.', $dir);
162
163
        if ($this->option('route-base')) {
164
            $routeBase = $this->option('route-base');
165
        }
166
167
        return array_merge($replace, [
168
            'DummyFullModelClass' => $modelClass,
169
            'DummyModelClass' => class_basename($modelClass),
170
            'DummyModelVariable' => lcfirst(class_basename($modelClass)),
171
            '$modelSlug$' => $modelSlug,
172
            '$label$' => $label,
173
            '$rows$' => Str::plural(lcfirst(class_basename($modelClass)), 2),
174
            '$viewDir$' => $dir,
175
            '$routeBase$' => $routeBase,
176
        ]);
177
    }
178
179
    private function appendModelToViewDir($path, $model)
180
    {
181
        $pathArray = explode("/", $path);
182
        if ($pathArray[sizeof($pathArray) - 1] == $model) {
183
            return $path;
184
        }
185
186
        return rtrim($path, '/') . "/" . $model;
187
    }
188
189
    /**
190
     * Get the console command options.
191
     *
192
     * @return array
193
     */
194
    protected function getOptions()
195
    {
196
        return [
197
            ['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a resource controller for the given model.'],
198
199
            ['resource', 'r', InputOption::VALUE_NONE, 'Generate a resource controller class.'],
200
201
            ['parent', 'p', InputOption::VALUE_OPTIONAL, 'Generate a nested resource controller class.'],
202
203
            ['api', null, InputOption::VALUE_NONE, 'Exclude the create and edit methods from the controller.'],
204
205
            ['views-dir', 'i', InputOption::VALUE_OPTIONAL, 'Use the specified path in controller actions to return the respective view'],
206
207
            ['controller-dir', 'c', InputOption::VALUE_OPTIONAL, 'Specify the controller path within the Http directory'],
208
209
            ['route-base', 'b', InputOption::VALUE_OPTIONAL, 'Specify the base route to use'],
210
211
            ['force', 'f', InputOption::VALUE_NONE, 'Overwrite existing controller']
212
        ];
213
    }
214
215
    public function handle()
216
    {
217
        $name = $this->qualifyClass($this->getNameInput());
218
        $path = $this->getPath($name);
219
        // First we will check to see if the class already exists. If it does, we don't want
220
        // to create the class and overwrite the user's code. So, we will bail out so the
221
        // code is untouched. Otherwise, we will continue generating this class' files.
222
        if ((!$this->hasOption('force') ||
223
                !$this->option('force')) &&
224
            $this->alreadyExists($this->getNameInput())
225
        ) {
226
            $this->error($this->type . ' already exists!');
227
228
            return false;
229
        }
230
231
        // Next, we will generate the path to the location where this class' file should get
232
        // written. Then, we will build the class and make the proper replacements on the
233
        // stub files so that it gets the correctly formatted namespace and class name.
234
        $this->makeDirectory($path);
235
236
        //$displayPath = str_replace($this->laravel['path'], '/app', $path);
237
238
        $this->files->put($path, $this->buildClass($name));
239
240
        $this->info($this->type . ' created successfully');
241
    }
242
}
243