Completed
Push — master ( 522f31...df166f )
by Eliurkis
03:48 queued 01:49
created

src/CrudController.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 $orderBy = [];
28
    protected $orderByRaw = null;
29
    protected $filterRequire = [];
30
    protected $textsGeneral = [
31
        'list_title'   => 'Contents',
32
        'create_title' => '',
33
        'edit_title'   => '',
34
    ];
35
    protected $texts = [];
36
    protected $htmlFilters = [];
37
    protected $action = null;
38
    protected $formColsClasses = [
39
        'col-md-10 col-md-offset-1',
40
        'col-md-2',
41
        'col-md-10',
42
    ];
43
    protected $links = [];
44
45
    public function __construct($entity, $config = [])
46
    {
47
        $this->entity = $entity;
48
49
        $config = count($config) ? $config : config('crud.'.$this->route);
50
51
        if (is_array($config)) {
52
            foreach ($config as $key => $value) {
53
                $this->$key = $value;
54
            }
55
        }
56
    }
57
58
    public function index(Request $request)
59
    {
60
        $entity = $this->entity;
61
62
        // Relation Fields
63
        if ($belongToFields = $this->getBelongToFields()) {
64
            $entity = $this->entity->with($belongToFields);
65
        }
66
67
        // Filters
68
        $entity = $this->filters($entity, $request);
69
70
        // Search
71
        $entity = $this->search($entity, $request);
72
73
        // Order By
74
        if ($this->orderBy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->orderBy 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...
75
            foreach ($this->orderBy as $column => $direction) {
76
                $entity = $entity->orderBy($column, $direction);
77
            }
78
        }
79
80
        if ($this->orderByRaw) {
81
            $entity = $entity->orderByRaw($this->orderByRaw);
82
        }
83
84
        // Pagination
85
        $rows = $this->paginate > 0 ? $this->paginate($entity, $request) : $entity->get();
86
87
        // HTML Filters
88
        $this->htmlFilters();
89
90
        return view('crud::list', compact('rows'))
91
            ->with('fields', $this->fields)
92
            ->with('columns', $this->columns)
93
            ->with('searchable', $this->searchable)
94
            ->with('buttons', $this->buttons)
95
            ->with('paginate', $this->paginate)
96
            ->with('t', $this->texts)
97
            ->with('htmlFilters', $this->htmlFilters)
98
            ->with('links', $this->prepareLinks())
99
            ->with('request', $request)
100
            ->with('route', $this->route);
101
    }
102
103
    public function create()
104
    {
105
        $this->prepareFields();
106
107
        return view('crud::create')
108
            ->with('type', 'create')
109
            ->with('route', $this->route)
110
            ->with('t', $this->texts)
111
            ->with('formColsClasses', $this->formColsClasses)
112
            ->with('links', $this->prepareLinks())
113
            ->with('fields', $this->fields);
114
    }
115
116
    public function store(Request $request)
117
    {
118
        $this->validateRequest($request);
119
120
        DB::beginTransaction();
121
122
        try {
123
            $row = $this->entity->create(array_merge($request->all(), $this->queryFilters));
124
            $this->updateForeignRelations($row, $request);
125
        } catch (QueryException $e) {
126
            return redirect()
127
                ->back()
128
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
129
        }
130
131
        DB::commit();
132
133
        return redirect()
134
            ->route($this->route.'.index')
135
            ->with('success', isset($this->textsGeneral['save_action'])
136
                ? $this->textsGeneral['save_action']
137
                : trans('eliurkis::crud.save_action'));
138
    }
139
140
    public function edit($id)
141
    {
142
        if (! $this->entityInstance) {
143
            $this->entityInstance = $this->entity->findOrFail($id);
144
        }
145
146
        $this->prepareFields();
147
148
        return view('crud::create')
149
            ->with('type', 'edit')
150
            ->with('route', $this->route)
151
            ->with('t', $this->texts)
152
            ->with('fields', $this->fields)
153
            ->with('formColsClasses', $this->formColsClasses)
154
            ->with('links', $this->prepareLinks())
155
            ->with('data', $this->entityInstance);
156
    }
157
158
    public function update(Request $request, $id)
159
    {
160
        $this->validateRequest($request);
161
162
        DB::beginTransaction();
163
164
        try {
165
            $row = $this->entity->findOrFail($id);
166
            $row->update(
167
                array_merge(
168
                    $request->all(),
169
                    $this->queryFilters
170
                )
171
            );
172
            $this->updateForeignRelations($row, $request);
173
        } catch (QueryException $e) {
174
            return redirect()
175
                ->back()
176
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
177
        }
178
179
        DB::commit();
180
181
        return redirect()
182
            ->route($this->route.'.index', $this->getParamsFilters($row))
183
            ->with('success', isset($this->textsGeneral['save_action'])
184
                ? $this->textsGeneral['save_action']
185
                : trans('eliurkis::crud.save_action'));
186
    }
187
188
    public function destroy($id)
189
    {
190
        $this->entity->destroy($id);
191
192
        return redirect()
193
            ->route($this->route.'.index')
194
            ->with('success', isset($this->textsGeneral['delete_action'])
195
                ? $this->textsGeneral['delete_action']
196
                : trans('eliurkis::crud.delete_action'));
197
    }
198
199
    /* Private Actions */
200
201
    /**
202
     * @param         $entity
203
     * @param Request $request
204
     *
205
     * @return mixed
206
     */
207
    protected function filters($entity, $request)
208
    {
209
        if ($request->query('filter')) {
210
            $filters = is_array($request->query('filter')) ? $request->query('filter') : [];
211
            foreach ($filters as $field => $value) {
212
                $entity = $entity->where($field, $value);
213
            }
214
        }
215
216
        if (count($this->queryFilters)) {
217
            foreach ($this->queryFilters as $field => $value) {
218
                if (is_array($value)) {
219
                    $entity = $entity->whereIn($field, $value);
220
                } else {
221
                    $entity = $entity->where($field, $value);
222
                }
223
            }
224
        }
225
226
        return $entity;
227
    }
228
229
    protected function htmlFilters()
230
    {
231
        $this->htmlFilters = [];
232
        if (count($this->filters)) {
233
            foreach ($this->filters as $filter) {
234
                // Build params
235
                $urlParams = \Input::query();
236
237
                // Default Value
238
                $this->fields[$filter]['config']['default_value'] = isset($urlParams['filter'][$filter])
239
                    ? $urlParams['filter'][$filter]
240
                    : null;
241
242
                // Create URL
243
                if (isset($urlParams['filter'][$filter])) {
244
                    unset($urlParams['filter'][$filter]);
245
                }
246
                $this->fields[$filter]['attributes']['data-filter-url'] = route($this->route.'.index', $urlParams)
247
                    .(count($urlParams) ? '&' : '?');
248
249
                // Create array
250
                $this->action = 'list';
251
                $this->htmlFilters[$filter] = $this->prepareField($filter);
252
            }
253
        }
254
    }
255
256
    /**
257
     * @param         $entity
258
     * @param Request $request
259
     *
260
     * @return mixed
261
     */
262
    protected function paginate($entity, $request)
263
    {
264
        $rows = $entity->paginate($this->paginate);
265
266
        if ($request->get('q') != '') {
267
            $rows->appends(['q' => $request->get('q')]);
268
        }
269
270
        if ($request->get('filter')) {
271
            foreach ($request->get('filter') as $field => $value) {
272
                $rows->appends(['filter['.$field.']' => $value]);
273
            }
274
        }
275
276
        return $rows;
277
    }
278
279
    /**
280
     * @param         $entity
281
     * @param Request $request
282
     *
283
     * @return mixed
284
     */
285
    protected function search($entity, $request)
286
    {
287
        if ($request->get('q') != '') {
288
            $searchableCols = isset($this->searchable['columns']) ? $this->searchable['columns'] : $this->searchable;
289
290
            $entity = $entity->where(function (Builder $query) use ($request, $searchableCols) {
291
                foreach ($searchableCols as $field) {
292
                    $query->orWhere($field, 'like', '%'.$request->get('q').'%');
293
                }
294
            });
295
296
            if (isset($this->searchable['joins'])) {
297
                foreach ($this->searchable['joins'] as $table => $joinFields) {
298
                    $entity = $entity->join($table, $joinFields[0], '=', $joinFields[1]);
299
                }
300
            }
301
        }
302
303
        return $entity;
304
    }
305
306
    protected function getForeignRelationsFields()
307
    {
308
        $foreignRelations = [];
309
        foreach ($this->fields as $field => $options) {
310
            if ($options['type'] === 'foreign') {
311
                $foreignRelations[] = $field;
312
            }
313
        }
314
315
        return $foreignRelations;
316
    }
317
318
    protected function getBelongToFields()
319
    {
320
        $fields = [];
321
        foreach ($this->fields as $field => $options) {
322
            if ($options['type'] === 'select' && isset($options['config']['rel'])) {
323
                $fields[] = $options['config']['rel'];
324
            }
325
        }
326
327
        return $fields;
328
    }
329
330
    /**
331
     * @param object  $row
332
     * @param Request $request
333
     */
334
    protected function updateForeignRelations($row, $request)
335
    {
336
        $foreignRelations = $this->getForeignRelationsFields();
337
338
        foreach ($foreignRelations as $foreignRelation) {
339
            $values = $request->get($foreignRelation);
340
            $row->$foreignRelation()->sync((array) $values);
341
        }
342
    }
343
344
    protected function getParamsFilters($row)
345
    {
346
        $params = [];
347
348
        if (count($this->filterRequire)) {
349
            $params['filter'] = [];
350
351
            foreach ($this->filterRequire as $field) {
352
                $params['filter'][$field] = $row->$field;
353
            }
354
        }
355
356
        return $params;
357
    }
358
359
    protected function prepareLinks()
360
    {
361
        $links = ['index', 'create', 'store'];
362
363
        foreach ($links as $link) {
364
            if (! isset($this->links[$link])) {
365
                $this->links[$link] = route($this->route.'.'.$link);
366
            }
367
        }
368
369
        return $this->links;
370
    }
371
372
    /**
373
     * @param Request $request
374
     */
375
    protected function validateRequest($request)
376
    {
377
        $validations = [
378
            'rules'            => [],
379
            'messages'         => [],
380
            'customAttributes' => [],
381
        ];
382
383
        foreach ($this->fields as $field => $options) {
384
            if (isset($options['validation'])) {
385
                $validations['rules'][$field] = $options['validation'];
386
                $validations['customAttributes'][$field] = $options['label'];
387
            }
388
        }
389
390
        if ($validations['rules']) {
391
            $this->validate(
392
                $request,
393
                $validations['rules'],
394
                $validations['messages'],
395
                $validations['customAttributes']
396
            );
397
        }
398
    }
399
400
    protected function prepareRelationalFields($name)
401
    {
402
        // Default values
403
        $config = isset($this->fields[$name]['config']) ? $this->fields[$name]['config'] : [];
404
        $config['options'] = isset($config['options']) ? $config['options'] : [];
405
        $config['cols'] = isset($config['cols']) ? $config['cols'] : 1;
406
407
        // Get foreign values
408
        if (! count($config['options']) && isset($config['entity'])) {
409
            $config['options'] = $config['entity']::get()
410
                ->lists($config['field_value'], $config['field_key'])
411
                ->toArray();
412
        }
413
414
        // No selection for filters
415
        if ($this->action == 'list' && isset($config['filter_no_selection'])) {
416
            $config['options'] = array_merge([
417
                '-1' => $config['filter_no_selection'],
418
            ], $config['options']);
419
        }
420
421
        $this->fields[$name]['config'] = $config;
422
423
        return $this->fields[$name];
424
    }
425
426
    protected function prepareFields()
427
    {
428
        if ($this->entityInstance) {
429
            \Form::model($this->entityInstance);
430
        }
431
432
        foreach ($this->fields as $name => $properties) {
433
            $this->fields[$name]['html'] = $this->prepareField($name, $properties);
434
        }
435
    }
436
437
    protected function prepareField($name, $properties = [])
438
    {
439
        // Init
440
        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...
441
            $properties = $this->fields[$name];
442
        }
443
444
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
445
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
446
        $this->fields[$name]['attributes']['class'] = 'form-control';
447
        $this->fields[$name]['html'] = null;
448
449
        $config = $this->fields[$name]['config'];
450
451
        $value = $this->entityInstance
452
            ? $this->entityInstance->$name
453
            : (isset($config['default_value']) ? $config['default_value'] : null);
454
455
        // Define field type class namespace
456
        $className = '\Eliurkis\Crud\FieldTypes\\'.ucfirst($properties['type']);
457
        if (! class_exists($className)) {
458
            return;
459
        }
460
461
        if ($properties['type'] == 'foreign' || $properties['type'] == 'select') {
462
            $properties = $this->prepareRelationalFields($name);
463
464
            if ($properties['type'] == 'foreign' && $this->entityInstance) {
465
                $value = $this->entityInstance->{$config['rel']}->lists('id')->toArray();
466
            }
467
468
            if ($properties['type'] == 'select') {
469
                $properties['attributes']['class'] = 'form-control chosen-select-width';
470
            }
471
472
            return $className::prepare(
473
                $name,
474
                $properties['config']['options'],
475
                $value,
476
                $properties
477
            );
478
        }
479
480
        return $className::prepare(
481
            $name,
482
            $value,
483
            $this->fields[$name]
484
        );
485
    }
486
}
487