Completed
Push — master ( 7dd9f0...f2f82b )
by Takafumi
05:21
created

Controller   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 408
Duplicated Lines 0 %

Test Coverage

Coverage 73.93%

Importance

Changes 0
Metric Value
dl 0
loc 408
ccs 139
cts 188
cp 0.7393
rs 7.9487
c 0
b 0
f 0
wmc 52

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getClassName() 0 6 2
A getTable() 0 3 1
A destroy() 0 8 1
D create() 0 34 9
A comments() 0 13 1
A edit() 0 17 1
A index() 0 15 1
A show() 0 16 1
D getRelations() 0 41 9
C getColumnsFromTable() 0 58 16
A new() 0 17 1
D update() 0 35 9

How to fix   Complexity   

Complex Class

Complex classes like Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Enomotodev\LaractiveAdmin\Http\Controllers;
4
5
use ReflectionClass;
6
use ReflectionException;
7
use ReflectionMethod;
8
use Illuminate\Database\Eloquent\Relations\BelongsTo;
9
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
10
use Illuminate\Http\Request;
11
use Illuminate\Http\UploadedFile;
12
use Illuminate\Support\HtmlString;
13
use Illuminate\Support\Str;
14
15
abstract class Controller
16
{
17
    /**
18
     * @var string
19
     */
20
    public $model;
21
22
    /**
23
     * @var array
24
     */
25
    protected $files = [];
26
27
    /**
28
     * @var array
29
     */
30
    protected $validate = [];
31
32
    /**
33
     * @var array
34
     */
35
    protected $enum = [];
36
37
    /**
38
     * The default layout view.
39
     *
40
     * @var string
41
     */
42
    public static $defaultLayoutView = 'laractive-admin::layout';
43
44
    /**
45
     * The default index view.
46
     *
47
     * @var string
48
     */
49
    public static $defaultIndexView = 'laractive-admin::index';
50
51
    /**
52
     * The default index view.
53
     *
54
     * @var string
55
     */
56
    public static $defaultShowView = 'laractive-admin::show';
57
58
    /**
59
     * The default new view.
60
     *
61
     * @var string
62
     */
63
    public static $defaultNewView = 'laractive-admin::new';
64
65
    /**
66
     * The default edit view.
67
     *
68
     * @var string
69
     */
70
    public static $defaultEditView = 'laractive-admin::edit';
71
72
    /**
73
     * @var \Illuminate\Session\SessionManager
74
     */
75
    protected $session;
76
77
    /**
78
     * @return \Illuminate\Support\HtmlString
79
     *
80
     * @throws \Throwable
81
     */
82 2
    public function index()
83
    {
84 2
        $model = $this->model::newModelInstance();
85 2
        $columns = $this->getColumnsFromTable($model);
86 2
        $collection = $this->model::paginate();
87
88 2
        return new HtmlString(
89 2
            view()->make(static::$defaultIndexView, [
90 2
                'class' => $this->getClassName(),
91 2
                'table' => $this->getTable(),
92 2
                'layoutView' => static::$defaultLayoutView,
93 2
                'columns' => $columns,
94 2
                'collection' => $collection,
95 2
                'enum' => $this->enum,
96 2
            ])->render()
97
        );
98
    }
99
100
    /**
101
     * @param  int  $id
102
     * @return \Illuminate\Support\HtmlString
103
     *
104
     * @throws \Throwable
105
     */
106 4
    public function show(int $id)
107
    {
108 4
        $model = $this->model::findOrFail($id);
109 4
        $commentColumns = array_filter($this->getColumnsFromTable($model->comments()->getRelated()), function ($type, $name) use ($model) {
110 4
            return !in_array($name, ['id', 'updated_at', $model->comments()->getForeignKeyName(), $model->comments()->getMorphType()]);
111 4
        }, ARRAY_FILTER_USE_BOTH);
112
113 4
        return new HtmlString(
114 4
            view()->make(static::$defaultShowView, [
115 4
                'class' => $this->getClassName(),
116 4
                'table' => $this->getTable(),
117 4
                'layoutView' => static::$defaultLayoutView,
118 4
                'model' => $model,
119 4
                'commentColumns' => $commentColumns,
120 4
                'enum' => $this->enum,
121 4
            ])->render()
122
        );
123
    }
124
125
    /**
126
     * @return \Illuminate\Support\HtmlString
127
     *
128
     * @throws \Throwable
129
     */
130 2
    public function new()
131
    {
132 2
        $model = $this->model::newModelInstance();
133 2
        $columns = $this->getColumnsFromTable($model);
134 2
        $relations = $this->getRelations();
135
136 2
        return new HtmlString(
137 2
            view()->make(static::$defaultNewView, [
138 2
                'class' => $this->getClassName(),
139 2
                'table' => $this->getTable(),
140 2
                'layoutView' => static::$defaultLayoutView,
141 2
                'columns' => $columns,
142 2
                'model' => $model,
143 2
                'relations' => $relations,
144 2
                'files' => $this->files,
145 2
                'enum' => $this->enum,
146 2
            ])->render()
147
        );
148
    }
149
150
    /**
151
     * @param  \Illuminate\Http\Request  $request
152
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
153
     */
154
    public function create(Request $request)
155
    {
156 2
        $inputs = $this->validate ? $request->validate($this->validate) : array_filter($request->post(), function ($item) {
157
            return $item !== null;
158 2
        });
159 2
        if (isset($inputs['password'])) {
160 2
            $inputs['password'] = \Hash::make($inputs['password']);
161
        }
162 2
        if (!empty($this->files)) {
163
            $files = array_filter($inputs, function ($item, $key) {
164
                return in_array($key, $this->files) && $item instanceof UploadedFile;
165
            }, ARRAY_FILTER_USE_BOTH);
166
167
            foreach ($files as $key => $file) {
168
                $fileName = Str::random(32).".".$request->{$key}->extension();
169
                $request->{$key}->storePubliclyAs("public/{$this->getTable()}", $fileName);
170
171
                $inputs[$key] = $fileName;
172
            }
173
        }
174 2
        $model = $this->model::create($inputs);
175 2
        foreach ($this->getRelations() as $key => $relation) {
176
            if ($relation['type'] !== 'BelongsToMany') {
177
                continue;
178
            }
179
180
            if (!empty($inputs[$key])) {
181
                $model->{$relation['relation_name']}()->sync($inputs[$key]);
182
            }
183
        }
184
185 2
        $request->session()->flash('message', 'Create');
186
187 2
        return redirect(route("admin.{$this->getTable()}.show", [$model->id]));
188
    }
189
190
    /**
191
     * @param  int  $id
192
     * @return \Illuminate\Support\HtmlString
193
     *
194
     * @throws \Throwable
195
     */
196 1
    public function edit(int $id)
197
    {
198 1
        $model = $this->model::findOrFail($id);
199 1
        $columns = $this->getColumnsFromTable($model);
200 1
        $relations = $this->getRelations();
201
202 1
        return new HtmlString(
203 1
            view()->make(static::$defaultEditView, [
204 1
                'class' => $this->getClassName(),
205 1
                'table' => $this->getTable(),
206 1
                'layoutView' => static::$defaultLayoutView,
207 1
                'columns' => $columns,
208 1
                'model' => $model,
209 1
                'relations' => $relations,
210 1
                'files' => $this->files,
211 1
                'enum' => $this->enum,
212 1
            ])->render()
213
        );
214
    }
215
216
    /**
217
     * @param  \Illuminate\Http\Request  $request
218
     * @param  int  $id
219
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
220
     */
221 1
    public function update(Request $request, int $id)
222
    {
223 1
        $model = $this->model::findOrFail($id);
224 1
        $inputs = $this->validate ? $request->validate($this->validate) : array_filter($request->post(), function ($item) {
225
            return $item !== null;
226 1
        });
227 1
        if (isset($inputs['password'])) {
228 1
            $inputs['password'] = \Hash::make($inputs['password']);
229
        }
230 1
        if (!empty($this->files)) {
231
            $files = array_filter($inputs, function ($item, $key) {
232
                return in_array($key, $this->files) && $item instanceof UploadedFile;
233
            }, ARRAY_FILTER_USE_BOTH);
234
235
            foreach ($files as $key => $file) {
236
                $fileName = Str::random(32).".".$request->{$key}->extension();
237
                $request->{$key}->storePubliclyAs("public/{$this->getTable()}", $fileName);
238
239
                $inputs[$key] = $fileName;
240
            }
241
        }
242 1
        $model->update($inputs);
243 1
        foreach ($this->getRelations() as $key => $relation) {
244
            if ($relation['type'] !== 'BelongsToMany') {
245
                continue;
246
            }
247
248
            if (!empty($inputs[$key])) {
249
                $model->{$relation['relation_name']}()->sync($inputs[$key]);
250
            }
251
        }
252
253 1
        $request->session()->flash('message', 'Update');
254
255 1
        return redirect(route("admin.{$this->getTable()}.show", [$model->id]));
256
    }
257
258
    /**
259
     * @param  \Illuminate\Http\Request  $request
260
     * @param  int  $id
261
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
262
     */
263 1
    public function destroy(Request $request, int $id)
264
    {
265 1
        $model = $this->model::findOrFail($id);
266 1
        $model->delete();
267
268 1
        $request->session()->flash('message', 'Delete');
269
270 1
        return redirect(route("admin.{$this->getTable()}.index"));
271
    }
272
273
    /**
274
     * @param  \Illuminate\Http\Request  $request
275
     * @param  int  $id
276
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
277
     */
278 1
    public function comments(Request $request, int $id)
279
    {
280 1
        $model = $this->model::findOrFail($id);
281 1
        $inputs = $request->validate([
282 1
            'body' => 'required',
283
        ]);
284 1
        $model->comments()->create([
285 1
            'body' => $inputs['body'],
286
        ]);
287
288 1
        $request->session()->flash('message', 'Create comment');
289
290 1
        return redirect(route("admin.{$this->getTable()}.show", [$model->id]));
291
    }
292
293
    /**
294
     * @return string
295
     */
296 6
    protected function getTable()
297
    {
298 6
        return (new $this->model)->getTable();
299
    }
300
301
    /**
302
     * @return array
303
     */
304 2
    protected function getRelations()
305
    {
306 2
        $model = (new $this->model)->newInstance();
307
308 2
        $relations = [];
309
310
        try {
311 2
            $methods = (new ReflectionClass($model))->getMethods(ReflectionMethod::IS_PUBLIC);
312 2
            foreach($methods as $method) {
313
                if (
314 2
                    $method->class != get_class($model) ||
315 2
                    !empty($method->getParameters()) ||
316 2
                    $method->getName() == __FUNCTION__
317
                ) {
318 2
                    continue;
319
                }
320
321
                try {
322 2
                    $return = $method->invoke($model);
323
324 2
                    if ($return instanceof BelongsTo) {
325
                        $relations[$return->getForeignKey()] = [
326
                            'type' => (new ReflectionClass($return))->getShortName(),
327
                            'model' => (new ReflectionClass($return->getRelated()))->getName(),
328
                        ];
329 2
                    } elseif ($return instanceof BelongsToMany) {
330
                        $relations[$return->getRelatedPivotKeyName()] = [
331
                            'type' => (new ReflectionClass($return))->getShortName(),
332
                            'model' => (new ReflectionClass($return->getRelated()))->getName(),
333 2
                            'relation_name' => $return->getRelationName(),
334
                        ];
335
                    }
336 2
                } catch (ReflectionException $e) {
337
                    // Ignore exception
338
                }
339
            }
340
        } catch (ReflectionException $e) {
341
            // Ignore exception
342
        }
343
344 2
        return $relations;
345
    }
346
347
    /**
348
     * @return string
349
     */
350 6
    protected function getClassName()
351
    {
352
        try {
353 6
            return (new ReflectionClass($this))->getShortName();
354
        } catch (ReflectionException $e) {
355
            return '';
356
        }
357
    }
358
359
    /**
360
     * @param  \Illuminate\Database\Eloquent\Model $model
361
     * @return array
362
     *
363
     * @throws \Throwable
364
     */
365 6
    protected function getColumnsFromTable($model)
366
    {
367 6
        $table = $model->getConnection()->getTablePrefix().$model->getTable();
368 6
        $schema = $model->getConnection()->getDoctrineSchemaManager($table);
0 ignored issues
show
Unused Code introduced by
The call to Illuminate\Database\Conn...DoctrineSchemaManager() has too many arguments starting with $table. ( Ignorable by Annotation )

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

368
        $schema = $model->getConnection()->/** @scrutinizer ignore-call */ getDoctrineSchemaManager($table);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
369 6
        $databasePlatform = $schema->getDatabasePlatform();
370 6
        $databasePlatform->registerDoctrineTypeMapping('enum', 'string');
371
372 6
        $database = null;
373 6
        if (strpos($table, '.')) {
374
            list($database, $table) = explode('.', $table);
375
        }
376
377 6
        $listTableColumns = $schema->listTableColumns($table, $database);
378
379 6
        $columns = [];
380 6
        if ($listTableColumns) {
381 6
            foreach ($listTableColumns as $column) {
382 6
                $name = $column->getName();
383
384 6
                switch ($column->getType()->getName()) {
385 6
                    case 'string':
386 6
                        $type = 'string';
387 6
                        break;
388 6
                    case 'text':
389 4
                        $type = 'text';
390 4
                        break;
391 6
                    case 'date':
392
                        $type = 'date';
393
                        break;
394 6
                    case 'time':
395
                        $type = 'time';
396
                        break;
397 6
                    case 'datetimetz':
398 6
                    case 'datetime':
399 6
                        $type = 'datetime';
400 6
                        break;
401 6
                    case 'integer':
402
                    case 'bigint':
403
                    case 'smallint':
404 6
                        $type = 'integer';
405 6
                        break;
406
                    case 'boolean':
407
                        $type = 'boolean';
408
                        break;
409
                    case 'decimal':
410
                    case 'float':
411
                        $type = 'float';
412
                        break;
413
                    default:
414
                        $type = 'mixed';
415
                        break;
416
                }
417
418 6
                $columns[$name] = $type;
419
            }
420
        }
421
422 6
        return $columns;
423
    }
424
}
425