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 Encore\Admin\Form; |
||
4 | |||
5 | use Encore\Admin\Admin; |
||
6 | use Encore\Admin\Form; |
||
7 | use Encore\Admin\Widgets\Form as WidgetForm; |
||
8 | use Illuminate\Database\Eloquent\Model; |
||
9 | use Illuminate\Support\Arr; |
||
10 | use Illuminate\Support\Collection; |
||
11 | |||
12 | /** |
||
13 | * Class NestedForm. |
||
14 | * |
||
15 | * @method Field\Text text($column, $label = '') |
||
16 | * @method Field\Checkbox checkbox($column, $label = '') |
||
17 | * @method Field\Radio radio($column, $label = '') |
||
18 | * @method Field\Select select($column, $label = '') |
||
19 | * @method Field\MultipleSelect multipleSelect($column, $label = '') |
||
20 | * @method Field\Textarea textarea($column, $label = '') |
||
21 | * @method Field\Hidden hidden($column, $label = '') |
||
22 | * @method Field\Id id($column, $label = '') |
||
23 | * @method Field\Ip ip($column, $label = '') |
||
24 | * @method Field\Url url($column, $label = '') |
||
25 | * @method Field\Color color($column, $label = '') |
||
26 | * @method Field\Email email($column, $label = '') |
||
27 | * @method Field\Mobile mobile($column, $label = '') |
||
28 | * @method Field\Slider slider($column, $label = '') |
||
29 | * @method Field\Map map($latitude, $longitude, $label = '') |
||
30 | * @method Field\Editor editor($column, $label = '') |
||
31 | * @method Field\File file($column, $label = '') |
||
32 | * @method Field\Image image($column, $label = '') |
||
33 | * @method Field\Date date($column, $label = '') |
||
34 | * @method Field\Datetime datetime($column, $label = '') |
||
35 | * @method Field\Time time($column, $label = '') |
||
36 | * @method Field\Year year($column, $label = '') |
||
37 | * @method Field\Month month($column, $label = '') |
||
38 | * @method Field\DateRange dateRange($start, $end, $label = '') |
||
39 | * @method Field\DateTimeRange datetimeRange($start, $end, $label = '') |
||
40 | * @method Field\TimeRange timeRange($start, $end, $label = '') |
||
41 | * @method Field\Number number($column, $label = '') |
||
42 | * @method Field\Currency currency($column, $label = '') |
||
43 | * @method Field\HasMany hasMany($relationName, $callback) |
||
44 | * @method Field\SwitchField switch($column, $label = '') |
||
45 | * @method Field\Display display($column, $label = '') |
||
46 | * @method Field\Rate rate($column, $label = '') |
||
47 | * @method Field\Divide divider() |
||
48 | * @method Field\Password password($column, $label = '') |
||
49 | * @method Field\Decimal decimal($column, $label = '') |
||
50 | * @method Field\Html html($html, $label = '') |
||
51 | * @method Field\Tags tags($column, $label = '') |
||
52 | * @method Field\Icon icon($column, $label = '') |
||
53 | * @method Field\Embeds embeds($column, $label = '') |
||
54 | */ |
||
55 | class NestedForm |
||
56 | { |
||
57 | const DEFAULT_KEY_NAME = '__LA_KEY__'; |
||
58 | |||
59 | const REMOVE_FLAG_NAME = '_remove_'; |
||
60 | |||
61 | const REMOVE_FLAG_CLASS = 'fom-removed'; |
||
62 | |||
63 | /** |
||
64 | * @var mixed |
||
65 | */ |
||
66 | protected $key; |
||
67 | |||
68 | /** |
||
69 | * @var string |
||
70 | */ |
||
71 | protected $relationName; |
||
72 | |||
73 | /** |
||
74 | * NestedForm key. |
||
75 | * |
||
76 | * @var Model |
||
77 | */ |
||
78 | protected $model; |
||
79 | |||
80 | /** |
||
81 | * Fields in form. |
||
82 | * |
||
83 | * @var Collection |
||
84 | */ |
||
85 | protected $fields; |
||
86 | |||
87 | /** |
||
88 | * Original data for this field. |
||
89 | * |
||
90 | * @var array |
||
91 | */ |
||
92 | protected $original = []; |
||
93 | |||
94 | /** |
||
95 | * @var \Encore\Admin\Form|\Encore\Admin\Widgets\Form |
||
96 | */ |
||
97 | protected $form; |
||
98 | |||
99 | /** |
||
100 | * Create a new NestedForm instance. |
||
101 | * |
||
102 | * NestedForm constructor. |
||
103 | * |
||
104 | * @param string $relation |
||
105 | * @param Model $model |
||
106 | */ |
||
107 | public function __construct($relation, $model = null) |
||
108 | { |
||
109 | $this->relationName = $relation; |
||
110 | |||
111 | $this->model = $model; |
||
112 | |||
113 | $this->fields = new Collection(); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Get current model. |
||
118 | * |
||
119 | * @return Model|null |
||
120 | */ |
||
121 | public function model() |
||
122 | { |
||
123 | return $this->model; |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * Get the value of the model's primary key. |
||
128 | * |
||
129 | * @return mixed|null |
||
130 | */ |
||
131 | public function getKey() |
||
132 | { |
||
133 | if ($this->model) { |
||
134 | $key = $this->model->getKey(); |
||
135 | } |
||
136 | |||
137 | if (!is_null($this->key)) { |
||
138 | $key = $this->key; |
||
139 | } |
||
140 | |||
141 | if (isset($key)) { |
||
142 | return $key; |
||
143 | } |
||
144 | |||
145 | return 'new_'.static::DEFAULT_KEY_NAME; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Set key for current form. |
||
150 | * |
||
151 | * @param mixed $key |
||
152 | * |
||
153 | * @return $this |
||
154 | */ |
||
155 | public function setKey($key) |
||
156 | { |
||
157 | $this->key = $key; |
||
158 | |||
159 | return $this; |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * Set Form. |
||
164 | * |
||
165 | * @param Form $form |
||
166 | * |
||
167 | * @return $this |
||
168 | */ |
||
169 | public function setForm(Form $form = null) |
||
170 | { |
||
171 | $this->form = $form; |
||
172 | |||
173 | return $this; |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Set Widget/Form. |
||
178 | * |
||
179 | * @param WidgetForm $form |
||
180 | * |
||
181 | * @return $this |
||
182 | */ |
||
183 | public function setWidgetForm(WidgetForm $form = null) |
||
184 | { |
||
185 | $this->form = $form; |
||
186 | |||
187 | return $this; |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * Get form. |
||
192 | * |
||
193 | * @return Form |
||
194 | */ |
||
195 | public function getForm() |
||
196 | { |
||
197 | return $this->form; |
||
0 ignored issues
–
show
Bug
Compatibility
introduced
by
Loading history...
|
|||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Set original values for fields. |
||
202 | * |
||
203 | * @param array $data |
||
204 | * @param string $relatedKeyName |
||
205 | * |
||
206 | * @return $this |
||
207 | */ |
||
208 | public function setOriginal($data, $relatedKeyName = null) |
||
209 | { |
||
210 | if (empty($data)) { |
||
211 | return $this; |
||
212 | } |
||
213 | |||
214 | foreach ($data as $key => $value) { |
||
215 | /* |
||
216 | * like $this->original[30] = [ id = 30, .....] |
||
217 | */ |
||
218 | if ($relatedKeyName) { |
||
219 | $key = $value[$relatedKeyName]; |
||
220 | } |
||
221 | |||
222 | $this->original[$key] = $value; |
||
223 | } |
||
224 | |||
225 | return $this; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Prepare for insert or update. |
||
230 | * |
||
231 | * @param array $input |
||
232 | * |
||
233 | * @return mixed |
||
234 | */ |
||
235 | public function prepare($input) |
||
236 | { |
||
237 | foreach ($input as $key => $record) { |
||
238 | $this->setFieldOriginalValue($key); |
||
239 | $input[$key] = $this->prepareRecord($record); |
||
240 | } |
||
241 | |||
242 | return $input; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Set original data for each field. |
||
247 | * |
||
248 | * @param string $key |
||
249 | * |
||
250 | * @return void |
||
251 | */ |
||
252 | View Code Duplication | protected function setFieldOriginalValue($key) |
|
253 | { |
||
254 | $values = []; |
||
255 | if (array_key_exists($key, $this->original)) { |
||
256 | $values = $this->original[$key]; |
||
257 | } |
||
258 | |||
259 | $this->fields->each(function (Field $field) use ($values) { |
||
260 | $field->setOriginal($values); |
||
261 | }); |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Do prepare work before store and update. |
||
266 | * |
||
267 | * @param array $record |
||
268 | * |
||
269 | * @return array |
||
270 | */ |
||
271 | protected function prepareRecord($record) |
||
272 | { |
||
273 | if ($record[static::REMOVE_FLAG_NAME] == 1) { |
||
274 | return $record; |
||
275 | } |
||
276 | |||
277 | $prepared = []; |
||
278 | |||
279 | /* @var Field $field */ |
||
280 | foreach ($this->fields as $field) { |
||
281 | $columns = $field->column(); |
||
282 | |||
283 | $value = $this->fetchColumnValue($record, $columns); |
||
284 | |||
285 | if (is_null($value)) { |
||
286 | continue; |
||
287 | } |
||
288 | |||
289 | if (method_exists($field, 'prepare')) { |
||
290 | $value = $field->prepare($value); |
||
291 | } |
||
292 | |||
293 | if (($field instanceof \Encore\Admin\Form\Field\Hidden) || $value != $field->original()) { |
||
294 | View Code Duplication | if (is_array($columns)) { |
|
295 | foreach ($columns as $name => $column) { |
||
296 | Arr::set($prepared, $column, $value[$name]); |
||
297 | } |
||
298 | } elseif (is_string($columns)) { |
||
299 | Arr::set($prepared, $columns, $value); |
||
300 | } |
||
301 | } |
||
302 | } |
||
303 | |||
304 | $prepared[static::REMOVE_FLAG_NAME] = $record[static::REMOVE_FLAG_NAME]; |
||
305 | |||
306 | return $prepared; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Fetch value in input data by column name. |
||
311 | * |
||
312 | * @param array $data |
||
313 | * @param string|array $columns |
||
314 | * |
||
315 | * @return array|mixed |
||
316 | */ |
||
317 | View Code Duplication | protected function fetchColumnValue($data, $columns) |
|
318 | { |
||
319 | if (is_string($columns)) { |
||
320 | return Arr::get($data, $columns); |
||
321 | } |
||
322 | |||
323 | if (is_array($columns)) { |
||
324 | $value = []; |
||
325 | foreach ($columns as $name => $column) { |
||
326 | if (!Arr::has($data, $column)) { |
||
327 | continue; |
||
328 | } |
||
329 | $value[$name] = Arr::get($data, $column); |
||
330 | } |
||
331 | |||
332 | return $value; |
||
333 | } |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * @param Field $field |
||
338 | * |
||
339 | * @return $this |
||
340 | */ |
||
341 | public function pushField(Field $field) |
||
342 | { |
||
343 | $this->fields->push($field); |
||
344 | |||
345 | return $this; |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * Get fields of this form. |
||
350 | * |
||
351 | * @return Collection |
||
352 | */ |
||
353 | public function fields() |
||
354 | { |
||
355 | return $this->fields; |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * Fill data to all fields in form. |
||
360 | * |
||
361 | * @param array $data |
||
362 | * |
||
363 | * @return $this |
||
364 | */ |
||
365 | public function fill(array $data) |
||
366 | { |
||
367 | /* @var Field $field */ |
||
368 | foreach ($this->fields() as $field) { |
||
369 | $field->fill($data); |
||
370 | } |
||
371 | |||
372 | return $this; |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * Get the html and script of template. |
||
377 | * |
||
378 | * @return array |
||
379 | */ |
||
380 | public function getTemplateHtmlAndScript() |
||
381 | { |
||
382 | $html = ''; |
||
383 | $scripts = []; |
||
384 | |||
385 | /* @var Field $field */ |
||
386 | foreach ($this->fields() as $field) { |
||
387 | |||
388 | //when field render, will push $script to Admin |
||
389 | $html .= $field->render(); |
||
390 | |||
391 | /* |
||
392 | * Get and remove the last script of Admin::$script stack. |
||
393 | */ |
||
394 | if ($field->getScript()) { |
||
395 | $scripts[] = array_pop(Admin::$script); |
||
396 | } |
||
397 | } |
||
398 | |||
399 | return [$html, implode("\r\n", $scripts)]; |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Set `errorKey` `elementName` `elementClass` for fields inside hasmany fields. |
||
404 | * |
||
405 | * @param Field $field |
||
406 | * |
||
407 | * @return Field |
||
408 | */ |
||
409 | protected function formatField(Field $field) |
||
410 | { |
||
411 | $column = $field->column(); |
||
412 | |||
413 | $elementName = $elementClass = $errorKey = []; |
||
414 | |||
415 | $key = $this->getKey(); |
||
416 | |||
417 | if (is_array($column)) { |
||
418 | foreach ($column as $k => $name) { |
||
419 | $errorKey[$k] = sprintf('%s.%s.%s', $this->relationName, $key, $name); |
||
420 | $elementName[$k] = sprintf('%s[%s][%s]', $this->relationName, $key, $name); |
||
421 | $elementClass[$k] = [$this->relationName, $name]; |
||
422 | } |
||
423 | } else { |
||
424 | $errorKey = sprintf('%s.%s.%s', $this->relationName, $key, $column); |
||
425 | $elementName = sprintf('%s[%s][%s]', $this->relationName, $key, $column); |
||
426 | $elementClass = [$this->relationName, $column]; |
||
427 | } |
||
428 | |||
429 | return $field->setErrorKey($errorKey) |
||
430 | ->setElementName($elementName) |
||
431 | ->setElementClass($elementClass); |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * Add nested-form fields dynamically. |
||
436 | * |
||
437 | * @param string $method |
||
438 | * @param array $arguments |
||
439 | * |
||
440 | * @return mixed |
||
441 | */ |
||
442 | View Code Duplication | public function __call($method, $arguments) |
|
443 | { |
||
444 | if ($className = Form::findFieldClass($method)) { |
||
445 | $column = Arr::get($arguments, 0, ''); |
||
446 | |||
447 | /* @var Field $field */ |
||
448 | $field = new $className($column, array_slice($arguments, 1)); |
||
449 | |||
450 | if ($this->form instanceof WidgetForm) { |
||
451 | $field->setWidgetForm($this->form); |
||
452 | } else { |
||
453 | $field->setForm($this->form); |
||
454 | } |
||
455 | |||
456 | $field = $this->formatField($field); |
||
457 | |||
458 | $this->pushField($field); |
||
459 | |||
460 | return $field; |
||
461 | } |
||
462 | |||
463 | return $this; |
||
464 | } |
||
465 | } |
||
466 |