Completed
Push — master ( b0f7dc...017e63 )
by Takafumi
07:37
created

Controller::getColumnsFromTable()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4.0047

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 4
nop 1
dl 0
loc 23
ccs 14
cts 15
cp 0.9333
crap 4.0047
rs 9.7998
c 0
b 0
f 0
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
        $inputs = $this->getInputsWithFiles($request, $inputs);
163 2
        $model = $this->model::create($inputs);
164 2
        foreach ($this->getRelations() as $key => $relation) {
165
            if ($relation['type'] !== 'BelongsToMany') {
166
                continue;
167
            }
168
169
            if (!empty($inputs[$key])) {
170
                $model->{$relation['relation_name']}()->sync($inputs[$key]);
171
            }
172
        }
173
174 2
        $request->session()->flash('message', 'Create');
175
176 2
        return redirect(route("admin.{$this->getTable()}.show", [$model->id]));
177
    }
178
179
    /**
180
     * @param  int  $id
181
     * @return \Illuminate\Support\HtmlString
182
     *
183
     * @throws \Throwable
184
     */
185 1
    public function edit(int $id)
186
    {
187 1
        $model = $this->model::findOrFail($id);
188 1
        $columns = $this->getColumnsFromTable($model);
189 1
        $relations = $this->getRelations();
190
191 1
        return new HtmlString(
192 1
            view()->make(static::$defaultEditView, [
193 1
                'class' => $this->getClassName(),
194 1
                'table' => $this->getTable(),
195 1
                'layoutView' => static::$defaultLayoutView,
196 1
                'columns' => $columns,
197 1
                'model' => $model,
198 1
                'relations' => $relations,
199 1
                'files' => $this->files,
200 1
                'enum' => $this->enum,
201 1
            ])->render()
202
        );
203
    }
204
205
    /**
206
     * @param  \Illuminate\Http\Request  $request
207
     * @param  int  $id
208
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
209
     */
210 1
    public function update(Request $request, int $id)
211
    {
212 1
        $model = $this->model::findOrFail($id);
213 1
        $inputs = $this->validate ? $request->validate($this->validate) : array_filter($request->post(), function ($item) {
214
            return $item !== null;
215 1
        });
216 1
        if (isset($inputs['password'])) {
217 1
            $inputs['password'] = \Hash::make($inputs['password']);
218
        }
219 1
        $inputs = $this->getInputsWithFiles($request, $inputs);
220 1
        $model->update($inputs);
221 1
        foreach ($this->getRelations() as $key => $relation) {
222
            if ($relation['type'] !== 'BelongsToMany') {
223
                continue;
224
            }
225
226
            if (!empty($inputs[$key])) {
227
                $model->{$relation['relation_name']}()->sync($inputs[$key]);
228
            }
229
        }
230
231 1
        $request->session()->flash('message', 'Update');
232
233 1
        return redirect(route("admin.{$this->getTable()}.show", [$model->id]));
234
    }
235
236
    /**
237
     * @param  \Illuminate\Http\Request  $request
238
     * @param  int  $id
239
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
240
     */
241 1
    public function destroy(Request $request, int $id)
242
    {
243 1
        $model = $this->model::findOrFail($id);
244 1
        $model->delete();
245
246 1
        $request->session()->flash('message', 'Delete');
247
248 1
        return redirect(route("admin.{$this->getTable()}.index"));
249
    }
250
251
    /**
252
     * @param  \Illuminate\Http\Request  $request
253
     * @param  int  $id
254
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
255
     */
256 1
    public function comments(Request $request, int $id)
257
    {
258 1
        $model = $this->model::findOrFail($id);
259 1
        $inputs = $request->validate([
260 1
            'body' => 'required',
261
        ]);
262 1
        $model->comments()->create([
263 1
            'body' => $inputs['body'],
264
        ]);
265
266 1
        $request->session()->flash('message', 'Create comment');
267
268 1
        return redirect(route("admin.{$this->getTable()}.show", [$model->id]));
269
    }
270
271
    /**
272
     * @return string
273
     */
274 6
    protected function getTable()
275
    {
276 6
        return (new $this->model)->getTable();
277
    }
278
279
    /**
280
     * @return array
281
     */
282 2
    protected function getRelations()
283
    {
284 2
        $model = (new $this->model)->newInstance();
285
286 2
        $relations = [];
287
288
        try {
289 2
            $methods = (new ReflectionClass($model))->getMethods(ReflectionMethod::IS_PUBLIC);
290 2
            foreach($methods as $method) {
291
                if (
292 2
                    $method->class != get_class($model) ||
293 2
                    !empty($method->getParameters()) ||
294 2
                    $method->getName() == __FUNCTION__
295
                ) {
296 2
                    continue;
297
                }
298
299
                try {
300 2
                    $return = $method->invoke($model);
301
302 2
                    if ($return instanceof BelongsTo) {
303
                        $relations[$return->getForeignKey()] = [
304
                            'type' => (new ReflectionClass($return))->getShortName(),
305
                            'model' => (new ReflectionClass($return->getRelated()))->getName(),
306
                        ];
307 2
                    } elseif ($return instanceof BelongsToMany) {
308
                        $relations[$return->getRelatedPivotKeyName()] = [
309
                            'type' => (new ReflectionClass($return))->getShortName(),
310
                            'model' => (new ReflectionClass($return->getRelated()))->getName(),
311 2
                            'relation_name' => $return->getRelationName(),
312
                        ];
313
                    }
314 2
                } catch (ReflectionException $e) {
315
                    // Ignore exception
316
                }
317
            }
318
        } catch (ReflectionException $e) {
319
            // Ignore exception
320
        }
321
322 2
        return $relations;
323
    }
324
325
    /**
326
     * @return string
327
     */
328 6
    protected function getClassName()
329
    {
330
        try {
331 6
            return (new ReflectionClass($this))->getShortName();
332
        } catch (ReflectionException $e) {
333
            return '';
334
        }
335
    }
336
337
    /**
338
     * @param  \Illuminate\Database\Eloquent\Model $model
339
     * @return array
340
     *
341
     * @throws \Throwable
342
     */
343 6
    protected function getColumnsFromTable($model)
344
    {
345 6
        $table = $model->getConnection()->getTablePrefix().$model->getTable();
346 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

346
        $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...
347 6
        $databasePlatform = $schema->getDatabasePlatform();
348 6
        $databasePlatform->registerDoctrineTypeMapping('enum', 'string');
349
350 6
        $database = null;
351 6
        if (strpos($table, '.')) {
352
            list($database, $table) = explode('.', $table);
353
        }
354
355 6
        $listTableColumns = $schema->listTableColumns($table, $database);
356
357 6
        $columns = [];
358 6
        if ($listTableColumns) {
359 6
            foreach ($listTableColumns as $column) {
360 6
                $name = $column->getName();
361 6
                $columns[$name] = $this->convertColumnTypeName($column->getType()->getName());
362
            }
363
        }
364
365 6
        return $columns;
366
    }
367
368
    /**
369
     * @param  \Illuminate\Http\Request $request
370
     * @param  array $inputs
371
     * @return array
372
     */
373 2
    protected function getInputsWithFiles($request, $inputs)
374
    {
375 2
        if (! empty($this->files)) {
376
            $files = array_filter($inputs, function ($item, $key) {
377
                return in_array($key, $this->files) && $item instanceof UploadedFile;
378
            }, ARRAY_FILTER_USE_BOTH);
379
380
            foreach ($files as $key => $file) {
381
                $fileName = Str::random(32).".".$request->{$key}->extension();
382
                $request->{$key}->storePubliclyAs("public/{$this->getTable()}", $fileName);
383
384
                $inputs[$key] = $fileName;
385
            }
386
        }
387
388 2
        return $inputs;
389
    }
390
391
    /**
392
     * @param  string $typeName
393
     * @return string
394
     */
395 6
    private function convertColumnTypeName($typeName)
396
    {
397
        $mapping = [
398 6
            'string' => 'string',
399
            'text' => 'text',
400
            'date' => 'date',
401
            'time' => 'time',
402
            'datetimetz' => 'datetime',
403
            'datetime' => 'datetime',
404
            'integer' => 'integer',
405
            'bigint' => 'integer',
406
            'smallint' => 'integer',
407
            'boolean' => 'boolean',
408
            'decimal' => 'float',
409
            'float' => 'float',
410
        ];
411 6
        $defaultType = 'mixed';
412
413 6
        return isset($mapping[$typeName]) ? $mapping[$typeName] : $defaultType;
414
    }
415
}
416