1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Kris\LaravelFormBuilder\Fields; |
4
|
|
|
|
5
|
|
|
use Kris\LaravelFormBuilder\Filters\Exception\FilterAlreadyBindedException; |
6
|
|
|
use Kris\LaravelFormBuilder\Filters\FilterInterface; |
7
|
|
|
use Kris\LaravelFormBuilder\Filters\FilterResolver; |
8
|
|
|
use Kris\LaravelFormBuilder\Form; |
9
|
|
|
use Kris\LaravelFormBuilder\FormHelper; |
10
|
|
|
use Kris\LaravelFormBuilder\Rules; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Class FormField |
14
|
|
|
* |
15
|
|
|
* @package Kris\LaravelFormBuilder\Fields |
16
|
|
|
*/ |
17
|
|
|
abstract class FormField |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* Name of the field. |
21
|
|
|
* |
22
|
|
|
* @var string |
23
|
|
|
*/ |
24
|
|
|
protected $name; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Type of the field. |
28
|
|
|
* |
29
|
|
|
* @var string |
30
|
|
|
*/ |
31
|
|
|
protected $type; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* All options for the field. |
35
|
|
|
* |
36
|
|
|
* @var array |
37
|
|
|
*/ |
38
|
|
|
protected $options = []; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Is field rendered. |
42
|
|
|
* |
43
|
|
|
* @var bool |
44
|
|
|
*/ |
45
|
|
|
protected $rendered = false; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var Form |
49
|
|
|
*/ |
50
|
|
|
protected $parent; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
protected $template; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var FormHelper |
59
|
|
|
*/ |
60
|
|
|
protected $formHelper; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Name of the property for value setting. |
64
|
|
|
* |
65
|
|
|
* @var string |
66
|
|
|
*/ |
67
|
|
|
protected $valueProperty = 'value'; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Name of the property for default value. |
71
|
|
|
* |
72
|
|
|
* @var string |
73
|
|
|
*/ |
74
|
|
|
protected $defaultValueProperty = 'default_value'; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Is default value set? |
78
|
|
|
* |
79
|
|
|
* @var bool|false |
80
|
|
|
*/ |
81
|
|
|
protected $hasDefault = false; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* @var \Closure|null |
85
|
|
|
*/ |
86
|
|
|
protected $valueClosure = null; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Array of filters key(alias/name) => objects. |
90
|
|
|
* |
91
|
|
|
* @var array |
92
|
|
|
*/ |
93
|
|
|
protected $filters = []; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Raw/unfiltered field value. |
97
|
|
|
* |
98
|
|
|
* @var mixed $rawValues |
99
|
|
|
*/ |
100
|
|
|
protected $rawValue; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Override filters with same alias/name for field. |
104
|
|
|
* |
105
|
|
|
* @var bool |
106
|
|
|
*/ |
107
|
|
|
protected $filtersOverride = false; |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* @param string $name |
111
|
|
|
* @param string $type |
112
|
|
|
* @param Form $parent |
113
|
|
|
* @param array $options |
114
|
|
|
*/ |
115
|
101 |
|
public function __construct($name, $type, Form $parent, array $options = []) |
116
|
|
|
{ |
117
|
101 |
|
$this->name = $name; |
118
|
101 |
|
$this->type = $type; |
119
|
101 |
|
$this->parent = $parent; |
120
|
101 |
|
$this->formHelper = $this->parent->getFormHelper(); |
121
|
101 |
|
$this->setTemplate(); |
122
|
101 |
|
$this->setDefaultOptions($options); |
123
|
101 |
|
$this->setupValue(); |
124
|
96 |
|
$this->initFilters(); |
125
|
96 |
|
} |
126
|
|
|
|
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Setup the value of the form field. |
130
|
|
|
* |
131
|
|
|
* @return void |
132
|
|
|
*/ |
133
|
101 |
|
protected function setupValue() |
134
|
|
|
{ |
135
|
101 |
|
$value = $this->getOption($this->valueProperty); |
136
|
101 |
|
$isChild = $this->getOption('is_child'); |
137
|
|
|
|
138
|
101 |
|
if ($value instanceof \Closure) { |
139
|
|
|
$this->valueClosure = $value; |
140
|
|
|
} |
141
|
|
|
|
142
|
101 |
|
if (($value === null || $value instanceof \Closure) && !$isChild) { |
143
|
90 |
|
$this->setValue($this->getModelValueAttribute($this->parent->getModel(), $this->name)); |
144
|
96 |
|
} elseif (!$isChild) { |
145
|
14 |
|
$this->hasDefault = true; |
146
|
14 |
|
} |
147
|
96 |
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Get the template, can be config variable or view path. |
151
|
|
|
* |
152
|
|
|
* @return string |
153
|
|
|
*/ |
154
|
|
|
abstract protected function getTemplate(); |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @return string |
158
|
|
|
*/ |
159
|
35 |
|
protected function getViewTemplate() |
160
|
|
|
{ |
161
|
35 |
|
return $this->parent->getTemplatePrefix() . $this->getOption('template', $this->template); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Render the field. |
166
|
|
|
* |
167
|
|
|
* @param array $options |
168
|
|
|
* @param bool $showLabel |
169
|
|
|
* @param bool $showField |
170
|
|
|
* @param bool $showError |
171
|
|
|
* @return string |
172
|
|
|
*/ |
173
|
35 |
|
public function render(array $options = [], $showLabel = true, $showField = true, $showError = true) |
174
|
|
|
{ |
175
|
35 |
|
$this->prepareOptions($options); |
176
|
35 |
|
$value = $this->getValue(); |
177
|
35 |
|
$defaultValue = $this->getDefaultValue(); |
178
|
|
|
|
179
|
35 |
|
if ($showField) { |
180
|
35 |
|
$this->rendered = true; |
181
|
35 |
|
} |
182
|
|
|
|
183
|
|
|
// Override default value with value |
184
|
35 |
|
if (!$this->isValidValue($value) && $this->isValidValue($defaultValue)) { |
185
|
|
|
$this->setOption($this->valueProperty, $defaultValue); |
186
|
|
|
} |
187
|
|
|
|
188
|
35 |
|
if (!$this->needsLabel()) { |
189
|
11 |
|
$showLabel = false; |
190
|
11 |
|
} |
191
|
|
|
|
192
|
35 |
|
if ($showError) { |
193
|
34 |
|
$showError = $this->parent->haveErrorsEnabled(); |
194
|
34 |
|
} |
195
|
|
|
|
196
|
35 |
|
$data = $this->getRenderData(); |
197
|
|
|
|
198
|
35 |
|
return $this->formHelper->getView()->make( |
199
|
35 |
|
$this->getViewTemplate(), |
200
|
|
|
$data + [ |
201
|
35 |
|
'name' => $this->name, |
202
|
35 |
|
'nameKey' => $this->getNameKey(), |
203
|
35 |
|
'type' => $this->type, |
204
|
35 |
|
'options' => $this->options, |
205
|
35 |
|
'showLabel' => $showLabel, |
206
|
35 |
|
'showField' => $showField, |
207
|
35 |
|
'showError' => $showError, |
208
|
35 |
|
'errorBag' => $this->parent->getErrorBag(), |
209
|
35 |
|
'translationTemplate' => $this->parent->getTranslationTemplate(), |
210
|
|
|
] |
211
|
35 |
|
)->render(); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Return the extra render data for this form field, passed into the field's template directly. |
216
|
|
|
* |
217
|
|
|
* @return array |
218
|
|
|
*/ |
219
|
35 |
|
protected function getRenderData() { |
220
|
35 |
|
return []; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Get the attribute value from the model by name. |
225
|
|
|
* |
226
|
|
|
* @param mixed $model |
227
|
|
|
* @param string $name |
228
|
|
|
* @return mixed |
229
|
|
|
*/ |
230
|
92 |
|
protected function getModelValueAttribute($model, $name) |
231
|
|
|
{ |
232
|
92 |
|
$transformedName = $this->transformKey($name); |
233
|
92 |
|
if (is_string($model)) { |
234
|
|
|
return $model; |
235
|
92 |
|
} elseif (is_object($model)) { |
236
|
3 |
|
return object_get($model, $transformedName); |
237
|
92 |
|
} elseif (is_array($model)) { |
238
|
91 |
|
return array_get($model, $transformedName); |
239
|
|
|
} |
240
|
5 |
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Transform array like syntax to dot syntax. |
244
|
|
|
* |
245
|
|
|
* @param string $key |
246
|
|
|
* @return mixed |
247
|
|
|
*/ |
248
|
101 |
|
protected function transformKey($key) |
249
|
|
|
{ |
250
|
101 |
|
return $this->formHelper->transformToDotSyntax($key); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Prepare options for rendering. |
255
|
|
|
* |
256
|
|
|
* @param array $options |
257
|
|
|
* @return array |
258
|
|
|
*/ |
259
|
101 |
|
protected function prepareOptions(array $options = []) |
260
|
|
|
{ |
261
|
101 |
|
$helper = $this->formHelper; |
262
|
101 |
|
$rulesParser = $helper->createRulesParser($this); |
263
|
101 |
|
$rules = $this->getOption('rules'); |
264
|
101 |
|
$parsedRules = $rules ? $rulesParser->parse($rules) : []; |
265
|
|
|
|
266
|
101 |
|
$this->options = $helper->mergeOptions($this->options, $options); |
267
|
|
|
|
268
|
101 |
|
foreach (['attr', 'label_attr', 'wrapper'] as $appendable) { |
269
|
|
|
// Append values to the 'class' attribute |
270
|
101 |
|
if ($this->getOption("{$appendable}.class_append")) { |
271
|
|
|
// Combine the current class attribute with the appends |
272
|
3 |
|
$append = $this->getOption("{$appendable}.class_append"); |
273
|
3 |
|
$classAttribute = $this->getOption("{$appendable}.class", '').' '.$append; |
274
|
3 |
|
$this->setOption("{$appendable}.class", $classAttribute); |
275
|
|
|
|
276
|
|
|
// Then remove the class_append option to prevent it from showing up as an attribute in the HTML |
277
|
3 |
|
$this->setOption("{$appendable}.class_append", null); |
278
|
3 |
|
} |
279
|
101 |
|
} |
280
|
|
|
|
281
|
101 |
|
if ($this->getOption('attr.multiple') && !$this->getOption('tmp.multipleBracesSet')) { |
282
|
2 |
|
$this->name = $this->name.'[]'; |
283
|
2 |
|
$this->setOption('tmp.multipleBracesSet', true); |
284
|
2 |
|
} |
285
|
|
|
|
286
|
101 |
|
if ($this->parent->haveErrorsEnabled()) { |
287
|
101 |
|
$this->addErrorClass(); |
288
|
101 |
|
} |
289
|
|
|
|
290
|
101 |
|
if ($this->getOption('required') === true || isset($parsedRules['required'])) { |
291
|
4 |
|
$lblClass = $this->getOption('label_attr.class', ''); |
292
|
4 |
|
$requiredClass = $this->getConfig('defaults.required_class', 'required'); |
293
|
|
|
|
294
|
4 |
|
if (! str_contains($lblClass, $requiredClass)) { |
295
|
4 |
|
$lblClass .= ' '.$requiredClass; |
296
|
4 |
|
$this->setOption('label_attr.class', $lblClass); |
297
|
4 |
|
} |
298
|
|
|
|
299
|
4 |
|
if ($this->parent->clientValidationEnabled()) { |
300
|
3 |
|
$this->setOption('attr.required', 'required'); |
301
|
3 |
|
} |
302
|
4 |
|
} |
303
|
|
|
|
304
|
101 |
|
if ($this->parent->clientValidationEnabled() && $parsedRules) { |
|
|
|
|
305
|
1 |
|
$attrs = $this->getOption('attr') + $parsedRules; |
306
|
1 |
|
$this->setOption('attr', $attrs); |
307
|
1 |
|
} |
308
|
|
|
|
309
|
101 |
|
$this->setOption('wrapperAttrs', $helper->prepareAttributes($this->getOption('wrapper'))); |
310
|
101 |
|
$this->setOption('errorAttrs', $helper->prepareAttributes($this->getOption('errors'))); |
311
|
|
|
|
312
|
101 |
|
if ($this->getOption('help_block.text')) { |
313
|
1 |
|
$this->setOption( |
314
|
1 |
|
'help_block.helpBlockAttrs', |
315
|
1 |
|
$helper->prepareAttributes($this->getOption('help_block.attr')) |
316
|
1 |
|
); |
317
|
1 |
|
} |
318
|
|
|
|
319
|
101 |
|
return $this->options; |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Get name of the field. |
324
|
|
|
* |
325
|
|
|
* @return string |
326
|
|
|
*/ |
327
|
39 |
|
public function getName() |
328
|
|
|
{ |
329
|
39 |
|
return $this->name; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* Set name of the field. |
334
|
|
|
* |
335
|
|
|
* @param string $name |
336
|
|
|
* @return $this |
337
|
|
|
*/ |
338
|
12 |
|
public function setName($name) |
339
|
|
|
{ |
340
|
12 |
|
$this->name = $name; |
341
|
|
|
|
342
|
12 |
|
return $this; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Get dot notation key for fields. |
347
|
|
|
* |
348
|
|
|
* @return string |
349
|
|
|
**/ |
350
|
54 |
|
public function getNameKey() |
351
|
|
|
{ |
352
|
54 |
|
return $this->transformKey($this->name); |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Get field options. |
357
|
|
|
* |
358
|
|
|
* @return array |
359
|
|
|
*/ |
360
|
12 |
|
public function getOptions() |
361
|
|
|
{ |
362
|
12 |
|
return $this->options; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
/** |
366
|
|
|
* Get single option from options array. Can be used with dot notation ('attr.class'). |
367
|
|
|
* |
368
|
|
|
* @param string $option |
369
|
|
|
* @param mixed|null $default |
370
|
|
|
* @return mixed |
371
|
|
|
*/ |
372
|
101 |
|
public function getOption($option, $default = null) |
373
|
|
|
{ |
374
|
101 |
|
return array_get($this->options, $option, $default); |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Set field options. |
379
|
|
|
* |
380
|
|
|
* @param array $options |
381
|
|
|
* @return $this |
382
|
|
|
*/ |
383
|
12 |
|
public function setOptions($options) |
384
|
|
|
{ |
385
|
12 |
|
$this->options = $this->prepareOptions($options); |
386
|
|
|
|
387
|
12 |
|
return $this; |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
/** |
391
|
|
|
* Set single option on the field. |
392
|
|
|
* |
393
|
|
|
* @param string $name |
394
|
|
|
* @param mixed $value |
395
|
|
|
* @return $this |
396
|
|
|
*/ |
397
|
101 |
|
public function setOption($name, $value) |
398
|
|
|
{ |
399
|
101 |
|
array_set($this->options, $name, $value); |
400
|
|
|
|
401
|
101 |
|
return $this; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* Get the type of the field. |
406
|
|
|
* |
407
|
|
|
* @return string |
408
|
|
|
*/ |
409
|
65 |
|
public function getType() |
410
|
|
|
{ |
411
|
65 |
|
return $this->type; |
412
|
|
|
} |
413
|
|
|
|
414
|
|
|
/** |
415
|
|
|
* Set type of the field. |
416
|
|
|
* |
417
|
|
|
* @param mixed $type |
418
|
|
|
* @return $this |
419
|
|
|
*/ |
420
|
1 |
|
public function setType($type) |
421
|
|
|
{ |
422
|
1 |
|
if ($this->formHelper->getFieldType($type)) { |
423
|
1 |
|
$this->type = $type; |
424
|
1 |
|
} |
425
|
|
|
|
426
|
1 |
|
return $this; |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
/** |
430
|
|
|
* @return Form |
431
|
|
|
*/ |
432
|
101 |
|
public function getParent() |
433
|
|
|
{ |
434
|
101 |
|
return $this->parent; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Check if the field is rendered. |
439
|
|
|
* |
440
|
|
|
* @return bool |
441
|
|
|
*/ |
442
|
4 |
|
public function isRendered() |
443
|
|
|
{ |
444
|
4 |
|
return $this->rendered; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* Default options for field. |
449
|
|
|
* |
450
|
|
|
* @return array |
451
|
|
|
*/ |
452
|
76 |
|
protected function getDefaults() |
453
|
|
|
{ |
454
|
76 |
|
return []; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
/** |
458
|
|
|
* Defaults used across all fields. |
459
|
|
|
* |
460
|
|
|
* @return array |
461
|
|
|
*/ |
462
|
101 |
|
private function allDefaults() |
463
|
|
|
{ |
464
|
|
|
return [ |
465
|
101 |
|
'wrapper' => ['class' => $this->getConfig('defaults.wrapper_class')], |
466
|
101 |
|
'attr' => ['class' => $this->getConfig('defaults.field_class')], |
467
|
101 |
|
'help_block' => ['text' => null, 'tag' => 'p', 'attr' => [ |
468
|
101 |
|
'class' => $this->getConfig('defaults.help_block_class') |
469
|
101 |
|
]], |
470
|
101 |
|
'value' => null, |
471
|
101 |
|
'default_value' => null, |
472
|
101 |
|
'label' => null, |
473
|
101 |
|
'label_show' => true, |
474
|
101 |
|
'is_child' => false, |
475
|
101 |
|
'label_attr' => ['class' => $this->getConfig('defaults.label_class')], |
476
|
101 |
|
'errors' => ['class' => $this->getConfig('defaults.error_class')], |
477
|
101 |
|
'rules' => [], |
478
|
101 |
|
'error_messages' => [] |
479
|
101 |
|
]; |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Get real name of the field without form namespace. |
484
|
|
|
* |
485
|
|
|
* @return string |
486
|
|
|
*/ |
487
|
100 |
|
public function getRealName() |
488
|
|
|
{ |
489
|
100 |
|
return $this->getOption('real_name', $this->name); |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* @param $value |
494
|
|
|
* @return $this |
495
|
|
|
*/ |
496
|
94 |
|
public function setValue($value) |
497
|
|
|
{ |
498
|
94 |
|
if ($this->hasDefault) { |
499
|
1 |
|
return $this; |
500
|
|
|
} |
501
|
|
|
|
502
|
94 |
|
$closure = $this->valueClosure; |
503
|
|
|
|
504
|
94 |
|
if ($closure instanceof \Closure) { |
505
|
|
|
$value = $closure($value ?: null); |
506
|
|
|
} |
507
|
|
|
|
508
|
94 |
|
if (!$this->isValidValue($value)) { |
509
|
91 |
|
$value = $this->getOption($this->defaultValueProperty); |
510
|
91 |
|
} |
511
|
|
|
|
512
|
94 |
|
$this->options[$this->valueProperty] = $value; |
513
|
|
|
|
514
|
94 |
|
return $this; |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Set the template property on the object. |
519
|
|
|
* |
520
|
|
|
* @return void |
521
|
|
|
*/ |
522
|
101 |
|
private function setTemplate() |
523
|
|
|
{ |
524
|
101 |
|
$this->template = $this->getConfig($this->getTemplate(), $this->getTemplate()); |
525
|
101 |
|
} |
526
|
|
|
|
527
|
|
|
/** |
528
|
|
|
* Add error class to wrapper if validation errors exist. |
529
|
|
|
* |
530
|
|
|
* @return void |
531
|
|
|
*/ |
532
|
101 |
|
protected function addErrorClass() |
533
|
|
|
{ |
534
|
101 |
|
$errors = $this->parent->getRequest()->session()->get('errors'); |
535
|
101 |
|
$errorBag = $this->parent->getErrorBag(); |
536
|
|
|
|
537
|
101 |
|
if ($errors && $errors->hasBag($errorBag) && $errors->getBag($errorBag)->has($this->getNameKey())) { |
538
|
|
|
$fieldErrorClass = $this->getConfig('defaults.field_error_class'); |
539
|
|
|
$fieldClass = $this->getOption('attr.class'); |
540
|
|
|
|
541
|
|
|
if ($fieldErrorClass && !str_contains($fieldClass, $fieldErrorClass)) { |
542
|
|
|
$fieldClass .= ' ' . $fieldErrorClass; |
543
|
|
|
$this->setOption('attr.class', $fieldClass); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
$wrapperErrorClass = $this->getConfig('defaults.wrapper_error_class'); |
547
|
|
|
$wrapperClass = $this->getOption('wrapper.class'); |
548
|
|
|
|
549
|
|
|
if ($wrapperErrorClass && $this->getOption('wrapper') && !str_contains($wrapperClass, $wrapperErrorClass)) { |
550
|
|
|
$wrapperClass .= ' ' . $wrapperErrorClass; |
551
|
|
|
$this->setOption('wrapper.class', $wrapperClass); |
552
|
|
|
} |
553
|
|
|
} |
554
|
101 |
|
} |
555
|
|
|
|
556
|
|
|
/** |
557
|
|
|
* Merge all defaults with field specific defaults and set template if passed. |
558
|
|
|
* |
559
|
|
|
* @param array $options |
560
|
|
|
*/ |
561
|
101 |
|
protected function setDefaultOptions(array $options = []) |
562
|
|
|
{ |
563
|
101 |
|
$this->options = $this->formHelper->mergeOptions($this->allDefaults(), $this->getDefaults()); |
564
|
101 |
|
$this->options = $this->prepareOptions($options); |
565
|
|
|
|
566
|
101 |
|
$defaults = $this->setDefaultClasses($options); |
567
|
101 |
|
$this->options = $this->formHelper->mergeOptions($this->options, $defaults); |
568
|
|
|
|
569
|
101 |
|
$this->setupLabel(); |
570
|
101 |
|
} |
571
|
|
|
|
572
|
|
|
/** |
573
|
|
|
* Creates default wrapper classes for the form element. |
574
|
|
|
* |
575
|
|
|
* @param array $options |
576
|
|
|
* @return array |
577
|
|
|
*/ |
578
|
101 |
|
protected function setDefaultClasses(array $options = []) |
579
|
|
|
{ |
580
|
101 |
|
$wrapper_class = $this->getConfig('defaults.' . $this->type . '.wrapper_class', ''); |
581
|
101 |
|
$label_class = $this->getConfig('defaults.' . $this->type . '.label_class', ''); |
582
|
101 |
|
$field_class = $this->getConfig('defaults.' . $this->type . '.field_class', ''); |
583
|
|
|
|
584
|
101 |
|
$defaults = []; |
585
|
101 |
|
if ($wrapper_class && !array_get($options, 'wrapper.class')) { |
586
|
|
|
$defaults['wrapper']['class'] = $wrapper_class; |
587
|
|
|
} |
588
|
101 |
|
if ($label_class && !array_get($options, 'label_attr.class')) { |
589
|
|
|
$defaults['label_attr']['class'] = $label_class; |
590
|
|
|
} |
591
|
101 |
|
if ($field_class && !array_get($options, 'attr.class')) { |
592
|
1 |
|
$defaults['attr']['class'] = $field_class; |
593
|
1 |
|
} |
594
|
101 |
|
return $defaults; |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
/** |
598
|
|
|
* Setup the label for the form field. |
599
|
|
|
* |
600
|
|
|
* @return void |
601
|
|
|
*/ |
602
|
101 |
|
protected function setupLabel() |
603
|
|
|
{ |
604
|
101 |
|
if ($this->getOption('label') !== null) { |
605
|
24 |
|
return; |
606
|
|
|
} |
607
|
|
|
|
608
|
99 |
|
if ($template = $this->parent->getTranslationTemplate()) { |
609
|
3 |
|
$label = str_replace( |
610
|
3 |
|
['{name}', '{type}'], |
611
|
3 |
|
[$this->getRealName(), 'label'], |
612
|
|
|
$template |
613
|
3 |
|
); |
614
|
99 |
|
} elseif ($langName = $this->parent->getLanguageName()) { |
615
|
4 |
|
$label = sprintf('%s.%s', $langName, $this->getRealName()); |
616
|
4 |
|
} else { |
617
|
93 |
|
$label = $this->getRealName(); |
618
|
|
|
} |
619
|
|
|
|
620
|
99 |
|
$this->setOption('label', $this->formHelper->formatLabel($label)); |
621
|
99 |
|
} |
622
|
|
|
|
623
|
|
|
/** |
624
|
|
|
* Check if fields needs label. |
625
|
|
|
* |
626
|
|
|
* @return bool |
627
|
|
|
*/ |
628
|
35 |
|
protected function needsLabel() |
629
|
|
|
{ |
630
|
|
|
// If field is <select> and child of choice, we don't need label for it |
631
|
35 |
|
$isChildSelect = $this->type == 'select' && $this->getOption('is_child') === true; |
632
|
|
|
|
633
|
35 |
|
if ($this->type == 'hidden' || $isChildSelect) { |
634
|
11 |
|
return false; |
635
|
|
|
} |
636
|
|
|
|
637
|
31 |
|
return true; |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
/** |
641
|
|
|
* Disable field. |
642
|
|
|
* |
643
|
|
|
* @return $this |
644
|
|
|
*/ |
645
|
1 |
|
public function disable() |
646
|
|
|
{ |
647
|
1 |
|
$this->setOption('attr.disabled', 'disabled'); |
648
|
|
|
|
649
|
1 |
|
return $this; |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
/** |
653
|
|
|
* Enable field. |
654
|
|
|
* |
655
|
|
|
* @return $this |
656
|
|
|
*/ |
657
|
1 |
|
public function enable() |
658
|
|
|
{ |
659
|
1 |
|
array_forget($this->options, 'attr.disabled'); |
660
|
|
|
|
661
|
1 |
|
return $this; |
662
|
|
|
} |
663
|
|
|
|
664
|
|
|
/** |
665
|
|
|
* Get validation rules for a field if any with label for attributes. |
666
|
|
|
* |
667
|
|
|
* @return array|null |
668
|
|
|
*/ |
669
|
9 |
|
public function getValidationRules() |
670
|
|
|
{ |
671
|
9 |
|
$rules = $this->getOption('rules', []); |
672
|
9 |
|
$name = $this->getNameKey(); |
673
|
9 |
|
$messages = $this->getOption('error_messages', []); |
674
|
9 |
|
$formName = $this->formHelper->transformToDotSyntax($this->parent->getName()); |
675
|
|
|
|
676
|
9 |
|
if ($messages && $formName) { |
677
|
1 |
|
$newMessages = []; |
678
|
1 |
|
foreach ($messages as $messageKey => $message) { |
679
|
1 |
|
$messageKey = sprintf('%s.%s', $formName, $messageKey); |
680
|
1 |
|
$newMessages[$messageKey] = $message; |
681
|
1 |
|
} |
682
|
1 |
|
$messages = $newMessages; |
683
|
1 |
|
} |
684
|
|
|
|
685
|
9 |
|
if (!$rules) { |
686
|
2 |
|
return new Rules([]); |
687
|
|
|
} |
688
|
|
|
|
689
|
8 |
|
if (is_array($rules)) { |
690
|
2 |
|
$rules = array_map(function ($rule) use ($name) { |
691
|
2 |
|
if ($rule instanceof \Closure) { |
692
|
|
|
return $rule($name); |
693
|
|
|
} |
694
|
|
|
|
695
|
2 |
|
return $rule; |
696
|
2 |
|
}, $rules); |
697
|
2 |
|
} |
698
|
|
|
|
699
|
8 |
|
return new Rules( |
700
|
8 |
|
[$name => $rules], |
701
|
8 |
|
[$name => $this->getOption('label')], |
702
|
|
|
$messages |
703
|
8 |
|
); |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
/** |
707
|
|
|
* Get this field's attributes, probably just one. |
708
|
|
|
* |
709
|
|
|
* @return array |
710
|
|
|
*/ |
711
|
3 |
|
public function getAllAttributes() |
712
|
|
|
{ |
713
|
3 |
|
return [$this->getNameKey()]; |
714
|
|
|
} |
715
|
|
|
|
716
|
|
|
/** |
717
|
|
|
* Get value property. |
718
|
|
|
* |
719
|
|
|
* @param mixed|null $default |
720
|
|
|
* @return mixed |
721
|
|
|
*/ |
722
|
38 |
|
public function getValue($default = null) |
723
|
|
|
{ |
724
|
38 |
|
return $this->getOption($this->valueProperty, $default); |
725
|
|
|
} |
726
|
|
|
|
727
|
|
|
/** |
728
|
|
|
* Get default value property. |
729
|
|
|
* |
730
|
|
|
* @param mixed|null $default |
731
|
|
|
* @return mixed |
732
|
|
|
*/ |
733
|
35 |
|
public function getDefaultValue($default = null) |
734
|
|
|
{ |
735
|
35 |
|
return $this->getOption($this->defaultValueProperty, $default); |
736
|
|
|
} |
737
|
|
|
|
738
|
|
|
/** |
739
|
|
|
* Check if provided value is valid for this type. |
740
|
|
|
* |
741
|
|
|
* @return bool |
742
|
|
|
*/ |
743
|
94 |
|
protected function isValidValue($value) |
744
|
|
|
{ |
745
|
94 |
|
return $value !== null; |
746
|
|
|
} |
747
|
|
|
|
748
|
|
|
/** |
749
|
|
|
* Method initFilters used to initialize filters |
750
|
|
|
* from field options and bind it to the same. |
751
|
|
|
* |
752
|
|
|
* @return $this |
753
|
|
|
*/ |
754
|
96 |
|
protected function initFilters() |
755
|
|
|
{ |
756
|
|
|
// If override status is set in field options to true |
757
|
|
|
// we will change filtersOverride property value to true |
758
|
|
|
// so we can override existing filters with registered |
759
|
|
|
// alias/name in addFilter method. |
760
|
96 |
|
$overrideStatus = $this->getOption('filters_override', false); |
761
|
96 |
|
if ($overrideStatus) { |
762
|
2 |
|
$this->setFiltersOverride(true); |
763
|
2 |
|
} |
764
|
|
|
|
765
|
|
|
// Get filters and bind it to field. |
766
|
96 |
|
$filters = $this->getOption('filters', []); |
767
|
96 |
|
foreach ($filters as $filter) { |
768
|
8 |
|
$this->addFilter($filter); |
769
|
96 |
|
} |
770
|
|
|
|
771
|
96 |
|
return $this; |
772
|
|
|
} |
773
|
|
|
|
774
|
|
|
/** |
775
|
|
|
* Method setFilters used to set filters to current filters property. |
776
|
|
|
* |
777
|
|
|
* @param array $filters |
778
|
|
|
* |
779
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
780
|
|
|
*/ |
781
|
|
|
public function setFilters(array $filters) |
782
|
|
|
{ |
783
|
|
|
$this->clearFilters(); |
784
|
|
|
foreach ($filters as $filter) { |
785
|
|
|
$this->addFilter($filter); |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
return $this; |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
/** |
792
|
|
|
* Method getFilters returns array of binded filters |
793
|
|
|
* if there are any binded. Otherwise empty array. |
794
|
|
|
* |
795
|
|
|
* @return array |
796
|
|
|
*/ |
797
|
23 |
|
public function getFilters() |
798
|
|
|
{ |
799
|
23 |
|
return $this->filters; |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
/** |
803
|
|
|
* @param string|FilterInterface $filter |
804
|
|
|
* |
805
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
806
|
|
|
* |
807
|
|
|
* @throws FilterAlreadyBindedException |
808
|
|
|
*/ |
809
|
8 |
|
public function addFilter($filter) |
810
|
|
|
{ |
811
|
|
|
// Resolve filter object from string/object or throw Ex. |
812
|
8 |
|
$filterObj = FilterResolver::instance($filter); |
813
|
|
|
|
814
|
|
|
// If filtersOverride is allowed we will override filter |
815
|
|
|
// with same alias/name if there is one with new resolved filter. |
816
|
8 |
|
if ($this->getFiltersOverride()) { |
817
|
1 |
|
if ($key = array_search($filterObj->getName(), $this->getFilters())) { |
818
|
|
|
$this->filters[$key] = $filterObj; |
819
|
|
|
} else { |
820
|
1 |
|
$this->filters[$filterObj->getName()] = $filterObj; |
821
|
|
|
} |
822
|
1 |
|
} else { |
823
|
|
|
// If filtersOverride is disabled and we found |
824
|
|
|
// equal alias defined we will throw Ex. |
825
|
7 |
|
if (array_key_exists($filterObj->getName(), $this->getFilters())) { |
826
|
1 |
|
$ex = new FilterAlreadyBindedException($filterObj->getName(), $this->getName()); |
827
|
1 |
|
throw $ex; |
828
|
|
|
} |
829
|
|
|
|
830
|
|
|
// Filter with resolvedFilter alias/name doesn't exist |
831
|
|
|
// so we will bind it as new one to field. |
832
|
7 |
|
$this->filters[$filterObj->getName()] = $filterObj; |
833
|
|
|
} |
834
|
|
|
|
835
|
8 |
|
return $this; |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
/** |
839
|
|
|
* Method removeFilter used to remove filter by provided alias/name. |
840
|
|
|
* |
841
|
|
|
* @param string $name |
842
|
|
|
* |
843
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
844
|
|
|
*/ |
845
|
1 |
|
public function removeFilter($name) |
846
|
|
|
{ |
847
|
1 |
|
$filters = $this->getFilters(); |
848
|
1 |
|
if (array_key_exists($name, $filters)) { |
849
|
1 |
|
unset($filters[$name]); |
850
|
1 |
|
$this->filters = $filters; |
851
|
1 |
|
} |
852
|
|
|
|
853
|
1 |
|
return $this; |
854
|
|
|
} |
855
|
|
|
|
856
|
|
|
/** |
857
|
|
|
* Method removeFilters used to remove filters by provided aliases/names. |
858
|
|
|
* |
859
|
|
|
* @param array $filterNames |
860
|
|
|
* |
861
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
862
|
|
|
*/ |
863
|
1 |
|
public function removeFilters(array $filterNames) |
864
|
|
|
{ |
865
|
1 |
|
$filters = $this->getFilters(); |
866
|
1 |
|
foreach ($filterNames as $filterName) { |
867
|
1 |
|
if (array_key_exists($filterName, $filters)) { |
868
|
1 |
|
unset($filters[$filterName]); |
869
|
1 |
|
$this->filters = $filters; |
870
|
1 |
|
} |
871
|
1 |
|
} |
872
|
|
|
|
873
|
1 |
|
return $this; |
874
|
|
|
} |
875
|
|
|
|
876
|
|
|
/** |
877
|
|
|
* Method clearFilters used to empty current filters property. |
878
|
|
|
* |
879
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
880
|
|
|
*/ |
881
|
1 |
|
public function clearFilters() |
882
|
|
|
{ |
883
|
1 |
|
$this->filters = []; |
884
|
1 |
|
return $this; |
885
|
|
|
} |
886
|
|
|
|
887
|
|
|
/** |
888
|
|
|
* Method used to set FiltersOverride status to provided value. |
889
|
|
|
* |
890
|
|
|
* @param $status |
891
|
|
|
* |
892
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
893
|
|
|
*/ |
894
|
2 |
|
public function setFiltersOverride($status) |
895
|
|
|
{ |
896
|
2 |
|
$this->filtersOverride = $status; |
897
|
2 |
|
return $this; |
898
|
|
|
} |
899
|
|
|
|
900
|
|
|
/** |
901
|
|
|
* @return bool |
902
|
|
|
*/ |
903
|
9 |
|
public function getFiltersOverride() |
904
|
|
|
{ |
905
|
9 |
|
return $this->filtersOverride; |
906
|
|
|
} |
907
|
|
|
|
908
|
|
|
/** |
909
|
|
|
* Method used to set Unfiltered/Unmutated field value. |
910
|
|
|
* Method is called before field value mutating starts - request value filtering. |
911
|
|
|
* |
912
|
|
|
* @param mixed $value |
913
|
|
|
* |
914
|
|
|
* @return \Kris\LaravelFormBuilder\Fields\FormField |
915
|
|
|
*/ |
916
|
1 |
|
public function setRawValue($value) |
917
|
|
|
{ |
918
|
1 |
|
$this->rawValue = $value; |
919
|
1 |
|
return $this; |
920
|
|
|
} |
921
|
|
|
|
922
|
|
|
/** |
923
|
|
|
* Returns unfiltered raw value of field. |
924
|
|
|
* |
925
|
|
|
* @return mixed |
926
|
|
|
*/ |
927
|
|
|
public function getRawValue() |
928
|
|
|
{ |
929
|
|
|
return $this->rawValue; |
930
|
|
|
} |
931
|
|
|
|
932
|
|
|
/** |
933
|
|
|
* Get config from the form. |
934
|
|
|
* |
935
|
|
|
* @return mixed |
936
|
|
|
*/ |
937
|
101 |
|
private function getConfig($key = null, $default = null) |
938
|
|
|
{ |
939
|
101 |
|
return $this->parent->getConfig($key, $default); |
940
|
|
|
} |
941
|
|
|
} |
942
|
|
|
|
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.