Completed
Push — master ( 83525e...66783e )
by Eliurkis
01:58
created

CrudController::manageFiles()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 14
rs 8.8571
cc 5
eloc 9
nc 4
nop 2
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\Carbon;
11
use Illuminate\Support\Facades\Route;
12
13
class CrudController extends Controller
14
{
15
    protected $route;
16
    protected $entity;
17
    protected $entityInstance = null;
18
    protected $fields = [];
19
    protected $columns = [];
20
    protected $buttons = [
21
        'show',
22
        'create',
23
        'edit',
24
        'delete',
25
    ];
26
    protected $paginate = null;
27
    protected $searchable = [];
28
    protected $filters = [];
29
    protected $queryFilters = [];
30
    protected $orderBy = [];
31
    protected $orderByRaw = null;
32
    protected $filterRequire = [];
33
    protected $textsGeneral = [
34
        'list_title'   => 'Contents',
35
        'create_title' => '',
36
        'edit_title'   => '',
37
    ];
38
    protected $texts = [];
39
    protected $htmlFilters = [];
40
    protected $action = null;
41
    protected $formColsClasses = [
42
        'col-md-10 col-md-offset-1',
43
        'col-md-2',
44
        'col-md-10',
45
    ];
46
    protected $links = [];
47
    protected $listDisplay = [
48
        'action-buttons' => true,
49
    ];
50
51
    public function __construct($entity, $config = [])
52
    {
53
        $this->entity = $entity;
54
55
        $config = count($config) ? $config : config('crud.'.$this->route);
56
57
        if (is_array($config)) {
58
            foreach ($config as $key => $value) {
59
                $this->$key = $value;
60
            }
61
        }
62
    }
63
64
    public function index(Request $request)
65
    {
66
        // If DataTable is activated
67
        if (isset($this->dataTableActivated)) {
68
            return $this->indexDataTable($request);
69
        }
70
71
        $entity = $this->entity;
72
73
        // Relation Fields
74
        if ($belongToFields = $this->getBelongToFields()) {
75
            $entity = $this->entity->with($belongToFields);
76
        }
77
78
        // Filters
79
        $entity = $this->filters($entity, $request);
80
81
        // Search
82
        $entity = $this->search($entity, $request);
83
84
        // Order By
85
        if (!empty($this->orderBy)) {
86
            foreach ($this->orderBy as $column => $direction) {
87
                $entity = $entity->orderBy($column, $direction);
88
            }
89
        }
90
91
        if ($this->orderByRaw) {
92
            $entity = $entity->orderByRaw($this->orderByRaw);
93
        }
94
95
        // Pagination
96
        $rows = $this->paginate > 0 ? $this->paginate($entity, $request) : $entity->get();
97
98
        // HTML Filters
99
        $this->htmlFilters();
100
101
        return view('crud::list', compact('rows'))
102
            ->with('fields', $this->fields)
103
            ->with('columns', $this->columns)
104
            ->with('searchable', $this->searchable)
105
            ->with('buttons', $this->buttons)
106
            ->with('paginate', $this->paginate)
107
            ->with('t', $this->texts)
108
            ->with('htmlFilters', $this->htmlFilters)
109
            ->with('listDisplay', $this->listDisplay)
110
            ->with('links', $this->prepareLinks())
111
            ->with('request', $request)
112
            ->with('route', $this->route);
113
    }
114
115 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...
116
    {
117
        if (!$this->entityInstance) {
118
            $this->entityInstance = $this->entity->findOrFail($id);
119
        }
120
121
        $this->prepareFields();
122
123
        return view('crud::show')
124
            ->with('type', 'show')
125
            ->with('route', $this->route)
126
            ->with('t', $this->texts)
127
            ->with('fields', $this->fields)
128
            ->with('formColsClasses', $this->formColsClasses)
129
            ->with('data', $this->entityInstance);
130
    }
131
132
    public function create()
133
    {
134
        $this->prepareFields();
135
136
        return view('crud::create')
137
            ->with('type', 'create')
138
            ->with('route', $this->route)
139
            ->with('t', $this->texts)
140
            ->with('formColsClasses', $this->formColsClasses)
141
            ->with('links', $this->prepareLinks())
142
            ->with('fields', $this->fields);
143
    }
144
145
    protected function manageFiles($row, $request)
146
    {
147
        foreach ($this->fields as $fieldName => $field) {
148
            if ($field['type'] === 'file' && $request->file($fieldName)) {
149
                $customProperties = ['route' => $this->route, 'field' => $fieldName];
150
                if (isset($field['storage_path'])) {
151
                    $customProperties['storage_path'] = $field['storage_path'];
152
                }
153
                $row->addMedia($request->file($fieldName))
154
                    ->withCustomProperties($customProperties)
155
                    ->toMediaCollection($fieldName);
156
            }
157
        }
158
    }
159
160
    public function store(Request $request)
161
    {
162
        $this->validateRequest($request);
163
164
        DB::beginTransaction();
165
166
        try {
167
            $row = $this->entity->create(array_merge($request->all(), $this->queryFilters));
168
            $this->updateForeignRelations($row, $request);
169
            $this->manageFiles($row, $request);
170
        } catch (QueryException $e) {
171
            \Log::error($e);
172
            if (config('app.debug')) {
173
                throw new \Exception($e);
174
            }
175
            return redirect()
176
                ->back()
177
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
178
        }
179
180
        DB::commit();
181
182
        return redirect()
183
            ->route($this->route.'.index')
184
            ->with('success', isset($this->textsGeneral['save_action'])
185
                ? $this->textsGeneral['save_action']
186
                : trans('eliurkis::crud.save_action'));
187
    }
188
189 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...
190
    {
191
        if (!$this->entityInstance) {
192
            $this->entityInstance = $this->entity->findOrFail($id);
193
        }
194
195
        $this->prepareFields();
196
197
        return view('crud::create')
198
            ->with('type', 'edit')
199
            ->with('route', $this->route)
200
            ->with('t', $this->texts)
201
            ->with('fields', $this->fields)
202
            ->with('formColsClasses', $this->formColsClasses)
203
            ->with('links', $this->prepareLinks())
204
            ->with('data', $this->entityInstance);
205
    }
206
207
    public function update(Request $request, $id)
208
    {
209
        $this->validateRequest($request);
210
211
        DB::beginTransaction();
212
213
        try {
214
            $row = $this->entity->findOrFail($id);
215
            $row->update(
216
                array_merge(
217
                    $request->all(),
218
                    $this->queryFilters
219
                )
220
            );
221
            $this->updateForeignRelations($row, $request);
222
            $this->manageFiles($row, $request);
223
        } catch (QueryException $e) {
224
            \Log::error($e);
225
            if (config('app.debug')) {
226
                throw new \Exception($e);
227
            }
228
            return redirect()
229
                ->back()
230
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
231
        }
232
233
        DB::commit();
234
235
        return redirect()
236
            ->route($this->route.'.index', $this->getParamsFilters($row))
237
            ->with('success', isset($this->textsGeneral['save_action'])
238
                ? $this->textsGeneral['save_action']
239
                : trans('eliurkis::crud.save_action'));
240
    }
241
242
    public function destroy($id)
243
    {
244
        $this->entity->destroy($id);
245
246
        return redirect()
247
            ->route($this->route.'.index')
248
            ->with('success', isset($this->textsGeneral['delete_action'])
249
                ? $this->textsGeneral['delete_action']
250
                : trans('eliurkis::crud.delete_action'));
251
    }
252
253
    public function download($id, $fieldName)
254
    {
255
        if (!$this->entityInstance) {
256
            $this->entityInstance = $this->entity->findOrFail($id);
257
        }
258
259
        $media = $this->entityInstance->getMedia($fieldName)->last();
260
261
        if ($media && $media->disk === 's3') {
262
            $tempImage = tempnam(sys_get_temp_dir(), $media->file_name);
263
            copy($media->getTemporaryUrl(\Carbon::now()->addMinutes(5)), $tempImage);
264
            return response()->file($tempImage, ['Content-Type' => $media->mime_type]);
265
        }
266
267
        return $media;
268
    }
269
270
    /* Private Actions */
271
272
    /**
273
     * @param         $entity
274
     * @param Request $request
275
     *
276
     * @return mixed
277
     */
278
    protected function filters($entity, $request)
279
    {
280
        if ($request->query('filter')) {
281
            $filters = is_array($request->query('filter')) ? $request->query('filter') : [];
282
            foreach ($filters as $field => $value) {
283
                $entity = $entity->where($field, $value);
284
            }
285
        }
286
287
        if (count($this->queryFilters)) {
288
            foreach ($this->queryFilters as $field => $value) {
289
                if (is_array($value)) {
290
                    $entity = $entity->whereIn($field, $value);
291
                } else {
292
                    $entity = $entity->where($field, $value);
293
                }
294
            }
295
        }
296
297
        return $entity;
298
    }
299
300
    protected function htmlFilters()
301
    {
302
        $this->htmlFilters = [];
303
        if (count($this->filters)) {
304
            foreach ($this->filters as $filter) {
305
                // Build params
306
                $urlParams = \Input::query();
307
308
                // Default Value
309
                $this->fields[$filter]['config']['default_value'] = isset($urlParams['filter'][$filter])
310
                    ? $urlParams['filter'][$filter]
311
                    : null;
312
313
                // Create URL
314
                if (isset($urlParams['filter'][$filter])) {
315
                    unset($urlParams['filter'][$filter]);
316
                }
317
                $this->fields[$filter]['attributes']['data-filter-url'] = route($this->route.'.index', $urlParams)
318
                    .(count($urlParams) ? '&' : '?');
319
320
                // Create array
321
                $this->action = 'list';
322
                $this->htmlFilters[$filter] = $this->prepareField($filter);
323
            }
324
        }
325
    }
326
327
    /**
328
     * @param         $entity
329
     * @param Request $request
330
     *
331
     * @return mixed
332
     */
333
    protected function paginate($entity, $request)
334
    {
335
        $rows = $entity->paginate($this->paginate);
336
337
        if ($request->get('q') != '') {
338
            $rows->appends(['q' => $request->get('q')]);
339
        }
340
341
        if ($request->get('filter')) {
342
            foreach ($request->get('filter') as $field => $value) {
343
                $rows->appends(['filter['.$field.']' => $value]);
344
            }
345
        }
346
347
        return $rows;
348
    }
349
350
    /**
351
     * @param         $entity
352
     * @param Request $request
353
     *
354
     * @return mixed
355
     */
356
    protected function search($entity, $request)
357
    {
358
        if ($request->get('q') != '') {
359
            $searchableCols = isset($this->searchable['columns']) ? $this->searchable['columns'] : $this->searchable;
360
361
            $entity = $entity->where(function (Builder $query) use ($request, $searchableCols) {
362
                foreach ($searchableCols as $field) {
363
                    $query->orWhere($field, 'like', '%'.$request->get('q').'%');
364
                }
365
            });
366
367
            if (isset($this->searchable['joins'])) {
368
                foreach ($this->searchable['joins'] as $table => $joinFields) {
369
                    $entity = $entity->join($table, $joinFields[0], '=', $joinFields[1]);
370
                }
371
            }
372
        }
373
374
        return $entity;
375
    }
376
377
    protected function getForeignRelationsFields()
378
    {
379
        $foreignRelations = [];
380
        foreach ($this->fields as $field => $options) {
381
            if ($options['type'] === 'foreign') {
382
                $foreignRelations[] = $field;
383
            }
384
        }
385
386
        return $foreignRelations;
387
    }
388
389
    protected function getBelongToFields()
390
    {
391
        $fields = [];
392
        foreach ($this->fields as $field => $options) {
393
            if ($options['type'] === 'select' && isset($options['config']['rel'])) {
394
                $fields[] = $options['config']['rel'];
395
            }
396
        }
397
398
        return $fields;
399
    }
400
401
    /**
402
     * @param object  $row
403
     * @param Request $request
404
     */
405
    protected function updateForeignRelations($row, $request)
406
    {
407
        $foreignRelations = $this->getForeignRelationsFields();
408
409
        foreach ($foreignRelations as $foreignRelation) {
410
            $values = $request->get($foreignRelation);
411
            $row->$foreignRelation()->sync((array) $values);
412
        }
413
    }
414
415
    protected function getParamsFilters($row)
416
    {
417
        $params = [];
418
419
        if (count($this->filterRequire)) {
420
            $params['filter'] = [];
421
422
            foreach ($this->filterRequire as $field) {
423
                $params['filter'][$field] = $row->$field;
424
            }
425
        }
426
427
        return $params;
428
    }
429
430
    protected function prepareLinks()
431
    {
432
        $links = ['index', 'create', 'store'];
433
434
        foreach ($links as $link) {
435
            if (!isset($this->links[$link]) && Route::has($this->route.'.'.$link)) {
436
                $this->links[$link] = route($this->route.'.'.$link);
437
            }
438
        }
439
440
        return $this->links;
441
    }
442
443
    /**
444
     * @param Request $request
445
     */
446
    protected function validateRequest($request)
447
    {
448
        $validations = [
449
            'rules'            => [],
450
            'messages'         => [],
451
            'customAttributes' => [],
452
        ];
453
454
        foreach ($this->fields as $field => $options) {
455
            if (isset($options['validation'])) {
456
                $validations['rules'][$field] = $options['validation'];
457
                $validations['customAttributes'][$field] = $options['label'];
458
            }
459
        }
460
461
        if ($validations['rules']) {
462
            $this->validate(
463
                $request,
464
                $validations['rules'],
465
                $validations['messages'],
466
                $validations['customAttributes']
467
            );
468
        }
469
    }
470
471
    protected function prepareRelationalFields($name)
472
    {
473
        // Default values
474
        $config = isset($this->fields[$name]['config']) ? $this->fields[$name]['config'] : [];
475
        $config['options'] = isset($config['options']) ? $config['options'] : [];
476
        $config['cols'] = isset($config['cols']) ? $config['cols'] : 1;
477
478
        // Get foreign values
479
        if (!count($config['options']) && isset($config['entity'])) {
480
            $config['options'] = $config['entity']::get()
481
                ->pluck($config['field_value'], $config['field_key'])
482
                ->toArray();
483
        }
484
485
        // No selection for filters
486
        if ($this->action == 'list' && isset($config['filter_no_selection'])) {
487
            $config['options'] = array_merge([
488
                '-1' => $config['filter_no_selection'],
489
            ], $config['options']);
490
        }
491
492
        if (isset($config['pre_options'])) {
493
            $config['options'] = $config['pre_options'] + $config['options'];
494
        }
495
496
        $this->fields[$name]['config'] = $config;
497
498
        return $this->fields[$name];
499
    }
500
501
    protected function prepareFields()
502
    {
503
        if ($this->entityInstance) {
504
            \Form::model($this->entityInstance);
505
        }
506
507
        foreach ($this->fields as $name => $properties) {
508
            $this->fields[$name]['html'] = $this->prepareField($name, $properties);
509
            $this->fields[$name]['value'] = $this->entityInstance->$name ?? null;
510
            $this->fields[$name]['value_text'] = $this->prepareFieldShow($name, $properties);
511
        }
512
513
        return $this->fields;
514
    }
515
516
    protected function prepareFieldShow($name, $properties = [])
517
    {
518
        // Init
519
        if (empty($properties)) {
520
            $properties = $this->fields[$name];
521
        }
522
523
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
524
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
525
        $config = $this->fields[$name]['config'];
526
527
        $value = $this->entityInstance
528
            ? ($this->entityInstance->$name ?? null)
529
            : (isset($config['default_value']) ? $config['default_value'] : null);
530
531
        if ($this->entityInstance) {
532
            if (($properties['type'] === 'date' || $properties['type'] === 'datetime') &&
533
                $this->entityInstance->$name != '') {
534
                $fieldValue = $this->entityInstance->$name;
535
536
                if (!is_object($fieldValue)) {
537
                    $fieldValue = Carbon::parse($this->entityInstance->$name);
538
                }
539
540
                $value = $fieldValue->diff(Carbon::now())->format('%y') != date('Y')
541
                    ? $fieldValue->format($properties['type'] === 'date' ? 'm/d/Y' : 'm/d/Y h:ia')
542
                    : null;
543
            }
544
545
            if ($properties['type'] === 'file' && $this->entityInstance->getMedia($name)->last()) {
546
                $value = '<a href="'.route($this->route.'.download', [$this->entityInstance->id, $name]).
547
                    '" target="_blank">'.(
548
                    isset($this->fields[$name]['link_name'])
549
                        ? $this->fields[$name]['link_name']
550
                        : 'download'
551
                    ).'</a>';
552
            }
553
554
            if (isset($config['entity'])) {
555
                $value = isset($this->entityInstance->{$config['rel']}->{$config['field_value']})
556
                    ? $this->entityInstance->{$config['rel']}->{$config['field_value']}
557
                    : null;
558
            } elseif (isset($config['options']) && count($config['options'])) {
559
                $value = $config['options'][$value] ?? null;
560
            }
561
        }
562
563
        return empty($value) ? 'N/A' : $value;
564
    }
565
566
    protected function prepareField($name, $properties = [])
567
    {
568
        // Init
569
        if (empty($properties)) {
570
            $properties = $this->fields[$name];
571
        }
572
573
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
574
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
575
        $this->fields[$name]['attributes']['class'] = 'form-control';
576
        $this->fields[$name]['html'] = null;
577
578
        $config = $this->fields[$name]['config'];
579
580
        $value = $this->entityInstance
581
            ? isset($properties['value_alias'])
582
                ? $this->entityInstance->{$properties['value_alias']}
583
                : $this->entityInstance->$name
584
            : (isset($config['default_value']) ? $config['default_value'] : null);
585
586
        // Define field type class namespace
587
        $className = '\Eliurkis\Crud\FieldTypes\\'.ucfirst($properties['type']);
588
        if (!class_exists($className)) {
589
            return;
590
        }
591
592
        if ($properties['type'] == 'foreign' || $properties['type'] == 'select') {
593
            $properties = $this->prepareRelationalFields($name);
594
595
            if ($properties['type'] == 'foreign' && $this->entityInstance) {
596
                $value = $this->entityInstance->{$config['rel']}->pluck($config['field_key'])->toArray();
597
            }
598
599
            if ($properties['type'] == 'select') {
600
                $properties['attributes']['class'] = 'form-control chosen-select-width';
601
            }
602
603
            return $className::prepare(
604
                $name,
605
                $properties['config']['options'],
606
                $value,
607
                $properties
608
            );
609
        }
610
611
        return $className::prepare(
612
            $name,
613
            $value,
614
            $this->fields[$name]
615
        );
616
    }
617
}
618