1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Anavel\Crud\Abstractor\Eloquent\Relation; |
4
|
|
|
|
5
|
|
|
use Anavel\Crud\Abstractor\Eloquent\Relation\Traits\CheckRelationCompatibility; |
6
|
|
|
use Anavel\Crud\Abstractor\Eloquent\Traits\HandleFiles; |
7
|
|
|
use Anavel\Crud\Contracts\Abstractor\Field; |
8
|
|
|
use Anavel\Crud\Contracts\Abstractor\Relation as RelationContract; |
9
|
|
|
use Illuminate\Database\Eloquent\Model; |
10
|
|
|
use Illuminate\Http\Request; |
11
|
|
|
use Illuminate\Support\Collection; |
12
|
|
|
|
13
|
|
|
class MiniCrud extends Relation |
14
|
|
|
{ |
15
|
|
|
use CheckRelationCompatibility; |
16
|
|
|
use HandleFiles; |
17
|
|
|
|
18
|
|
|
/** @var \ANavallaSuiza\Laravel\Database\Contracts\Dbal\AbstractionLayer $dbal */ |
19
|
|
|
protected $dbal; |
20
|
|
|
|
21
|
|
|
/** @var Collection */ |
22
|
|
|
protected $results; |
23
|
|
|
|
24
|
|
|
protected $compatibleEloquentRelations = [ |
25
|
|
|
'Illuminate\Database\Eloquent\Relations\HasMany', |
26
|
|
|
]; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @return Collection |
30
|
|
|
*/ |
31
|
4 |
|
protected function getResults() |
32
|
1 |
|
{ |
33
|
4 |
|
if (empty($this->results)) { |
34
|
4 |
|
return $this->results = $this->eloquentRelation->getResults(); |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
return $this->results; |
38
|
|
|
} |
39
|
|
|
|
40
|
8 |
|
public function setup() |
41
|
|
|
{ |
42
|
8 |
|
$this->checkRelationCompatibility(); |
43
|
6 |
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @return array |
47
|
|
|
*/ |
48
|
2 |
|
public function getEditFields($arrayKey = null) |
49
|
|
|
{ |
50
|
2 |
|
$fields = []; |
51
|
2 |
|
if (empty($arrayKey)) { |
52
|
2 |
|
$arrayKey = $this->name; |
53
|
2 |
|
} |
54
|
|
|
|
55
|
2 |
|
$fieldsBase = $this->getEditFieldsBase(); |
56
|
|
|
|
57
|
|
|
/** @var Collection $results */ |
58
|
2 |
|
$results = $this->getResults(); |
59
|
|
|
|
60
|
2 |
|
$results->put('emptyResult', ''); |
61
|
2 |
|
if (!empty($fieldsBase)) { |
62
|
2 |
|
foreach ($results as $key => $result) { |
63
|
2 |
|
$tempFields = []; |
64
|
2 |
|
$index = $key === 'emptyResult' ? 0 : $result->id; |
65
|
|
|
|
66
|
2 |
|
foreach ($fieldsBase as $columnName => $fieldBase) { |
67
|
2 |
|
$field = clone $fieldBase; |
68
|
2 |
|
if ($this->skipField($columnName, $key)) { |
69
|
|
|
continue; |
70
|
|
|
} |
71
|
|
|
|
72
|
2 |
|
if ($columnName != '__delete') { |
73
|
2 |
|
if ($key !== 'emptyResult') { |
74
|
2 |
|
$field->setValue($result->getAttribute($columnName)); |
75
|
2 |
|
} |
76
|
2 |
|
} elseif ($key === 'emptyResult') { |
77
|
2 |
|
continue; |
78
|
|
|
} |
79
|
2 |
|
$tempFields[$columnName] = $field; |
80
|
2 |
|
} |
81
|
|
|
|
82
|
2 |
|
$relationModel = $this->eloquentRelation->getRelated()->newInstance(); |
83
|
2 |
|
if (!empty($result)) { |
84
|
2 |
|
$relationModel = $result; |
85
|
2 |
|
} |
86
|
|
|
|
87
|
2 |
|
$this->modelAbstractor->setInstance($relationModel); |
88
|
2 |
|
$secondaryRelations = $this->getSecondaryRelations(); |
89
|
|
|
|
90
|
2 |
|
if (!empty($secondaryRelations)) { |
91
|
2 |
|
foreach ($secondaryRelations as $secondaryRelationKey => $secondaryRelation) { |
92
|
2 |
|
foreach ($secondaryRelation->getEditFields($secondaryRelationKey) as $editGroupName => $editGroup) { |
93
|
|
|
if ($secondaryRelation->getType() === 'Anavel\Crud\Abstractor\Eloquent\Relation\Select') { |
94
|
|
|
$tempFields[$editGroup[key($editGroup)]->getName()] = $editGroup[key($editGroup)]; |
95
|
|
|
} else { |
96
|
|
|
$tempFields[$editGroupName] = $editGroup; |
97
|
|
|
} |
98
|
2 |
|
} |
99
|
2 |
|
} |
100
|
2 |
|
} |
101
|
|
|
|
102
|
2 |
|
$fields[$arrayKey][$index] = $tempFields; |
103
|
2 |
|
} |
104
|
2 |
|
} |
105
|
|
|
|
106
|
2 |
|
return $fields; |
107
|
|
|
} |
108
|
|
|
|
109
|
4 |
|
public function getEditFieldsBase() |
110
|
|
|
{ |
111
|
4 |
|
$fields = []; |
112
|
4 |
|
$columns = $this->modelAbstractor->getColumns('edit'); |
113
|
4 |
|
$this->readConfig('edit'); |
114
|
|
|
|
115
|
4 |
|
if (!empty($columns)) { |
116
|
4 |
|
$readOnly = [Model::CREATED_AT, Model::UPDATED_AT, 'deleted_at']; |
117
|
|
|
|
118
|
|
|
//Add field for model deletion |
119
|
|
|
$config = [ |
120
|
4 |
|
'name' => '__delete', |
121
|
4 |
|
'presentation' => 'Delete', |
122
|
4 |
|
'form_type' => 'checkbox', |
123
|
4 |
|
'no_validate' => true, |
124
|
4 |
|
'validation' => null, |
125
|
4 |
|
'functions' => null, |
126
|
4 |
|
]; |
127
|
|
|
|
128
|
|
|
/** @var Field $field */ |
129
|
4 |
|
$field = $this->fieldFactory |
130
|
4 |
|
->setColumn($columns[key($columns)]) //Set any column, we are not really using it |
131
|
4 |
|
->setConfig($config) |
132
|
4 |
|
->get(); |
133
|
4 |
|
$fields['__delete'] = $field; |
134
|
|
|
|
135
|
4 |
|
foreach ($columns as $columnName => $column) { |
136
|
4 |
|
if (in_array($columnName, $readOnly, true)) { |
137
|
|
|
continue; |
138
|
|
|
} |
139
|
|
|
|
140
|
4 |
|
$formType = null; |
141
|
4 |
|
if ($columnName === $this->eloquentRelation->getParent()->getKeyName()) { |
142
|
|
|
$formType = 'hidden'; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
$config = [ |
146
|
4 |
|
'name' => $columnName, |
147
|
4 |
|
'presentation' => $this->name.' '.ucfirst(transcrud($columnName)), |
148
|
4 |
|
'form_type' => $formType, |
149
|
4 |
|
'no_validate' => true, |
150
|
4 |
|
'validation' => null, |
151
|
4 |
|
'functions' => null, |
152
|
4 |
|
]; |
153
|
|
|
|
154
|
4 |
|
$config = $this->setConfig($config, $columnName); |
155
|
|
|
|
156
|
|
|
/** @var Field $field */ |
157
|
4 |
|
$field = $this->fieldFactory |
158
|
4 |
|
->setColumn($column) |
159
|
4 |
|
->setConfig($config) |
160
|
4 |
|
->get(); |
161
|
|
|
|
162
|
4 |
|
$fields[$columnName] = $field; |
163
|
|
|
|
164
|
4 |
View Code Duplication |
if (!empty($config['form_type']) && $config['form_type'] === 'file') { |
|
|
|
|
165
|
|
|
$field = $this->fieldFactory |
166
|
|
|
->setColumn($column) |
167
|
|
|
->setConfig([ |
168
|
|
|
'name' => $columnName.'__delete', |
169
|
|
|
'presentation' => null, |
170
|
|
|
'form_type' => 'checkbox', |
171
|
|
|
'no_validate' => true, |
172
|
|
|
'validation' => null, |
173
|
|
|
'functions' => null, |
174
|
|
|
]) |
175
|
|
|
->get(); |
176
|
|
|
$fields[$columnName.'__delete'] = $field; |
177
|
|
|
} |
178
|
4 |
|
} |
179
|
4 |
|
} |
180
|
|
|
|
181
|
4 |
|
return $fields; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @param array|null $relationArray |
186
|
|
|
* |
187
|
|
|
* @return mixed |
188
|
|
|
*/ |
189
|
2 |
|
public function persist(array $relationArray = null, Request $request) |
190
|
|
|
{ |
191
|
2 |
|
if (!empty($relationArray)) { |
192
|
2 |
|
$keyName = $this->eloquentRelation->getParent()->getKeyName(); |
193
|
2 |
|
$currentRelations = $this->getResults()->keyBy($keyName); |
194
|
|
|
|
195
|
2 |
|
$this->readConfig('edit'); |
196
|
2 |
|
$fieldsBase = $this->getEditFieldsBase(); |
197
|
|
|
|
198
|
2 |
|
foreach ($relationArray as $relationIndex => &$relation) { |
199
|
2 |
|
if (!empty($relation[$keyName]) |
200
|
2 |
|
&& ($currentRelations->has($relation[$keyName])) |
201
|
2 |
|
) { |
202
|
|
|
$relationModel = $currentRelations->get($relation[$keyName]); |
203
|
|
|
} else { |
204
|
2 |
|
$relationModel = $this->eloquentRelation->getRelated()->newInstance(); |
205
|
|
|
} |
206
|
|
|
|
207
|
2 |
|
$this->modelAbstractor->setInstance($relationModel); |
208
|
2 |
|
$secondaryRelations = $this->getSecondaryRelations(); |
209
|
|
|
|
210
|
2 |
|
$this->setKeys($relationModel); |
211
|
|
|
|
212
|
2 |
|
$shouldBeSkipped = true; |
213
|
2 |
|
$delayedRelations = collect(); |
214
|
|
|
|
215
|
2 |
|
$skip = null; |
216
|
2 |
|
foreach ($fieldsBase as $fieldBaseKey => $field) { |
217
|
2 |
|
$fieldName = $field->getName(); |
218
|
|
|
|
219
|
2 |
|
if (get_class($field->getFormField()) === \FormManager\Fields\File::class) { |
220
|
|
|
$handleResult = $this->handleField($request, $relationModel, $fieldsBase, |
221
|
|
|
$this->name.".$relationIndex", $fieldName, $this->modelAbstractor->mustDeleteFilesInFilesystem()); |
222
|
|
|
if (!empty($handleResult['skip'])) { |
223
|
|
|
$skip = $handleResult['skip']; |
224
|
|
|
unset($relationArray[$relationIndex][$skip]); |
225
|
|
|
} |
226
|
|
|
if (!empty($handleResult['requestValue'])) { |
227
|
|
|
$relationArray[$relationIndex][$fieldName] = $handleResult['requestValue']; |
228
|
|
|
} |
229
|
|
|
} |
230
|
|
|
|
231
|
2 |
|
if ($fieldName !== '__delete' && ($fieldName != $skip && (get_class($field->getFormField()) === \FormManager\Fields\Checkbox::class))) { |
232
|
|
|
if (empty($relationArray[$relationIndex][$fieldName])) { |
233
|
|
|
// Unchecked checkboxes are not sent, so we force setting them to false |
234
|
|
|
$relationModel->setAttribute($fieldName, null); |
235
|
|
|
} else { |
236
|
|
|
$relationArray[$relationIndex][$fieldName] = true; |
237
|
|
|
} |
238
|
|
|
} |
239
|
2 |
|
} |
240
|
|
|
|
241
|
2 |
|
foreach ($relation as $fieldKey => $fieldValue) { |
242
|
2 |
|
if ($secondaryRelations->has($fieldKey)) { |
243
|
1 |
|
$delayedRelations->put($fieldKey, $fieldValue); |
244
|
1 |
|
continue; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
// This field can only come from existing models |
248
|
2 |
|
if ($fieldKey === '__delete') { |
249
|
|
|
$relationModel->delete(); |
250
|
|
|
$shouldBeSkipped = true; |
251
|
|
|
break; |
252
|
|
|
} |
253
|
|
|
|
254
|
2 |
|
if ($shouldBeSkipped) { |
255
|
2 |
|
$shouldBeSkipped = ($shouldBeSkipped === ($fieldValue === '')); |
256
|
2 |
|
} |
257
|
|
|
|
258
|
2 |
|
$relationModel->setAttribute($fieldKey, $fieldValue); |
259
|
2 |
|
} |
260
|
|
|
|
261
|
2 |
|
if (!$shouldBeSkipped) { |
262
|
2 |
|
$relationModel->save(); |
263
|
|
|
|
264
|
2 |
|
if (!$delayedRelations->isEmpty()) { |
265
|
1 |
|
foreach ($delayedRelations as $relationKey => $delayedRelation) { |
266
|
|
|
/** @var RelationContract $secondaryRelation */ |
267
|
1 |
|
$secondaryRelation = $secondaryRelations->get($relationKey); |
268
|
|
|
|
269
|
1 |
|
$secondaryRelation->persist($delayedRelation, $request); |
270
|
1 |
|
} |
271
|
1 |
|
} |
272
|
2 |
|
} |
273
|
2 |
|
} |
274
|
2 |
|
} |
275
|
2 |
|
} |
276
|
|
|
|
277
|
1 |
|
protected function setKeys(Model $relationModel) |
278
|
|
|
{ |
279
|
1 |
|
$relationModel->setAttribute($this->eloquentRelation->getForeignKey(), $this->relatedModel->id); |
280
|
1 |
|
} |
281
|
|
|
|
282
|
1 |
View Code Duplication |
protected function skipField($columnName, $key) |
|
|
|
|
283
|
|
|
{ |
284
|
1 |
|
if ($columnName === $this->eloquentRelation->getPlainForeignKey()) { |
285
|
|
|
return true; |
286
|
|
|
} |
287
|
|
|
|
288
|
1 |
|
if ($key === 'emptyResult' && ($columnName === $this->eloquentRelation->getParent()->getKeyName())) { |
289
|
|
|
return true; |
290
|
|
|
} |
291
|
|
|
|
292
|
1 |
|
return false; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* @return string |
297
|
|
|
*/ |
298
|
|
|
public function getDisplayType() |
299
|
|
|
{ |
300
|
|
|
return self::DISPLAY_TYPE_TAB; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* @param array $fields |
305
|
|
|
* |
306
|
|
|
* @return array |
307
|
|
|
*/ |
308
|
|
|
public function addSecondaryRelationFields(array $fields) |
309
|
|
|
{ |
310
|
|
|
$tempFields = []; |
311
|
|
|
foreach ($this->getSecondaryRelations() as $relationKey => $relation) { |
312
|
|
|
foreach ($relation->getEditFields($relationKey) as $editGroupName => $editGroup) { |
313
|
|
|
if ($relation->getType() === 'Anavel\Crud\Abstractor\Eloquent\Relation\Select') { |
314
|
|
|
$tempFields[key($editGroup)] = $editGroup[key($editGroup)]; |
315
|
|
|
} else { |
316
|
|
|
$tempFields[$editGroupName] = $editGroup; |
317
|
|
|
} |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
foreach ($fields[$this->name] as $groupKey => $mainFields) { |
321
|
|
|
$combinedFields = array_merge($mainFields, $tempFields); |
322
|
|
|
$fields[$this->name][$groupKey] = $combinedFields; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
return $fields; |
326
|
|
|
} |
327
|
|
|
} |
328
|
|
|
|
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.