1
|
|
|
<?php |
2
|
|
|
namespace Anavel\Crud\Abstractor\Eloquent; |
3
|
|
|
|
4
|
|
|
use Anavel\Crud\Abstractor\Eloquent\Traits\HandleFiles; |
5
|
|
|
use Anavel\Crud\Abstractor\Eloquent\Traits\ModelFields; |
6
|
|
|
use Anavel\Crud\Contracts\Abstractor\Field as FieldContract; |
7
|
|
|
use Anavel\Crud\Contracts\Abstractor\Model as ModelAbstractorContract; |
8
|
|
|
use Anavel\Crud\Abstractor\ConfigurationReader; |
9
|
|
|
use Anavel\Crud\Contracts\Abstractor\Relation; |
10
|
|
|
use Anavel\Crud\Contracts\Abstractor\RelationFactory as RelationFactoryContract; |
11
|
|
|
use Anavel\Crud\Contracts\Abstractor\FieldFactory as FieldFactoryContract; |
12
|
|
|
use ANavallaSuiza\Laravel\Database\Contracts\Dbal\AbstractionLayer; |
13
|
|
|
use FormManager\ElementInterface; |
14
|
|
|
use Illuminate\Database\Eloquent\Model as LaravelModel; |
15
|
|
|
use App; |
16
|
|
|
use Anavel\Crud\Contracts\Form\Generator as FormGenerator; |
17
|
|
|
use Anavel\Crud\Abstractor\Exceptions\AbstractorException; |
18
|
|
|
use Illuminate\Http\Request; |
19
|
|
|
use Illuminate\Support\Collection; |
20
|
|
|
use League\Flysystem\Adapter\Local; |
21
|
|
|
use League\Flysystem\Filesystem; |
22
|
|
|
|
23
|
|
|
class Model implements ModelAbstractorContract |
24
|
|
|
{ |
25
|
|
|
use ConfigurationReader; |
26
|
|
|
use ModelFields; |
27
|
|
|
use HandleFiles; |
28
|
|
|
|
29
|
|
|
protected $dbal; |
30
|
|
|
protected $relationFactory; |
31
|
|
|
protected $fieldFactory; |
32
|
|
|
protected $generator; |
33
|
|
|
|
34
|
|
|
protected $model; |
35
|
|
|
protected $config; |
36
|
|
|
|
37
|
|
|
protected $slug; |
38
|
|
|
protected $name; |
39
|
|
|
protected $instance; |
40
|
|
|
|
41
|
17 |
|
public function __construct( |
42
|
|
|
$config, |
43
|
|
|
AbstractionLayer $dbal, |
44
|
|
|
RelationFactoryContract $relationFactory, |
45
|
|
|
FieldFactoryContract $fieldFactory, |
46
|
|
|
FormGenerator $generator |
47
|
|
|
) { |
48
|
17 |
|
if (is_array($config)) { |
49
|
17 |
|
$this->model = $config['model']; |
50
|
17 |
|
$this->config = $config; |
51
|
17 |
|
} else { |
52
|
|
|
$this->model = $config; |
53
|
|
|
$this->config = []; |
54
|
|
|
} |
55
|
|
|
|
56
|
17 |
|
$this->dbal = $dbal; |
57
|
17 |
|
$this->relationFactory = $relationFactory; |
58
|
17 |
|
$this->fieldFactory = $fieldFactory; |
59
|
17 |
|
$this->generator = $generator; |
60
|
17 |
|
} |
61
|
|
|
|
62
|
3 |
|
public function setSlug($slug) |
63
|
|
|
{ |
64
|
3 |
|
$this->slug = $slug; |
65
|
|
|
|
66
|
3 |
|
return $this; |
67
|
|
|
} |
68
|
|
|
|
69
|
2 |
|
public function setName($name) |
70
|
|
|
{ |
71
|
2 |
|
$this->name = $name; |
72
|
|
|
|
73
|
2 |
|
return $this; |
74
|
|
|
} |
75
|
|
|
|
76
|
5 |
|
public function setInstance($instance) |
77
|
|
|
{ |
78
|
5 |
|
$this->instance = $instance; |
79
|
|
|
|
80
|
5 |
|
return $this; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
public function getSlug() |
84
|
|
|
{ |
85
|
|
|
return $this->slug; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
public function getName() |
89
|
|
|
{ |
90
|
|
|
return transcrud($this->name); |
91
|
|
|
} |
92
|
|
|
|
93
|
1 |
|
public function getModel() |
94
|
|
|
{ |
95
|
1 |
|
return $this->model; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
public function getInstance() |
99
|
|
|
{ |
100
|
|
|
return $this->instance; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
public function isSoftDeletes() |
104
|
|
|
{ |
105
|
|
|
return $this->getConfigValue('soft_deletes') ? true : false; |
106
|
|
|
} |
107
|
|
|
|
108
|
8 |
|
public function getColumns($action, $withForeignKeys = false) |
109
|
|
|
{ |
110
|
8 |
|
$tableColumns = $this->dbal->getTableColumns(); |
111
|
|
|
|
112
|
8 |
|
$filteredColumns = []; |
113
|
8 |
|
foreach ($tableColumns as $name => $column) { |
114
|
8 |
|
$filteredColumns[str_replace('`', '', $name)] = $column; |
115
|
8 |
|
} |
116
|
8 |
|
$tableColumns = $filteredColumns; |
117
|
|
|
|
118
|
|
|
|
119
|
8 |
|
$foreignKeysName = []; |
120
|
8 |
|
if ($withForeignKeys === false) { |
121
|
8 |
|
$foreignKeys = $this->dbal->getTableForeignKeys(); |
122
|
|
|
|
123
|
8 |
|
foreach ($foreignKeys as $foreignKey) { |
124
|
|
|
foreach ($foreignKey->getColumns() as $columnName) { |
125
|
|
|
$foreignKeysName[] = $columnName; |
126
|
|
|
} |
127
|
8 |
|
} |
128
|
8 |
|
} |
129
|
|
|
|
130
|
8 |
|
$customDisplayedColumns = $this->getConfigValue($action, 'display'); |
131
|
8 |
|
$customHiddenColumns = $this->getConfigValue($action, 'hide') ? : []; |
132
|
|
|
|
133
|
8 |
|
$relations = $this->getRelations(); |
134
|
8 |
|
|
135
|
8 |
|
$columns = array(); |
136
|
8 |
|
if (! empty($customDisplayedColumns) && is_array($customDisplayedColumns)) { |
137
|
|
|
foreach ($customDisplayedColumns as $customColumn) { |
138
|
|
|
if (strpos($customColumn, '.')) { |
139
|
|
|
$customColumnRelation = explode('.', $customColumn); |
140
|
8 |
|
|
141
|
8 |
|
if (! $relations->has($customColumnRelation[0])) { |
142
|
8 |
|
throw new AbstractorException("Relation " . $customColumnRelation[0] . " not configured on " . $this->getModel()); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
$relation = $relations->get($customColumnRelation[0]); |
146
|
|
|
|
147
|
|
|
$relationColumns = $relation->getModelAbstractor()->getColumns($action); |
148
|
|
|
|
149
|
|
|
if (! array_key_exists($customColumnRelation[1], $relationColumns)) { |
150
|
|
|
throw new AbstractorException("Column " . $customColumnRelation[1] . " does not exist on relation ".$customColumnRelation[0]. " of model " . $this->getModel()); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
$columns[$customColumn] = $relationColumns[$customColumnRelation[1]]; |
154
|
|
|
} else { |
155
|
|
|
if (! array_key_exists($customColumn, $tableColumns)) { |
156
|
8 |
|
throw new AbstractorException("Column " . $customColumn . " does not exist on " . $this->getModel()); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
$columns[$customColumn] = $tableColumns[$customColumn]; |
160
|
|
|
} |
161
|
|
|
} |
162
|
4 |
|
} else { |
163
|
|
|
foreach ($tableColumns as $name => $column) { |
164
|
4 |
|
if (in_array($name, $customHiddenColumns)) { |
165
|
|
|
continue; |
166
|
4 |
|
} |
167
|
|
|
|
168
|
4 |
|
if (in_array($name, $foreignKeysName)) { |
169
|
4 |
|
continue; |
170
|
4 |
|
} |
171
|
|
|
|
172
|
|
|
$columns[$name] = $column; |
173
|
|
|
} |
174
|
4 |
|
} |
175
|
4 |
|
|
176
|
4 |
|
return $columns; |
177
|
|
|
} |
178
|
|
|
|
179
|
4 |
|
/** |
180
|
|
|
* @return \Illuminate\Support\Collection |
181
|
4 |
|
*/ |
182
|
|
|
public function getRelations() |
183
|
|
|
{ |
184
|
4 |
|
$configRelations = $this->getConfigValue('relations'); |
185
|
4 |
|
|
186
|
4 |
|
$relations = collect(); |
187
|
|
|
|
188
|
4 |
|
if (! empty($configRelations)) { |
189
|
|
|
foreach ($configRelations as $relationName => $configRelation) { |
190
|
|
|
if (is_int($relationName)) { |
191
|
4 |
|
$relationName = $configRelation; |
192
|
1 |
|
} |
193
|
1 |
|
|
194
|
1 |
|
$config = []; |
195
|
1 |
|
if ($configRelation !== $relationName) { |
196
|
1 |
|
if (! is_array($configRelation)) { |
197
|
3 |
|
$config['type'] = $configRelation; |
198
|
|
|
} else { |
199
|
|
|
$config = $configRelation; |
200
|
4 |
|
} |
201
|
4 |
|
} |
202
|
|
|
|
203
|
4 |
|
/** @var Relation $relation */ |
204
|
|
|
$relation = $this->relationFactory->setModel($this->instance) |
205
|
|
|
->setConfig($config) |
206
|
|
|
->get($relationName); |
207
|
|
|
|
208
|
|
|
$secondaryRelations = $relation->getSecondaryRelations(); |
209
|
|
|
|
210
|
|
|
|
211
|
2 |
|
if (! $secondaryRelations->isEmpty()) { |
212
|
|
|
$relations->put( |
213
|
2 |
|
$relationName, |
214
|
|
|
collect(['relation' => $relation, 'secondaryRelations' => $secondaryRelations]) |
215
|
2 |
|
); |
216
|
|
|
} else { |
217
|
2 |
|
$relations->put($relationName, $relation); |
218
|
2 |
|
} |
219
|
2 |
|
|
220
|
2 |
|
} |
221
|
2 |
|
} |
222
|
2 |
|
|
223
|
|
|
return $relations; |
224
|
|
|
} |
225
|
2 |
|
|
226
|
2 |
|
/** |
227
|
2 |
|
* @param string|null $arrayKey |
228
|
2 |
|
* @return array |
229
|
|
|
* @throws AbstractorException |
230
|
2 |
|
*/ |
231
|
|
View Code Duplication |
public function getListFields($arrayKey = 'main') |
|
|
|
|
232
|
2 |
|
{ |
233
|
2 |
|
$columns = $this->getColumns('list'); |
234
|
2 |
|
|
235
|
2 |
|
$fieldsPresentation = $this->getConfigValue('fields_presentation') ? : []; |
236
|
2 |
|
|
237
|
|
|
$fields = array(); |
238
|
2 |
|
foreach ($columns as $name => $column) { |
239
|
|
|
$presentation = null; |
240
|
|
|
if (array_key_exists($name, $fieldsPresentation)) { |
241
|
|
|
$presentation = $fieldsPresentation[$name]; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
$config = [ |
245
|
|
|
'name' => $name, |
246
|
2 |
|
'presentation' => $presentation, |
247
|
|
|
'form_type' => null, |
248
|
2 |
|
'validation' => null, |
249
|
|
|
'functions' => null |
250
|
2 |
|
]; |
251
|
|
|
|
252
|
2 |
|
$fields[$arrayKey][] = $this->fieldFactory |
253
|
2 |
|
->setColumn($column) |
254
|
2 |
|
->setConfig($config) |
255
|
2 |
|
->get(); |
256
|
2 |
|
} |
257
|
2 |
|
|
258
|
|
|
return $fields; |
259
|
|
|
} |
260
|
2 |
|
|
261
|
2 |
|
/** |
262
|
2 |
|
* @param string|null $arrayKey |
263
|
2 |
|
* @return array |
264
|
|
|
* @throws AbstractorException |
265
|
2 |
|
*/ |
266
|
|
View Code Duplication |
public function getDetailFields($arrayKey = 'main') |
|
|
|
|
267
|
2 |
|
{ |
268
|
2 |
|
$columns = $this->getColumns('detail'); |
269
|
2 |
|
|
270
|
2 |
|
$fieldsPresentation = $this->getConfigValue('fields_presentation') ? : []; |
271
|
2 |
|
|
272
|
|
|
$fields = array(); |
273
|
2 |
|
foreach ($columns as $name => $column) { |
274
|
|
|
$presentation = null; |
275
|
|
|
if (array_key_exists($name, $fieldsPresentation)) { |
276
|
|
|
$presentation = $fieldsPresentation[$name]; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
$config = [ |
280
|
|
|
'name' => $name, |
281
|
|
|
'presentation' => $presentation, |
282
|
4 |
|
'form_type' => null, |
283
|
|
|
'validation' => null, |
284
|
4 |
|
'functions' => null |
285
|
|
|
]; |
286
|
4 |
|
|
287
|
|
|
$fields[$arrayKey][] = $this->fieldFactory |
288
|
4 |
|
->setColumn($column) |
289
|
4 |
|
->setConfig($config) |
290
|
4 |
|
->get(); |
291
|
4 |
|
} |
292
|
4 |
|
|
293
|
|
|
return $fields; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
4 |
|
* @param bool|null $withForeignKeys |
298
|
4 |
|
* @param string|null $arrayKey |
299
|
4 |
|
* @return array |
300
|
4 |
|
* @throws AbstractorException |
301
|
|
|
*/ |
302
|
4 |
|
public function getEditFields($withForeignKeys = false, $arrayKey = 'main') |
303
|
|
|
{ |
304
|
4 |
|
$columns = $this->getColumns('edit', $withForeignKeys); |
|
|
|
|
305
|
|
|
|
306
|
4 |
|
$this->readConfig('edit'); |
307
|
4 |
|
|
308
|
4 |
|
$fields = array(); |
309
|
4 |
|
foreach ($columns as $name => $column) { |
310
|
|
|
if (! in_array($name, $this->getReadOnlyColumns())) { |
311
|
4 |
|
$presentation = null; |
312
|
|
|
if (array_key_exists($name, $this->fieldsPresentation)) { |
313
|
|
|
$presentation = $this->fieldsPresentation[$name]; |
314
|
|
|
} |
315
|
4 |
|
|
316
|
|
|
$config = [ |
317
|
4 |
|
'name' => $name, |
318
|
4 |
|
'presentation' => $presentation, |
319
|
4 |
|
'form_type' => null, |
320
|
4 |
|
'validation' => null, |
321
|
4 |
|
'functions' => null |
322
|
4 |
|
]; |
323
|
4 |
|
|
324
|
4 |
|
$config = $this->setConfig($config, $name); |
325
|
|
|
|
326
|
4 |
|
$field = $this->fieldFactory |
327
|
4 |
|
->setColumn($column) |
328
|
4 |
|
->setConfig($config) |
329
|
4 |
|
->get(); |
330
|
4 |
|
|
331
|
4 |
|
if (! empty($this->instance) && ! empty($this->instance->getAttribute($name))) { |
332
|
|
|
$field->setValue($this->instance->getAttribute($name)); |
333
|
4 |
|
} |
334
|
|
|
|
335
|
|
|
$fields[$arrayKey][$name] = $field; |
336
|
4 |
|
|
337
|
|
View Code Duplication |
if (! empty($config['form_type']) && $config['form_type'] === 'file') { |
|
|
|
|
338
|
4 |
|
$field = $this->fieldFactory |
339
|
|
|
->setColumn($column) |
340
|
4 |
|
->setConfig([ |
341
|
|
|
'name' => $name . '__delete', |
342
|
4 |
|
'presentation' => null, |
343
|
|
|
'form_type' => 'checkbox', |
344
|
|
|
'no_validate' => true, |
345
|
|
|
'functions' => null |
346
|
|
|
]) |
347
|
|
|
->get(); |
348
|
|
|
$fields[$arrayKey][$name . '__delete'] = $field; |
349
|
2 |
|
} |
350
|
|
|
} |
351
|
2 |
|
} |
352
|
2 |
|
|
353
|
|
|
return $fields; |
354
|
2 |
|
} |
355
|
|
|
|
356
|
|
|
protected function getReadOnlyColumns() |
357
|
|
|
{ |
358
|
|
|
$columns = [LaravelModel::CREATED_AT, LaravelModel::UPDATED_AT]; |
359
|
|
|
|
360
|
|
|
$columns[] = $this->dbal->getModel()->getKeyName(); |
361
|
1 |
|
|
362
|
|
|
return $columns; |
363
|
|
|
} |
364
|
1 |
|
|
365
|
1 |
|
/** |
366
|
|
|
* @param string $action |
367
|
|
|
* @return ElementInterface |
368
|
1 |
|
*/ |
369
|
|
|
public function getForm($action) |
370
|
|
|
{ |
371
|
|
|
$this->generator->setModelFields($this->getEditFields()); |
372
|
1 |
|
$this->generator->setRelatedModelFields($this->getRelations()); |
373
|
1 |
|
|
374
|
|
|
return $this->generator->getForm($action); |
375
|
|
|
} |
376
|
|
|
|
377
|
1 |
|
/** |
378
|
1 |
|
* @param array $requestForm |
|
|
|
|
379
|
1 |
|
* @return mixed |
380
|
|
|
*/ |
381
|
1 |
|
public function persist(Request $request) |
382
|
|
|
{ |
383
|
|
|
/** @var \ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager $modelManager */ |
384
|
|
|
$modelManager = App::make('ANavallaSuiza\Laravel\Database\Contracts\Manager\ModelManager'); |
385
|
1 |
|
if (! empty($this->instance)) { |
386
|
1 |
|
$item = $this->instance; |
387
|
|
|
} else { |
388
|
1 |
|
$item = $modelManager->getModelInstance($this->getModel()); |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
|
392
|
|
|
$fields = $this->getEditFields(true); |
393
|
|
|
if (empty($fields['main']) && $this->getRelations()->isEmpty()) { |
394
|
|
|
return; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
if (! empty($fields['main'])) { |
398
|
|
|
$skip = null; |
399
|
|
|
foreach ($fields['main'] as $key => $field) { |
400
|
1 |
|
/** @var FieldContract $field */ |
401
|
|
|
if ($skip === $key) { |
402
|
|
|
$skip = null; |
403
|
|
|
continue; |
404
|
|
|
} |
405
|
|
|
$fieldName = $field->getName(); |
406
|
|
|
$requestValue = $request->input("main.{$fieldName}"); |
407
|
|
|
|
408
|
|
|
if (get_class($field->getFormField()) === \FormManager\Fields\Checkbox::class) { |
409
|
|
|
if (empty($requestValue)) { |
410
|
|
|
// Unchecked checkboxes are not sent, so we force setting them to false |
411
|
1 |
|
$item->setAttribute( |
412
|
|
|
$fieldName, |
413
|
|
|
$field->applyFunctions(null) |
414
|
|
|
); |
415
|
1 |
|
} else { |
416
|
1 |
|
$requestValue = true; |
417
|
1 |
|
} |
418
|
1 |
|
} |
419
|
1 |
|
|
420
|
1 |
|
if (get_class($field->getFormField()) === \FormManager\Fields\File::class) { |
421
|
1 |
|
$handleResult = $this->handleField($request, $item, $fields['main'], 'main', $fieldName); |
422
|
1 |
|
if (! empty($handleResult['skip'])) { |
423
|
|
|
$skip = $handleResult['skip']; |
424
|
1 |
|
} |
425
|
|
|
if (! empty($handleResult['requestValue'])) { |
426
|
1 |
|
$requestValue = $handleResult['requestValue']; |
427
|
|
|
} |
428
|
|
|
} |
429
|
1 |
|
|
430
|
1 |
|
|
431
|
1 |
|
if (! $field->saveIfEmpty() && empty($requestValue)) { |
432
|
|
|
continue; |
433
|
|
|
} |
434
|
|
|
|
435
|
1 |
|
if (! empty($requestValue) || (empty($requestValue) && ! empty($item->getAttribute($fieldName)))) { |
436
|
|
|
$item->setAttribute( |
437
|
1 |
|
$fieldName, |
438
|
1 |
|
$field->applyFunctions($requestValue) |
439
|
|
|
); |
440
|
1 |
|
} |
441
|
|
|
} |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
$item->save(); |
445
|
|
|
|
446
|
1 |
|
$this->setInstance($item); |
447
|
|
|
|
448
|
1 |
|
|
449
|
|
|
if (! empty($relations = $this->getRelations())) { |
450
|
|
|
foreach ($relations as $relationKey => $relation) { |
451
|
|
|
if ($relation instanceof Collection) { |
452
|
|
|
$input = $request->input($relationKey); |
453
|
|
|
$relation->get('relation')->persist($input, $request); |
454
|
|
|
} else { |
455
|
|
|
$relation->persist($request->input($relationKey), $request); |
456
|
|
|
} |
457
|
|
|
} |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
return $item; |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
/** |
464
|
|
|
* @return array |
465
|
|
|
*/ |
466
|
|
|
public function getValidationRules() |
467
|
|
|
{ |
468
|
|
|
return $this->generator->getValidationRules(); |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
public function getFieldValue($item, $fieldName) |
472
|
|
|
{ |
473
|
|
|
$value = null; |
|
|
|
|
474
|
|
|
|
475
|
|
|
if (strpos($fieldName, '.')) { |
476
|
|
|
$customColumnRelation = explode('.', $fieldName); |
477
|
|
|
|
478
|
|
|
$relation = $item->$customColumnRelation[0]; |
479
|
|
|
if (empty($relation)) { |
480
|
|
|
return null; |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
if ($relation instanceof \Illuminate\Support\Collection) { |
484
|
|
|
$relations = $this->getRelations(); |
485
|
|
|
|
486
|
|
|
$relationAbstractor = $relations->get($customColumnRelation[0]); |
487
|
|
|
|
488
|
|
|
if ($relationAbstractor instanceof \Anavel\Crud\Abstractor\Eloquent\Relation\Translation) { |
489
|
|
|
$value = $item->getAttribute($customColumnRelation[1]); |
490
|
|
|
} else { |
491
|
|
|
$value = $relation->implode($customColumnRelation[1], ', '); |
492
|
|
|
} |
493
|
|
|
} else { |
494
|
|
|
$value = $relation->getAttribute($customColumnRelation[1]); |
495
|
|
|
} |
496
|
|
|
} else { |
497
|
|
|
$value = $item->getAttribute($fieldName); |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
return $value; |
501
|
|
|
} |
502
|
|
|
} |
503
|
|
|
|
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.