Passed
Branch master (249862)
by Adam
07:51
created

Field::setupValue()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 6
nc 4
nop 0
dl 0
loc 11
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Coyote\Services\FormBuilder\Fields;
4
5
use Coyote\Services\FormBuilder\Form;
6
use Coyote\Services\FormBuilder\RenderTrait;
7
use Illuminate\Database\Eloquent\Model;
8
9
abstract class Field
10
{
11
    use RenderTrait;
12
13
    const DEFAULT_TEMPLATE = 'row';
14
15
    /**
16
     * @var string
17
     */
18
    protected $name;
19
20
    /**
21
     * @var mixed
22
     */
23
    protected $value;
24
25
    /**
26
     * @var string
27
     */
28
    protected $type;
29
30
    /**
31
     * @var Form
32
     */
33
    protected $parent;
34
35
    /**
36
     * @var string
37
     */
38
    protected $label;
39
40
    /**
41
     * @var string
42
     */
43
    protected $help;
44
45
    /**
46
     * @var string
47
     */
48
    protected $theme;
49
50
    /**
51
     * @var string
52
     */
53
    protected $template = self::DEFAULT_TEMPLATE;
54
55
    /**
56
     * @var string
57
     */
58
    protected $rules;
59
60
    /**
61
     * @var array
62
     */
63
    protected $attr = [];
64
65
    /**
66
     * @var array
67
     */
68
    protected $labelAttr = [];
69
70
    /**
71
     * @var array
72
     */
73
    protected $rowAttr = [];
74
75
    /**
76
     * @var array
77
     */
78
    protected $helpAttr = [];
79
80
    /**
81
     * Name of the property for value setting
82
     *
83
     * @var string
84
     */
85
    protected $valueProperty = 'value';
86
87
    /**
88
     * @var bool
89
     */
90
    protected $required = false;
91
92
    /**
93
     * Field constructor.
94
     * @param $name
95
     * @param $type
96
     * @param Form $parent
97
     * @param array $options
98
     */
99
    public function __construct($name, $type, Form $parent, array $options = [])
100
    {
101
        $this->setName($name);
102
        $this->setType($type);
103
        $this->setParent($parent);
104
105
        // 1) Set up options (attributes, field value)
106
        $this->setDefaultOptions($options);
107
        // 2) Set up the value (from model, request, session etc) if it wasn't set before
108
        $this->setupValue();
109
    }
110
111
    /**
112
     * @return string
113
     */
114
    public function getName()
115
    {
116
        return $this->name;
117
    }
118
119
    /**
120
     * @param mixed $name
121
     */
122
    public function setName($name)
123
    {
124
        $this->name = $name;
125
    }
126
127
    /**
128
     * @return mixed
129
     */
130
    public function getValue()
131
    {
132
        return $this->value;
133
    }
134
135
    /**
136
     * Set value (can be string, can be array etc)
137
     *
138
     * @param mixed $value
139
     */
140
    public function setValue($value)
141
    {
142
        $this->value = $value;
143
    }
144
145
    /**
146
     * @param string $type
147
     * @return $this
148
     */
149
    protected function setType($type)
150
    {
151
        $this->type = $type;
152
        return $this;
153
    }
154
155
    /**
156
     * @return string
157
     */
158
    public function getType()
159
    {
160
        return $this->type;
161
    }
162
163
    /**
164
     * @param Form $parent
165
     * @return $this
166
     */
167
    protected function setParent(Form $parent)
168
    {
169
        $this->parent = $parent;
170
        return $this;
171
    }
172
173
    /**
174
     * @return Form
175
     */
176
    public function getParent()
177
    {
178
        return $this->parent;
179
    }
180
181
    /**
182
     * @return string
183
     */
184
    public function getLabel()
185
    {
186
        return $this->label;
187
    }
188
189
    /**
190
     * @param string $label
191
     */
192
    public function setLabel($label)
193
    {
194
        $this->label = $label;
195
    }
196
197
    /**
198
     * @param string $rules
199
     * @return $this
200
     */
201
    public function setRules($rules)
202
    {
203
        $this->rules = $rules;
204
205
        if (is_string($rules)) {
0 ignored issues
show
introduced by
The condition is_string($rules) can never be false.
Loading history...
206
            $rules = explode('|', $rules);
207
208
            if (in_array('required', $rules)) {
209
                $this->setRequired(true);
210
            }
211
        }
212
        return $this;
213
    }
214
215
    /**
216
     * @return string
217
     */
218
    public function getRules()
219
    {
220
        return $this->rules;
221
    }
222
223
    /**
224
     * @return string
225
     */
226
    public function getHelp()
227
    {
228
        return $this->help;
229
    }
230
231
    /**
232
     * @param mixed $help
233
     */
234
    public function setHelp($help)
235
    {
236
        $this->help = $help;
237
    }
238
239
    /**
240
     * @return array
241
     */
242
    public function getAttr()
243
    {
244
        return $this->attr;
245
    }
246
247
    /**
248
     * @param array $attr
249
     */
250
    public function setAttr($attr)
251
    {
252
        $this->attr = $attr;
253
    }
254
255
    /**
256
     * @return array
257
     */
258
    public function getLabelAttr()
259
    {
260
        return $this->labelAttr;
261
    }
262
263
    /**
264
     * @param array $labelAttr
265
     */
266
    public function setLabelAttr($labelAttr)
267
    {
268
        $this->labelAttr = $labelAttr;
269
    }
270
271
    /**
272
     * @return array
273
     */
274
    public function getRowAttr()
275
    {
276
        return $this->rowAttr;
277
    }
278
279
    /**
280
     * @param array $rowAttr
281
     */
282
    public function setRowAttr($rowAttr)
283
    {
284
        $this->rowAttr = $rowAttr;
285
    }
286
287
    /**
288
     * @return array
289
     */
290
    public function getHelpAttr()
291
    {
292
        return $this->helpAttr;
293
    }
294
295
    /**
296
     * @param array $helpAttr
297
     * @return $this
298
     */
299
    public function setHelpAttr($helpAttr)
300
    {
301
        $this->helpAttr = $helpAttr;
302
303
        return $this;
304
    }
305
306
    /**
307
     * @return boolean
308
     */
309
    public function isRequired()
310
    {
311
        return $this->required;
312
    }
313
314
    /**
315
     * Method alias
316
     *
317
     * @return bool
318
     */
319
    public function getRequired()
320
    {
321
        return $this->isRequired();
322
    }
323
324
    /**
325
     * @param boolean $required
326
     * @return $this
327
     */
328
    public function setRequired($required)
329
    {
330
        $this->required = $required;
331
332
        return $this;
333
    }
334
335
    /**
336
     * @param array $options
337
     * @return $this
338
     */
339
    public function mergeOptions(array $options)
340
    {
341
        $reflection = new \ReflectionClass($this);
342
343
        foreach ($options as $key => $values) {
344
            $baseName = ucfirst(camel_case($key));
345
            $setter = 'set' . $baseName;
346
347
            if (method_exists($this, $setter)) {
348
                $getter = 'get' . $baseName;
349
350
                if ($reflection->hasMethod($getter)
351
                    && $reflection->getMethod($getter)->getNumberOfParameters() === 0) {
352
                    $currentValue = $this->$getter();
353
354
                    if (is_array($currentValue)) {
355
                        $values = $this->arrayMerge($currentValue, $values);
356
                    }
357
                }
358
                $this->$setter($values);
359
            }
360
        }
361
362
        return $this;
363
    }
364
365
    /**
366
     * @param array $old
367
     * @param array $new
368
     * @return array
369
     */
370
    protected function arrayMerge($old, $new)
371
    {
372
        return array_merge($old, $new);
373
    }
374
375
    /**
376
     * @return array|null
377
     */
378
    public function getErrors()
379
    {
380
        return $this->parent->errors() ? $this->parent->errors()->get($this->transformToDotSyntax($this->name)) : null;
381
    }
382
383
    /**
384
     * @return string|null
385
     */
386
    public function getError()
387
    {
388
        return $this->parent->errors() ? $this->parent->errors()->first($this->transformToDotSyntax($this->name)) : null;
389
    }
390
391
    /**
392
     * @return string
393
     * @throws \Exception
394
     * @throws \Throwable
395
     */
396
    public function renderLabel()
397
    {
398
        return $this->view($this->getViewPath('label'), $this->viewData())->render();
399
    }
400
401
    /**
402
     * @return string
403
     * @throws \Exception
404
     * @throws \Throwable
405
     */
406
    public function renderWidget()
407
    {
408
        return $this->view($this->getWidgetPath(), $this->viewData())->render();
409
    }
410
411
    /**
412
     * @return string
413
     * @throws \Exception
414
     * @throws \Throwable
415
     */
416
    public function renderError()
417
    {
418
        return $this->view($this->getViewPath('error'), $this->viewData())->render();
419
    }
420
421
    /**
422
     * Render entire element
423
     *
424
     * @return mixed
425
     */
426
    public function render()
427
    {
428
        return $this->view($this->getViewPath($this->getTemplate()), $this->viewData())->render();
429
    }
430
431
    /**
432
     * Setup field value when initialized
433
     */
434
    protected function setupValue()
435
    {
436
        if ($this->parent->isSubmitted()) {
437
            $this->setValue($this->parent->getRequest()->get($this->name));
438
        } elseif ($this->hasOldInput($this->name)) {
439
            $this->setValue($this->getOldInput($this->name));
440
        // we set value from model/object/array only if current value is empty.
441
            // that's because we can set custom value in form class and we DO NOT want
442
            // overwrite this here:
443
        } elseif ($this->value === null && !($this instanceof ChildForm)) {
444
            $this->setValue($this->getDataValue($this->parent->getData(), $this->name));
445
        }
446
    }
447
448
    /**
449
     * @param mixed $data
450
     * @param string $name
451
     * @return mixed|null
452
     */
453
    protected function getDataValue($data, $name)
454
    {
455
        $name = $this->transformToDotSyntax($name);
456
        $data = $this->loadModelRelation($data, $name);
457
458
        if (is_string($data)) {
459
            return $data;
460
        } elseif (is_array($data) || $data instanceof \ArrayAccess) {
461
            return array_get($data, $name);
462
        } elseif (is_object($data)) {
463
            return object_get($data, $name);
464
        }
465
466
        return $this->getValue();
467
    }
468
469
    /**
470
     * @param string $key
471
     * @return string
472
     */
473
    protected function getOldInput($key)
474
    {
475
        return $this->parent->getRequest()->session()->getOldInput($key);
476
    }
477
478
    /**
479
     * @param string $key
480
     * @return bool
481
     */
482
    protected function hasOldInput($key)
483
    {
484
        return $this->parent->getRequest()->session()->hasOldInput($key);
485
    }
486
487
    /**
488
     * If object is a instance of Eloquent model, we have to make sure that relations were loaded
489
     *
490
     * @param $model
491
     * @param string $key
492
     * @return mixed
493
     */
494
    protected function loadModelRelation($model, $key)
495
    {
496
        if (!($model instanceof Model)) {
497
            return $model;
498
        }
499
500
        if (!isset($model->$key) && method_exists($model, $key)) {
501
            $model->getRelationValue($key);
502
        }
503
504
        return $model;
505
    }
506
507
    /**
508
     * @return array
509
     */
510
    protected function viewData()
511
    {
512
        $result = [];
513
514
        $reflection = new \ReflectionClass($this);
515
516
        foreach ($reflection->getMethods() as $method) {
517
            $name = $method->getName();
518
            $snakeCase = snake_case($name);
519
            $prefix = substr($snakeCase, 0, strpos($snakeCase, '_'));
520
521
            if (in_array($prefix, ['get', 'is']) && $method->getNumberOfParameters() === 0 && !$method->isPrivate() && $name !== 'getParent') {
522
                $withoutPrefix = $snakeCase;
523
524
                if ($prefix === 'get') {
525
                    $withoutPrefix = substr($withoutPrefix, 4);
526
                }
527
                $result[$withoutPrefix] = $this->$name();
528
            }
529
        }
530
531
        return $result;
532
    }
533
534
    /**
535
     * @return string
536
     */
537
    protected function getWidgetName()
538
    {
539
        return $this->getType() . '_widget';
540
    }
541
542
    /**
543
     * @param array $options
544
     */
545
    protected function setDefaultOptions(array $options)
546
    {
547
        // if default value was provided, we would like to set it at the end after all other options
548
        // because setting value can modify children elements in Collection.php. Before creating children
549
        // forms, we want to make sure that other options have been set.
550
        $defaultValue = array_pull($options, 'value');
551
552
        foreach ($options as $key => $values) {
553
            $methodName = 'set' . ucfirst(camel_case($key));
554
555
            if (method_exists($this, $methodName)) {
556
                $this->$methodName($values);
557
            }
558
        }
559
560
        if ($defaultValue !== null) {
561
            $this->setValue($defaultValue);
562
        }
563
    }
564
565
    /**
566
     * @param string $string
567
     * @return string
568
     */
569
    public function transformToDotSyntax($string)
570
    {
571
        return str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $string);
572
    }
573
574
    /**
575
     * @return string
576
     */
577
    public function __toString()
578
    {
579
        return $this->getValue();
580
    }
581
}
582