Passed
Push — master ( 9c3264...7e350c )
by Takafumi
04:58 queued 29s
created

Controller::getQueryBuilderForIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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