Completed
Push — master ( 6104e6...6e3dc8 )
by Eliurkis
01:39
created

CrudController::show()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 16
loc 16
rs 9.4285
cc 2
eloc 11
nc 2
nop 1
1
<?php
2
3
namespace Eliurkis\Crud;
4
5
use App\Http\Controllers\Controller;
6
use DB;
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Database\QueryException;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\Facades\Route;
11
12
class CrudController extends Controller
13
{
14
    protected $route;
15
    protected $entity;
16
    protected $entityInstance = null;
17
    protected $fields = [];
18
    protected $columns = [];
19
    protected $buttons = [
20
        'show',
21
        'create',
22
        'edit',
23
        'delete',
24
    ];
25
    protected $paginate = null;
26
    protected $searchable = [];
27
    protected $filters = [];
28
    protected $queryFilters = [];
29
    protected $orderBy = [];
30
    protected $orderByRaw = null;
31
    protected $filterRequire = [];
32
    protected $textsGeneral = [
33
        'list_title'   => 'Contents',
34
        'create_title' => '',
35
        'edit_title'   => '',
36
    ];
37
    protected $texts = [];
38
    protected $htmlFilters = [];
39
    protected $action = null;
40
    protected $formColsClasses = [
41
        'col-md-10 col-md-offset-1',
42
        'col-md-2',
43
        'col-md-10',
44
    ];
45
    protected $links = [];
46
    protected $listDisplay = [
47
        'action-buttons' => true,
48
    ];
49
50
    public function __construct($entity, $config = [])
51
    {
52
        $this->entity = $entity;
53
54
        $config = count($config) ? $config : config('crud.'.$this->route);
55
56
        if (is_array($config)) {
57
            foreach ($config as $key => $value) {
58
                $this->$key = $value;
59
            }
60
        }
61
    }
62
63
    public function index(Request $request)
64
    {
65
        // If DataTable is activated
66
        if (isset($this->dataTableActivated)) {
67
            return $this->indexDataTable($request);
68
        }
69
70
        $entity = $this->entity;
71
72
        // Relation Fields
73
        if ($belongToFields = $this->getBelongToFields()) {
74
            $entity = $this->entity->with($belongToFields);
75
        }
76
77
        // Filters
78
        $entity = $this->filters($entity, $request);
79
80
        // Search
81
        $entity = $this->search($entity, $request);
82
83
        // Order By
84
        if (!empty($this->orderBy)) {
85
            foreach ($this->orderBy as $column => $direction) {
86
                $entity = $entity->orderBy($column, $direction);
87
            }
88
        }
89
90
        if ($this->orderByRaw) {
91
            $entity = $entity->orderByRaw($this->orderByRaw);
92
        }
93
94
        // Pagination
95
        $rows = $this->paginate > 0 ? $this->paginate($entity, $request) : $entity->get();
96
97
        // HTML Filters
98
        $this->htmlFilters();
99
100
        return view('crud::list', compact('rows'))
101
            ->with('fields', $this->fields)
102
            ->with('columns', $this->columns)
103
            ->with('searchable', $this->searchable)
104
            ->with('buttons', $this->buttons)
105
            ->with('paginate', $this->paginate)
106
            ->with('t', $this->texts)
107
            ->with('htmlFilters', $this->htmlFilters)
108
            ->with('listDisplay', $this->listDisplay)
109
            ->with('links', $this->prepareLinks())
110
            ->with('request', $request)
111
            ->with('route', $this->route);
112
    }
113
114 View Code Duplication
    public function show($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        if (!$this->entityInstance) {
117
            $this->entityInstance = $this->entity->findOrFail($id);
118
        }
119
120
        $this->prepareFields();
121
122
        return view('crud::show')
123
            ->with('type', 'show')
124
            ->with('route', $this->route)
125
            ->with('t', $this->texts)
126
            ->with('fields', $this->fields)
127
            ->with('formColsClasses', $this->formColsClasses)
128
            ->with('data', $this->entityInstance);
129
    }
130
131
    public function create()
132
    {
133
        $this->prepareFields();
134
135
        return view('crud::create')
136
            ->with('type', 'create')
137
            ->with('route', $this->route)
138
            ->with('t', $this->texts)
139
            ->with('formColsClasses', $this->formColsClasses)
140
            ->with('links', $this->prepareLinks())
141
            ->with('fields', $this->fields);
142
    }
143
144
    protected function manageFiles($row, $request)
145
    {
146
        foreach ($this->fields as $fieldName => $field) {
147
            if ($field['type'] === 'file' && $request->file($fieldName)) {
148
                $row->addMedia($request->file($fieldName))
149
                    ->withCustomProperties(['route' => $this->route])
150
                    ->toMediaCollection($field['media_collection']);
151
            }
152
        }
153
    }
154
155
    public function store(Request $request)
156
    {
157
        $this->validateRequest($request);
158
159
        DB::beginTransaction();
160
161
        try {
162
            $row = $this->entity->create(array_merge($request->all(), $this->queryFilters));
163
            $this->updateForeignRelations($row, $request);
164
            $this->manageFiles($row, $request);
165
        } catch (QueryException $e) {
166
            \Log::error($e);
167
            if (config('app.debug')) {
168
                throw new \Exception($e);
169
            }
170
            return redirect()
171
                ->back()
172
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
173
        }
174
175
        DB::commit();
176
177
        return redirect()
178
            ->route($this->route.'.index')
179
            ->with('success', isset($this->textsGeneral['save_action'])
180
                ? $this->textsGeneral['save_action']
181
                : trans('eliurkis::crud.save_action'));
182
    }
183
184 View Code Duplication
    public function edit($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
185
    {
186
        if (!$this->entityInstance) {
187
            $this->entityInstance = $this->entity->findOrFail($id);
188
        }
189
190
        $this->prepareFields();
191
192
        return view('crud::create')
193
            ->with('type', 'edit')
194
            ->with('route', $this->route)
195
            ->with('t', $this->texts)
196
            ->with('fields', $this->fields)
197
            ->with('formColsClasses', $this->formColsClasses)
198
            ->with('links', $this->prepareLinks())
199
            ->with('data', $this->entityInstance);
200
    }
201
202
    public function update(Request $request, $id)
203
    {
204
        $this->validateRequest($request);
205
206
        DB::beginTransaction();
207
208
        try {
209
            $row = $this->entity->findOrFail($id);
210
            $row->update(
211
                array_merge(
212
                    $request->all(),
213
                    $this->queryFilters
214
                )
215
            );
216
            $this->updateForeignRelations($row, $request);
217
            $this->manageFiles($row, $request);
218
        } catch (QueryException $e) {
219
            \Log::error($e);
220
            if (config('app.debug')) {
221
                throw new \Exception($e);
222
            }
223
            return redirect()
224
                ->back()
225
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
226
        }
227
228
        DB::commit();
229
230
        return redirect()
231
            ->route($this->route.'.index', $this->getParamsFilters($row))
232
            ->with('success', isset($this->textsGeneral['save_action'])
233
                ? $this->textsGeneral['save_action']
234
                : trans('eliurkis::crud.save_action'));
235
    }
236
237
    public function destroy($id)
238
    {
239
        $this->entity->destroy($id);
240
241
        return redirect()
242
            ->route($this->route.'.index')
243
            ->with('success', isset($this->textsGeneral['delete_action'])
244
                ? $this->textsGeneral['delete_action']
245
                : trans('eliurkis::crud.delete_action'));
246
    }
247
248
    /* Private Actions */
249
250
    /**
251
     * @param         $entity
252
     * @param Request $request
253
     *
254
     * @return mixed
255
     */
256
    protected function filters($entity, $request)
257
    {
258
        if ($request->query('filter')) {
259
            $filters = is_array($request->query('filter')) ? $request->query('filter') : [];
260
            foreach ($filters as $field => $value) {
261
                $entity = $entity->where($field, $value);
262
            }
263
        }
264
265
        if (count($this->queryFilters)) {
266
            foreach ($this->queryFilters as $field => $value) {
267
                if (is_array($value)) {
268
                    $entity = $entity->whereIn($field, $value);
269
                } else {
270
                    $entity = $entity->where($field, $value);
271
                }
272
            }
273
        }
274
275
        return $entity;
276
    }
277
278
    protected function htmlFilters()
279
    {
280
        $this->htmlFilters = [];
281
        if (count($this->filters)) {
282
            foreach ($this->filters as $filter) {
283
                // Build params
284
                $urlParams = \Input::query();
285
286
                // Default Value
287
                $this->fields[$filter]['config']['default_value'] = isset($urlParams['filter'][$filter])
288
                    ? $urlParams['filter'][$filter]
289
                    : null;
290
291
                // Create URL
292
                if (isset($urlParams['filter'][$filter])) {
293
                    unset($urlParams['filter'][$filter]);
294
                }
295
                $this->fields[$filter]['attributes']['data-filter-url'] = route($this->route.'.index', $urlParams)
296
                    .(count($urlParams) ? '&' : '?');
297
298
                // Create array
299
                $this->action = 'list';
300
                $this->htmlFilters[$filter] = $this->prepareField($filter);
301
            }
302
        }
303
    }
304
305
    /**
306
     * @param         $entity
307
     * @param Request $request
308
     *
309
     * @return mixed
310
     */
311
    protected function paginate($entity, $request)
312
    {
313
        $rows = $entity->paginate($this->paginate);
314
315
        if ($request->get('q') != '') {
316
            $rows->appends(['q' => $request->get('q')]);
317
        }
318
319
        if ($request->get('filter')) {
320
            foreach ($request->get('filter') as $field => $value) {
321
                $rows->appends(['filter['.$field.']' => $value]);
322
            }
323
        }
324
325
        return $rows;
326
    }
327
328
    /**
329
     * @param         $entity
330
     * @param Request $request
331
     *
332
     * @return mixed
333
     */
334
    protected function search($entity, $request)
335
    {
336
        if ($request->get('q') != '') {
337
            $searchableCols = isset($this->searchable['columns']) ? $this->searchable['columns'] : $this->searchable;
338
339
            $entity = $entity->where(function (Builder $query) use ($request, $searchableCols) {
340
                foreach ($searchableCols as $field) {
341
                    $query->orWhere($field, 'like', '%'.$request->get('q').'%');
342
                }
343
            });
344
345
            if (isset($this->searchable['joins'])) {
346
                foreach ($this->searchable['joins'] as $table => $joinFields) {
347
                    $entity = $entity->join($table, $joinFields[0], '=', $joinFields[1]);
348
                }
349
            }
350
        }
351
352
        return $entity;
353
    }
354
355
    protected function getForeignRelationsFields()
356
    {
357
        $foreignRelations = [];
358
        foreach ($this->fields as $field => $options) {
359
            if ($options['type'] === 'foreign') {
360
                $foreignRelations[] = $field;
361
            }
362
        }
363
364
        return $foreignRelations;
365
    }
366
367
    protected function getBelongToFields()
368
    {
369
        $fields = [];
370
        foreach ($this->fields as $field => $options) {
371
            if ($options['type'] === 'select' && isset($options['config']['rel'])) {
372
                $fields[] = $options['config']['rel'];
373
            }
374
        }
375
376
        return $fields;
377
    }
378
379
    /**
380
     * @param object  $row
381
     * @param Request $request
382
     */
383
    protected function updateForeignRelations($row, $request)
384
    {
385
        $foreignRelations = $this->getForeignRelationsFields();
386
387
        foreach ($foreignRelations as $foreignRelation) {
388
            $values = $request->get($foreignRelation);
389
            $row->$foreignRelation()->sync((array) $values);
390
        }
391
    }
392
393
    protected function getParamsFilters($row)
394
    {
395
        $params = [];
396
397
        if (count($this->filterRequire)) {
398
            $params['filter'] = [];
399
400
            foreach ($this->filterRequire as $field) {
401
                $params['filter'][$field] = $row->$field;
402
            }
403
        }
404
405
        return $params;
406
    }
407
408
    protected function prepareLinks()
409
    {
410
        $links = ['index', 'create', 'store'];
411
412
        foreach ($links as $link) {
413
            if (!isset($this->links[$link]) && Route::has($this->route.'.'.$link)) {
414
                $this->links[$link] = route($this->route.'.'.$link);
415
            }
416
        }
417
418
        return $this->links;
419
    }
420
421
    /**
422
     * @param Request $request
423
     */
424
    protected function validateRequest($request)
425
    {
426
        $validations = [
427
            'rules'            => [],
428
            'messages'         => [],
429
            'customAttributes' => [],
430
        ];
431
432
        foreach ($this->fields as $field => $options) {
433
            if (isset($options['validation'])) {
434
                $validations['rules'][$field] = $options['validation'];
435
                $validations['customAttributes'][$field] = $options['label'];
436
            }
437
        }
438
439
        if ($validations['rules']) {
440
            $this->validate(
441
                $request,
442
                $validations['rules'],
443
                $validations['messages'],
444
                $validations['customAttributes']
445
            );
446
        }
447
    }
448
449
    protected function prepareRelationalFields($name)
450
    {
451
        // Default values
452
        $config = isset($this->fields[$name]['config']) ? $this->fields[$name]['config'] : [];
453
        $config['options'] = isset($config['options']) ? $config['options'] : [];
454
        $config['cols'] = isset($config['cols']) ? $config['cols'] : 1;
455
456
        // Get foreign values
457
        if (!count($config['options']) && isset($config['entity'])) {
458
            $config['options'] = $config['entity']::get()
459
                ->pluck($config['field_value'], $config['field_key'])
460
                ->toArray();
461
        }
462
463
        // No selection for filters
464
        if ($this->action == 'list' && isset($config['filter_no_selection'])) {
465
            $config['options'] = array_merge([
466
                '-1' => $config['filter_no_selection'],
467
            ], $config['options']);
468
        }
469
470
        if (isset($config['pre_options'])) {
471
            $config['options'] = $config['pre_options'] + $config['options'];
472
        }
473
474
        $this->fields[$name]['config'] = $config;
475
476
        return $this->fields[$name];
477
    }
478
479
    protected function prepareFields()
480
    {
481
        if ($this->entityInstance) {
482
            \Form::model($this->entityInstance);
483
        }
484
485
        foreach ($this->fields as $name => $properties) {
486
            $this->fields[$name]['html'] = $this->prepareField($name, $properties);
487
            $this->fields[$name]['value'] = $this->entityInstance->$name ?? null;
488
            $this->fields[$name]['value_text'] = $this->prepareFieldShow($name, $properties);
489
        }
490
491
        return $this->fields;
492
    }
493
494
    protected function prepareFieldShow($name, $properties = [])
495
    {
496
        // Init
497
        if (empty($properties)) {
498
            $properties = $this->fields[$name];
499
        }
500
501
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
502
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
503
        $config = $this->fields[$name]['config'];
504
505
        $value = $this->entityInstance
506
            ? ($this->entityInstance->$name ?? null)
507
            : (isset($config['default_value']) ? $config['default_value'] : null);
508
509
        if ($this->entityInstance) {
510
            if (isset($config['entity'])) {
511
                $value = isset($this->entityInstance->{$config['rel']}->{$config['field_value']})
512
                    ? $this->entityInstance->{$config['rel']}->{$config['field_value']}
513
                    : null;
514
            } elseif (isset($config['options']) && count($config['options'])) {
515
                $value = $config['options'][$value] ?? null;
516
            }
517
        }
518
519
        return empty($value) ? 'N/A' : $value;
520
    }
521
522
    protected function prepareField($name, $properties = [])
523
    {
524
        // Init
525
        if (empty($properties)) {
526
            $properties = $this->fields[$name];
527
        }
528
529
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
530
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
531
        $this->fields[$name]['attributes']['class'] = 'form-control';
532
        $this->fields[$name]['html'] = null;
533
534
        $config = $this->fields[$name]['config'];
535
536
        $value = $this->entityInstance
537
            ? $this->entityInstance->$name
538
            : (isset($config['default_value']) ? $config['default_value'] : null);
539
540
        // Define field type class namespace
541
        $className = '\Eliurkis\Crud\FieldTypes\\'.ucfirst($properties['type']);
542
        if (!class_exists($className)) {
543
            return;
544
        }
545
546
        if ($properties['type'] == 'foreign' || $properties['type'] == 'select') {
547
            $properties = $this->prepareRelationalFields($name);
548
549
            if ($properties['type'] == 'foreign' && $this->entityInstance) {
550
                $value = $this->entityInstance->{$config['rel']}->pluck($config['field_key'])->toArray();
551
            }
552
553
            if ($properties['type'] == 'select') {
554
                $properties['attributes']['class'] = 'form-control chosen-select-width';
555
            }
556
557
            return $className::prepare(
558
                $name,
559
                $properties['config']['options'],
560
                $value,
561
                $properties
562
            );
563
        }
564
565
        return $className::prepare(
566
            $name,
567
            $value,
568
            $this->fields[$name]
569
        );
570
    }
571
}
572