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