Completed
Push — master ( 79a5bc...179d47 )
by Eliurkis
04:36 queued 02:39
created

CrudController::update()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 29
rs 8.8571
cc 3
eloc 20
nc 4
nop 2
1
<?php
2
3
namespace Eliurkis\Crud;
4
5
use DB;
6
use Illuminate\Http\Request;
7
use App\Http\Controllers\Controller;
8
use Illuminate\Database\QueryException;
9
use Illuminate\Database\Eloquent\Builder;
10
11
class CrudController extends Controller
12
{
13
    protected $route;
14
    protected $entity;
15
    protected $entityInstance = null;
16
    protected $fields = [];
17
    protected $columns = [];
18
    protected $buttons = [
19
        'create',
20
        'edit',
21
        'delete',
22
    ];
23
    protected $paginate = null;
24
    protected $searchable = [];
25
    protected $filters = [];
26
    protected $queryFilters = [];
27
    protected $filterRequire = [];
28
    protected $textsGeneral = [
29
        'list_title'   => 'Contents',
30
        'create_title' => '',
31
        'edit_title'   => '',
32
    ];
33
    protected $texts = [];
34
    protected $htmlFilters = [];
35
    protected $action = null;
36
    protected $formColsClasses = [
37
        'col-md-10 col-md-offset-1',
38
        'col-md-2',
39
        'col-md-10',
40
    ];
41
    protected $links = [];
42
43
    public function __construct($entity, $config = [])
44
    {
45
        $this->entity = $entity;
46
47
        $config = count($config) ? $config : config('crud.'.$this->route);
48
49
        foreach ($config as $key => $value) {
50
            $this->$key = $value;
51
        }
52
    }
53
54
    public function index(Request $request)
55
    {
56
        $entity = $this->entity;
57
58
        // Relation Fields
59
        $belongToFields = $this->getBelongToFields();
60
        if (count($belongToFields)) {
61
            $entity = $this->entity->with($belongToFields);
62
        }
63
64
        // Filters
65
        $entity = $this->filters($entity, $request);
66
67
        // Search
68
        $entity = $this->search($entity, $request);
69
70
        // Pagination
71
        $rows = $this->paginate > 0 ? $this->paginate($entity, $request) : $entity->get();
72
73
        // HTML Filters
74
        $this->htmlFilters();
75
76
        return view('crud::list', compact('rows'))
77
            ->with('fields', $this->fields)
78
            ->with('columns', $this->columns)
79
            ->with('searchable', $this->searchable)
80
            ->with('buttons', $this->buttons)
81
            ->with('paginate', $this->paginate)
82
            ->with('t', $this->texts)
83
            ->with('htmlFilters', $this->htmlFilters)
84
            ->with('links', $this->prepareLinks())
85
            ->with('request', $request)
86
            ->with('route', $this->route);
87
    }
88
89
    public function create()
90
    {
91
        $this->prepareFields();
92
93
        return view('crud::create')
94
            ->with('type', 'create')
95
            ->with('route', $this->route)
96
            ->with('t', $this->texts)
97
            ->with('formColsClasses', $this->formColsClasses)
98
            ->with('links', $this->prepareLinks())
99
            ->with('fields', $this->fields);
100
    }
101
102
    public function store(Request $request)
103
    {
104
        $this->validateRequest($request);
105
106
        DB::beginTransaction();
107
108
        try {
109
            $row = $this->entity->create(array_merge($request->all(), $this->queryFilters));
110
            $this->updateForeignRelations($row, $request);
111
        } catch (QueryException $e) {
112
            return redirect()
113
                ->back()
114
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
115
        }
116
117
        DB::commit();
118
119
        return redirect()
120
            ->route($this->route.'.index')
121
            ->with('success', isset($this->textsGeneral['save_action'])
122
                ? $this->textsGeneral['save_action']
123
                : trans('eliurkis::crud.save_action'));
124
    }
125
126
    public function edit($id)
127
    {
128
        if (! $this->entityInstance) {
129
            $this->entityInstance = $this->entity->findOrFail($id);
130
        }
131
132
        $this->prepareFields();
133
134
        return view('crud::create')
135
            ->with('type', 'edit')
136
            ->with('route', $this->route)
137
            ->with('t', $this->texts)
138
            ->with('fields', $this->fields)
139
            ->with('formColsClasses', $this->formColsClasses)
140
            ->with('links', $this->prepareLinks())
141
            ->with('data', $this->entityInstance);
142
    }
143
144
    public function update(Request $request, $id)
145
    {
146
        $this->validateRequest($request);
147
148
        DB::beginTransaction();
149
150
        try {
151
            $row = $this->entity->findOrFail($id);
152
            $row->update(
153
                array_merge(
154
                    $request->all(),
155
                    $this->queryFilters
156
                )
157
            );
158
            $this->updateForeignRelations($row, $request);
159
        } catch (QueryException $e) {
160
            return redirect()
161
                ->back()
162
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
163
        }
164
165
        DB::commit();
166
167
        return redirect()
168
            ->route($this->route.'.index', $this->getParamsFilters($row))
169
            ->with('success', isset($this->textsGeneral['save_action'])
170
                ? $this->textsGeneral['save_action']
171
                : trans('eliurkis::crud.save_action'));
172
    }
173
174
    public function destroy($id)
175
    {
176
        $this->entity->destroy($id);
177
178
        return redirect()
179
            ->route($this->route.'.index')
180
            ->with('success', isset($this->textsGeneral['delete_action'])
181
                ? $this->textsGeneral['delete_action']
182
                : trans('eliurkis::crud.delete_action'));
183
    }
184
185
    /* Private Actions */
186
187
    /**
188
     * @param         $entity
189
     * @param Request $request
190
     *
191
     * @return mixed
192
     */
193
    protected function filters($entity, $request)
194
    {
195
        if ($request->query('filter')) {
196
            $filters = is_array($request->query('filter')) ? $request->query('filter') : [];
197
            foreach ($filters as $field => $value) {
198
                $entity = $entity->where($field, $value);
199
            }
200
        }
201
202
        if (count($this->queryFilters)) {
203
            foreach ($this->queryFilters as $field => $value) {
204
                $entity = $entity->where($field, $value);
205
            }
206
        }
207
208
        return $entity;
209
    }
210
211
    protected function htmlFilters()
212
    {
213
        $this->htmlFilters = [];
214
        if (count($this->filters)) {
215
            foreach ($this->filters as $filter) {
216
                // Build params
217
                $urlParams = \Input::query();
218
219
                // Default Value
220
                $this->fields[$filter]['config']['default_value'] = isset($urlParams['filter'][$filter])
221
                    ? $urlParams['filter'][$filter]
222
                    : null;
223
224
                // Create URL
225
                if (isset($urlParams['filter'][$filter])) {
226
                    unset($urlParams['filter'][$filter]);
227
                }
228
                $this->fields[$filter]['attributes']['data-filter-url'] = route($this->route.'.index', $urlParams)
229
                    .(count($urlParams) ? '&' : '?');
230
231
                // Create array
232
                $this->action = 'list';
233
                $this->htmlFilters[$filter] = $this->prepareField($filter);
234
            }
235
        }
236
    }
237
238
    /**
239
     * @param         $entity
240
     * @param Request $request
241
     *
242
     * @return mixed
243
     */
244
    protected function paginate($entity, $request)
245
    {
246
        $rows = $entity->paginate($this->paginate);
247
248
        if ($request->get('q') != '') {
249
            $rows->appends(['q' => $request->get('q')]);
250
        }
251
252
        if ($request->get('filter')) {
253
            foreach ($request->get('filter') as $field => $value) {
254
                $rows->appends(['filter['.$field.']' => $value]);
255
            }
256
        }
257
258
        return $rows;
259
    }
260
261
    /**
262
     * @param         $entity
263
     * @param Request $request
264
     *
265
     * @return mixed
266
     */
267
    protected function search($entity, $request)
268
    {
269
        if ($request->get('q') != '') {
270
            $searchableCols = isset($this->searchable['columns']) ? $this->searchable['columns'] : $this->searchable;
271
272
            $entity = $entity->where(function (Builder $query) use ($request, $searchableCols) {
273
                foreach ($searchableCols as $field) {
274
                    $query->orWhere($field, 'like', '%'.$request->get('q').'%');
275
                }
276
            });
277
278
            if (isset($this->searchable['joins'])) {
279
                foreach ($this->searchable['joins'] as $table => $joinFields) {
280
                    $entity = $entity->join($table, $joinFields[0], '=', $joinFields[1]);
281
                }
282
            }
283
        }
284
285
        return $entity;
286
    }
287
288
    protected function getForeignRelationsFields()
289
    {
290
        $foreignRelations = [];
291
        foreach ($this->fields as $field => $options) {
292
            if ($options['type'] === 'foreign') {
293
                $foreignRelations[] = $field;
294
            }
295
        }
296
297
        return $foreignRelations;
298
    }
299
300
    protected function getBelongToFields()
301
    {
302
        $fields = [];
303
        foreach ($this->fields as $field => $options) {
304
            if ($options['type'] === 'select' && isset($options['config']['rel'])) {
305
                $fields[] = $options['config']['rel'];
306
            }
307
        }
308
309
        return $fields;
310
    }
311
312
    /**
313
     * @param object  $row
314
     * @param Request $request
315
     */
316
    protected function updateForeignRelations($row, $request)
317
    {
318
        $foreignRelations = $this->getForeignRelationsFields();
319
320
        foreach ($foreignRelations as $foreignRelation) {
321
            $values = $request->get($foreignRelation);
322
            $row->$foreignRelation()->sync((array) $values);
323
        }
324
    }
325
326
    protected function getParamsFilters($row)
327
    {
328
        $params = [];
329
330
        if (count($this->filterRequire)) {
331
            $params['filter'] = [];
332
333
            foreach ($this->filterRequire as $field) {
334
                $params['filter'][$field] = $row->$field;
335
            }
336
        }
337
338
        return $params;
339
    }
340
341
    protected function prepareLinks()
342
    {
343
        $links = ['index', 'create', 'store'];
344
345
        foreach ($links as $link) {
346
            if (! isset($this->links[$link])) {
347
                $this->links[$link] = route($this->route.'.'.$link);
348
            }
349
        }
350
351
        return $this->links;
352
    }
353
354
    /**
355
     * @param Request $request
356
     */
357
    protected function validateRequest($request)
358
    {
359
        $validations = [
360
            'rules'            => [],
361
            'messages'         => [],
362
            'customAttributes' => [],
363
        ];
364
365
        foreach ($this->fields as $field => $options) {
366
            if (isset($options['validation'])) {
367
                $validations['rules'][$field] = $options['validation'];
368
                $validations['customAttributes'][$field] = $options['label'];
369
            }
370
        }
371
372
        if ($validations['rules']) {
373
            $this->validate(
374
                $request,
375
                $validations['rules'],
376
                $validations['messages'],
377
                $validations['customAttributes']
378
            );
379
        }
380
    }
381
382
    protected function prepareRelationalFields($name)
383
    {
384
        // Default values
385
        $config = isset($this->fields[$name]['config']) ? $this->fields[$name]['config'] : [];
386
        $config['options'] = isset($config['options']) ? $config['options'] : [];
387
        $config['cols'] = isset($config['cols']) ? $config['cols'] : 1;
388
389
        // Get foreign values
390
        if (! count($config['options']) && isset($config['entity'])) {
391
            $config['options'] = $config['entity']::get()
392
                ->lists($config['field_value'], $config['field_key'])
393
                ->toArray();
394
        }
395
396
        // No selection for filters
397
        if ($this->action == 'list' && isset($config['filter_no_selection'])) {
398
            $config['options'] = array_merge([
399
                '-1' => $config['filter_no_selection'],
400
            ], $config['options']);
401
        }
402
403
        $this->fields[$name]['config'] = $config;
404
405
        return $this->fields[$name];
406
    }
407
408
    protected function prepareFields()
409
    {
410
        if ($this->entityInstance) {
411
            \Form::model($this->entityInstance);
412
        }
413
414
        foreach ($this->fields as $name => $properties) {
415
            $this->fields[$name]['html'] = $this->prepareField($name, $properties);
416
        }
417
    }
418
419
    protected function prepareField($name, $properties = [])
420
    {
421
        // Init
422
        if (! $properties) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $properties of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
423
            $properties = $this->fields[$name];
424
        }
425
426
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
427
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
428
        $this->fields[$name]['attributes']['class'] = 'form-control';
429
        $this->fields[$name]['html'] = null;
430
431
        $config = $this->fields[$name]['config'];
432
433
        $value = $this->entityInstance
434
            ? $this->entityInstance->$name
435
            : (isset($config['default_value']) ? $config['default_value'] : null);
436
437
        // Define field type class namespace
438
        $className = '\Eliurkis\Crud\FieldTypes\\'.ucfirst($properties['type']);
439
        if (! class_exists($className)) {
440
            return;
441
        }
442
443
        if ($properties['type'] == 'foreign' || $properties['type'] == 'select') {
444
            $properties = $this->prepareRelationalFields($name);
445
446
            if ($properties['type'] == 'foreign' && $this->entityInstance) {
447
                $value = $this->entityInstance->{$config['rel']}->lists('id')->toArray();
448
            }
449
450
            if ($properties['type'] == 'select') {
451
                $properties['attributes']['class'] = 'form-control chosen-select-width';
452
            }
453
454
            return $className::prepare(
455
                $name,
456
                $properties['config']['options'],
457
                $value,
458
                $properties
459
            );
460
        }
461
462
        return $className::prepare(
463
            $name,
464
            $value,
465
            $this->fields[$name]
466
        );
467
    }
468
}
469