Completed
Pull Request — master (#5)
by ARCANEDEV
05:05
created

FormBuilder::number()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
ccs 2
cts 2
cp 1
cc 1
eloc 2
nc 1
nop 3
crap 1
1
<?php namespace Arcanedev\LaravelHtml;
2
3
use Arcanedev\LaravelHtml\Contracts\FormBuilderInterface;
4
use Arcanedev\LaravelHtml\Traits\Componentable;
5
use BadMethodCallException;
6
use DateTime;
7
use Illuminate\Contracts\Routing\UrlGenerator;
8
use Illuminate\Session\SessionInterface as Session;
9
use Illuminate\Support\Collection;
10
use Illuminate\Support\HtmlString;
11
use Illuminate\Support\Traits\Macroable;
12
13
/**
14
 * Class     FormBuilder
15
 *
16
 * @package  Arcanedev\LaravelHtml\Builders
17
 * @author   ARCANEDEV <[email protected]>
18
 */
19
class FormBuilder implements FormBuilderInterface
20
{
21
    /* ------------------------------------------------------------------------------------------------
22
     |  Traits
23
     | ------------------------------------------------------------------------------------------------
24
     */
25
    use Macroable, Componentable {
26
        Macroable::__call     as macroCall;
27
        Componentable::__call as componentCall;
28
    }
29
30
    /* ------------------------------------------------------------------------------------------------
31
     |  Properties
32
     | ------------------------------------------------------------------------------------------------
33
     */
34
    /**
35
    * The HTML builder instance.
36
    *
37
    * @var \Arcanedev\LaravelHtml\Contracts\HtmlBuilderInterface
38
    */
39
    protected $html;
40
41
    /**
42
    * The URL generator instance.
43
    *
44
    * @var \Illuminate\Contracts\Routing\UrlGenerator
45
    */
46
    protected $url;
47
48
    /**
49
    * The CSRF token used by the form builder.
50
    *
51
    * @var string
52
    */
53
    protected $csrfToken;
54
55
    /**
56
    * The session store implementation.
57
    *
58
    * @var \Illuminate\Session\SessionInterface
59
    */
60
    protected $session;
61
62
    /**
63
    * The current model instance for the form.
64
    *
65
    * @var mixed
66
    */
67
    protected $model;
68
69
    /**
70
    * An array of label names we've created.
71
    *
72
    * @var array
73
    */
74
    protected $labels = [];
75
76
    /**
77
    * The reserved form open attributes.
78
    *
79
    * @var array
80
    */
81
    protected $reserved = ['method', 'url', 'route', 'action', 'files'];
82
83
    /**
84
    * The form methods that should be spoofed, in uppercase.
85
    *
86
    * @var array
87
    */
88
    protected $spoofedMethods = ['DELETE', 'PATCH', 'PUT'];
89
90
    /**
91
    * The types of inputs to not fill values on by default.
92
    *
93
    * @var array
94
    */
95
    protected $skipValueTypes = ['file', 'password', 'checkbox', 'radio'];
96
97
    /* ------------------------------------------------------------------------------------------------
98
     |  Constructor
99
     | ------------------------------------------------------------------------------------------------
100
     */
101
    /**
102
    * Create a new form builder instance.
103
    *
104
    * @param  \Illuminate\Contracts\Routing\UrlGenerator             $url
105
    * @param  \Arcanedev\LaravelHtml\Contracts\HtmlBuilderInterface  $html
106
    * @param  string                                                 $csrfToken
107
    */
108 760
    public function __construct(
109
        Contracts\HtmlBuilderInterface $html,
110
        UrlGenerator $url,
111
        $csrfToken
112
    ) {
113 760
        $this->url       = $url;
114 760
        $this->html      = $html;
115 760
        $this->csrfToken = $csrfToken;
116 760
    }
117
118
    /* ------------------------------------------------------------------------------------------------
119
     |  Getters & Setters
120
     | ------------------------------------------------------------------------------------------------
121
     */
122
    /**
123
     * Get the session store implementation.
124
     *
125
     * @return  \Illuminate\Session\SessionInterface
126
     */
127 8
    public function getSessionStore()
128
    {
129 8
        return $this->session;
130
    }
131
132
    /**
133
     * Set the session store implementation.
134
     *
135
     * @param  \Illuminate\Session\SessionInterface  $session
136
     *
137
     * @return self
138
     */
139 120
    public function setSessionStore(Session $session)
140
    {
141 120
        $this->session = $session;
142
143 120
        return $this;
144
    }
145
146
    /**
147
     * Set the model instance on the form builder.
148
     *
149
     * @param  mixed  $model
150
     *
151
     * @return self
152
     */
153 80
    public function setModel($model)
154
    {
155 80
        $this->model = $model;
156
157 80
        return $this;
158
    }
159
160
    /**
161
     * Get the ID attribute for a field name.
162
     *
163
     * @param  string  $name
164
     * @param  array   $attributes
165
     *
166
     * @return string
167
     */
168 632
    public function getIdAttribute($name, array $attributes)
169
    {
170 632
        if (array_key_exists('id', $attributes)) {
171 48
            return $attributes['id'];
172
        }
173
174 600
        if (in_array($name, $this->labels)) {
175 8
            return $name;
176
        }
177
178 592
        return null;
179
    }
180
181
    /**
182
     * Get the value that should be assigned to the field.
183
     *
184
     * @param  string  $name
185
     * @param  mixed   $value
186
     *
187
     * @return mixed
188
     */
189 560
    public function getValueAttribute($name, $value = null)
190
    {
191 560
        if (is_null($name)) {
192 24
            return $value;
193
        }
194
195 536
        if ( ! is_null($this->old($name))) {
196 32
            return $this->old($name);
197
        }
198
199 520
        if ( ! is_null($value)) {
200 296
            return $value;
201
        }
202
203 304
        if (isset($this->model)) {
204 40
            return $this->getModelValueAttribute($name);
205
        }
206
207 264
        return null;
208
    }
209
210
    /**
211
     * Get the model value that should be assigned to the field.
212
     *
213
     * @param  string  $name
214
     *
215
     * @return mixed
216
     */
217 64
    private function getModelValueAttribute($name)
218
    {
219 64
        return data_get($this->model, $this->transformKey($name));
220
    }
221
222
    /**
223
     * Get a value from the session's old input.
224
     *
225
     * @param  string  $name
226
     *
227
     * @return mixed
228
     */
229 560
    public function old($name)
230
    {
231 560
        return isset($this->session)
232 436
            ? $this->session->getOldInput($this->transformKey($name))
233 560
            : null;
234
    }
235
236
    /**
237
     * Transform key from array to dot syntax.
238
     *
239
     * @param  string  $key
240
     *
241
     * @return string
242
     */
243 96
    private function transformKey($key)
244
    {
245 96
        return str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $key);
246
    }
247
248
    /**
249
     * Determine if the old input is empty.
250
     *
251
     * @return bool
252
     */
253 24
    public function oldInputIsEmpty()
254
    {
255 24
        return isset($this->session) && (count($this->session->getOldInput()) == 0);
256
    }
257
258
    /**
259
     * Parse the form action method.
260
     *
261
     * @param  string  $method
262
     *
263
     * @return string
264
     */
265 128
    private function getMethod($method)
266
    {
267 128
        $method = strtoupper($method);
268
269 128
        return $method !== 'GET' ? 'POST' : $method;
270
    }
271
272
    /* ------------------------------------------------------------------------------------------------
273
     |  Main Functions
274
     | ------------------------------------------------------------------------------------------------
275
     */
276
    /**
277
    * Open up a new HTML form.
278
    *
279
    * @param  array  $options
280
    *
281
    * @return string
282
    */
283 128
    public function open(array $options = [])
284
    {
285 128
        $method = array_get($options, 'method', 'post');
286
287
        // We need to extract the proper method from the attributes. If the method is
288
        // something other than GET or POST we'll use POST since we will spoof the
289
        // actual method since forms don't support the reserved methods in HTML.
290 128
        $attributes = [];
291 128
        $attributes['method']         = $this->getMethod($method);
292 128
        $attributes['action']         = $this->getAction($options);
293 128
        $attributes['accept-charset'] = 'UTF-8';
294
295 128
        if (isset($options['files']) && $options['files']) {
296 16
            $options['enctype'] = 'multipart/form-data';
297 12
        }
298
299
        // Finally we're ready to create the final form HTML field. We will attribute
300
        // format the array of attributes. We will also add on the appendage which
301
        // is used to spoof requests for this PUT, PATCH, etc. methods on forms.
302 128
        $attributes = array_merge(
303 128
            $attributes, array_except($options, $this->reserved)
304 96
        );
305
306
        // Finally, we will concatenate all of the attributes into a single string so
307
        // we can build out the final form open statement. We'll also append on an
308
        // extra value for the hidden _method field if it's needed for the form.
309 128
        $attributes = $this->html->attributes($attributes);
310
311
        // If the method is PUT, PATCH or DELETE we will need to add a spoofer hidden
312
        // field that will instruct the Symfony request to pretend the method is a
313
        // different method than it actually is, for convenience from the forms.
314 128
        $append = $this->getAppendage($method);
315
316 128
        return $this->toHtmlString('<form' . $attributes . '>' . $append);
317
    }
318
319
    /**
320
     * Create a new model based form builder.
321
     *
322
     * @param  mixed  $model
323
     * @param  array  $options
324
     *
325
     * @return \Illuminate\Support\HtmlString
326
     */
327 40
    public function model($model, array $options = [])
328
    {
329 40
        $this->setModel($model);
330
331 40
        return $this->open($options);
332
    }
333
334
    /**
335
     * Close the current form.
336
     *
337
     * @return \Illuminate\Support\HtmlString
338
     */
339 16
    public function close()
340
    {
341 16
        $this->labels = [];
342 16
        $this->setModel(null);
343
344 16
        return $this->toHtmlString('</form>');
345
    }
346
347
    /**
348
     * Generate a hidden field with the current CSRF token.
349
     *
350
     * @return \Illuminate\Support\HtmlString
351
     */
352 56
    public function token()
353
    {
354 56
        $token = ! empty($this->csrfToken)
355 52
            ? $this->csrfToken
356 56
            : $this->session->getToken();
357
358 56
        return $this->hidden('_token', $token);
359
    }
360
361
    /**
362
     * Create a form label element.
363
     *
364
     * @param  string  $name
365
     * @param  string  $value
366
     * @param  array   $options
367
     *
368
     * @return \Illuminate\Support\HtmlString
369
     */
370 24
    public function label($name, $value = null, array $options = [])
371
    {
372 24
        $this->labels[] = $name;
373
374 24
        return $this->toHtmlString(
375 24
            Helpers\Label::make($name, $value, $options)
376 18
        );
377
    }
378
379
    /**
380
     * Create a form input field.
381
     *
382
     * @param  string  $type
383
     * @param  string  $name
384
     * @param  string  $value
385
     * @param  array   $options
386
     *
387
     * @return \Illuminate\Support\HtmlString
388
     */
389 496
    public function input($type, $name, $value = null, array $options = [])
390
    {
391 496
        if ( ! isset($options['name'])) {
392 496
            $options['name'] = $name;
393 372
        }
394
395
        // We will get the appropriate value for the given field. We will look for the
396
        // value in the session for the value in the old input data then we'll look
397
        // in the model instance if one is set. Otherwise we will just use empty.
398 496
        $id = $this->getIdAttribute($name, $options);
399
400 496
        if ( ! in_array($type, $this->skipValueTypes)) {
401 400
            $value = $this->getValueAttribute($name, $value);
402 300
        }
403
404
        // Once we have the type, value, and ID we can merge them into the rest of the
405
        // attributes array so we can convert them into their HTML attribute format
406
        // when creating the HTML element. Then, we will return the entire input.
407 496
        $options = array_merge($options, compact('type', 'value', 'id'));
408
409 496
        return $this->toHtmlString(
410 496
            '<input' . $this->html->attributes($options) . '>'
411 372
        );
412
    }
413
414
    /**
415
     * Create a text input field.
416
     *
417
     * @param  string  $name
418
     * @param  string  $value
419
     * @param  array   $options
420
     *
421
     * @return \Illuminate\Support\HtmlString
422
     */
423 54
    public function text($name, $value = null, array $options = [])
424
    {
425 54
        return $this->input('text', $name, $value, $options);
426 9
    }
427
428
    /**
429
     * Create a password input field.
430
     *
431
     * @param  string  $name
432
     * @param  array   $options
433
     *
434
     * @return \Illuminate\Support\HtmlString
435
     */
436 24
    public function password($name, array $options = [])
437
    {
438 24
        return $this->input('password', $name, '', $options);
439
    }
440
441
    /**
442
     * Create a hidden input field.
443
     *
444
     * @param  string  $name
445
     * @param  string  $value
446
     * @param  array   $options
447
     *
448
     * @return \Illuminate\Support\HtmlString
449
     */
450 80
    public function hidden($name, $value = null, array $options = [])
451
    {
452 80
        return $this->input('hidden', $name, $value, $options);
453
    }
454
455
    /**
456
     * Create an e-mail input field.
457
     *
458
     * @param  string  $name
459
     * @param  string  $value
460
     * @param  array   $options
461
     *
462
     * @return \Illuminate\Support\HtmlString
463
     */
464 24
    public function email($name, $value = null, array $options = [])
465
    {
466 24
        return $this->input('email', $name, $value, $options);
467
    }
468
469
    /**
470
     * Create a tel input field.
471
     *
472
     * @param  string  $name
473
     * @param  string  $value
474
     * @param  array   $options
475
     *
476
     * @return \Illuminate\Support\HtmlString
477
     */
478 24
    public function tel($name, $value = null, array $options = [])
479
    {
480 24
        return $this->input('tel', $name, $value, $options);
481
    }
482
483
    /**
484
     * Create a number input field.
485
     *
486
     * @param  string  $name
487
     * @param  string  $value
488
     * @param  array   $options
489
     *
490
     * @return \Illuminate\Support\HtmlString
491
     */
492 24
    public function number($name, $value = null, array $options = [])
493
    {
494 24
        return $this->input('number', $name, $value, $options);
495
    }
496
497
    /**
498
     * Create a date input field.
499
     *
500
     * @param  string  $name
501
     * @param  string  $value
502
     * @param  array   $options
503
     *
504
     * @return \Illuminate\Support\HtmlString
505
     */
506 32
    public function date($name, $value = null, array $options = [])
507
    {
508 32
        if ($value instanceof DateTime) {
509 8
            $value = $value->format('Y-m-d');
510 6
        }
511
512 32
        return $this->input('date', $name, $value, $options);
513
    }
514
515
    /**
516
     * Create a datetime input field.
517
     *
518
     * @param  string  $name
519
     * @param  string  $value
520
     * @param  array   $options
521
     *
522
     * @return \Illuminate\Support\HtmlString
523
     */
524 32
    public function datetime($name, $value = null, array $options = [])
525
    {
526 32
        if ($value instanceof DateTime) {
527 16
            $value = $value->format(DateTime::RFC3339);
528 12
        }
529
530 32
        return $this->input('datetime', $name, $value, $options);
531
    }
532
533
    /**
534
     * Create a datetime-local input field.
535
     *
536
     * @param  string  $name
537
     * @param  string  $value
538
     * @param  array   $options
539
     *
540
     * @return \Illuminate\Support\HtmlString
541
     */
542 32
    public function datetimeLocal($name, $value = null, array $options = [])
543
    {
544 32
        if ($value instanceof DateTime) {
545 16
            $value = $value->format('Y-m-d\TH:i');
546 12
        }
547
548 32
        return $this->input('datetime-local', $name, $value, $options);
549
    }
550
551
    /**
552
     * Create a time input field.
553
     *
554
     * @param  string  $name
555
     * @param  string  $value
556
     * @param  array   $options
557
     *
558
     * @return \Illuminate\Support\HtmlString
559
     */
560 24
    public function time($name, $value = null, array $options = [])
561
    {
562 24
        return $this->input('time', $name, $value, $options);
563
    }
564
565
    /**
566
     * Create a url input field.
567
     *
568
     * @param  string  $name
569
     * @param  string  $value
570
     * @param  array   $options
571
     *
572
     * @return \Illuminate\Support\HtmlString
573
     */
574 16
    public function url($name, $value = null, array $options = [])
575
    {
576 16
        return $this->input('url', $name, $value, $options);
577
    }
578
579
    /**
580
     * Create a file input field.
581
     *
582
     * @param  string  $name
583
     * @param  array   $options
584
     *
585
     * @return \Illuminate\Support\HtmlString
586
     */
587 24
    public function file($name, array $options = [])
588
    {
589 24
        return $this->input('file', $name, null, $options);
590
    }
591
592
    /**
593
     * Create a textarea input field.
594
     *
595
     * @param  string  $name
596
     * @param  string  $value
597
     * @param  array   $options
598
     *
599
     * @return \Illuminate\Support\HtmlString
600
     */
601 32
    public function textarea($name, $value = null, array $options = [])
602
    {
603 32
        if ( ! isset($options['name'])) {
604 32
            $options['name'] = $name;
605 24
        }
606
607
        // Next we will look for the rows and cols attributes, as each of these are put
608
        // on the textarea element definition. If they are not present, we will just
609
        // assume some sane default values for these attributes for the developer.
610 32
        $options       = $this->setTextAreaSize($options);
611 32
        $options['id'] = $this->getIdAttribute($name, $options);
612 32
        $value         = (string) $this->getValueAttribute($name, $value);
613
614 32
        unset($options['size']);
615
616
        // Next we will convert the attributes into a string form. Also we have removed
617
        // the size attribute, as it was merely a short-cut for the rows and cols on
618
        // the element. Then we'll create the final textarea elements HTML for us.
619 32
        $options = $this->html->attributes($options);
620
621 32
        return $this->toHtmlString(
622 32
            '<textarea' . $options . '>' . e($value) . '</textarea>'
623 24
        );
624
    }
625
626
    /**
627
     * Set the text area size on the attributes.
628
     *
629
     * @param  array  $options
630
     *
631
     * @return array
632
     */
633 32
    private function setTextAreaSize(array $options)
634
    {
635 32
        if (isset($options['size'])) {
636 8
            return $this->setQuickTextAreaSize($options);
637
        }
638
639
        // If the "size" attribute was not specified, we will just look for the regular
640
        // columns and rows attributes, using sane defaults if these do not exist on
641
        // the attributes array. We'll then return this entire options array back.
642 24
        $cols = array_get($options, 'cols', 50);
643 24
        $rows = array_get($options, 'rows', 10);
644
645 24
        return array_merge($options, compact('cols', 'rows'));
646
    }
647
648
    /**
649
     * Set the text area size using the quick "size" attribute.
650
     *
651
     * @param  array  $options
652
     *
653
     * @return array
654
     */
655 8
    protected function setQuickTextAreaSize(array $options)
656
    {
657 8
        list($cols, $rows) = explode('x', $options['size']);
658
659 8
        return array_merge($options, [
660 8
            'cols' => $cols,
661 2
            'rows' => $rows
662 6
        ]);
663
    }
664
665
    /**
666
     * Create a select box field.
667
     *
668
     * @param  string  $name
669
     * @param  array   $list
670
     * @param  string  $selected
671
     * @param  array   $options
672
     *
673
     * @return \Illuminate\Support\HtmlString
674
     */
675 104
    public function select($name, $list = [], $selected = null, array $options = [])
676
    {
677
        // When building a select box the "value" attribute is really the selected one
678
        // so we will use that when checking the model or session for a value which
679
        // should provide a convenient method of re-populating the forms on post.
680 104
        $selected      = $this->getValueAttribute($name, $selected);
681
682
        // Transform to array if it is a collection
683 104
        if ($selected instanceof Collection) {
684 8
            $selected = $selected->all();
685 6
        }
686
687 104
        $options['id'] = $this->getIdAttribute($name, $options);
688
689 104
        if ( ! isset($options['name'])) {
690 72
            $options['name'] = $name;
691 54
        }
692
693
        // We will simply loop through the options and build an HTML value for each of
694
        // them until we have an array of HTML declarations. Then we will join them
695
        // all together into one single HTML element that can be put on the form.
696 104
        $html = [];
697
698 104
        if (isset($options['placeholder'])) {
699 8
            $html[] = $this->placeholderOption($options['placeholder'], $selected);
700 8
            unset($options['placeholder']);
701 6
        }
702
703 104
        foreach($list as $value => $display) {
704 96
            $html[] = $this->getSelectOption($display, $value, $selected);
705 78
        }
706
707
        // Once we have all of this HTML, we can join this into a single element after
708
        // formatting the attributes into an HTML "attributes" string, then we will
709
        // build out a final select statement, which will contain all the values.
710 104
        $options = $this->html->attributes($options);
711
712 104
        return $this->toHtmlString(
713 104
            "<select{$options}>" . implode('', $html) . "</select>"
714 78
        );
715
    }
716
717
    /**
718
     * Create a select range field.
719
     *
720
     * @param  string  $name
721
     * @param  string  $begin
722
     * @param  string  $end
723
     * @param  string  $selected
724
     * @param  array   $options
725
     *
726
     * @return \Illuminate\Support\HtmlString
727
     */
728 16
    public function selectRange($name, $begin, $end, $selected = null, array $options = [])
729
    {
730 16
        $range = array_combine($range = range($begin, $end), $range);
731
732 16
        return $this->select($name, $range, $selected, $options);
733
    }
734
735
    /**
736
     * Create a select year field.
737
     *
738
     * @param  string  $name
739
     * @param  string  $begin
740
     * @param  string  $end
741
     * @param  string  $selected
742
     * @param  array   $options
743
     *
744
     * @return \Illuminate\Support\HtmlString
745
     */
746 8
    public function selectYear($name, $begin, $end, $selected = null, array $options = [])
747
    {
748 8
        return call_user_func_array(
749 8
            [$this, 'selectRange'],
750 8
            compact('name', 'begin', 'end', 'selected', 'options')
751 6
        );
752
    }
753
754
    /**
755
     * Create a select month field.
756
     *
757
     * @param  string  $name
758
     * @param  string  $selected
759
     * @param  array   $options
760
     * @param  string  $format
761
     *
762
     * @return \Illuminate\Support\HtmlString
763
     */
764 8
    public function selectMonth($name, $selected = null, array $options = [], $format = '%B')
765
    {
766 8
        $months = [];
767
768 8
        foreach(range(1, 12) as $month) {
769 8
            $months[$month] = strftime($format, mktime(0, 0, 0, $month, 1));
770 6
        }
771
772 8
        return $this->select($name, $months, $selected, $options);
773
    }
774
775
    /**
776
     * Get the select option for the given value.
777
     *
778
     * @param  string  $display
779
     * @param  string  $value
780
     * @param  string  $selected
781
     *
782
     * @return string
783
     */
784 96
    private function getSelectOption($display, $value, $selected)
785
    {
786 96
        if (is_array($display)) {
787 8
            return $this->optionGroup($display, $value, $selected);
788
        }
789
790 88
        return $this->option($display, $value, $selected);
791
    }
792
793
    /**
794
     * Create an option group form element.
795
     *
796
     * @param  array   $list
797
     * @param  string  $label
798
     * @param  string  $selected
799
     *
800
     * @return string
801
     */
802 8
    private function optionGroup(array $list, $label, $selected)
803
    {
804 8
        $html = [];
805
806 8
        foreach($list as $value => $display) {
807 8
            $html[] = $this->option($display, $value, $selected);
808 6
        }
809
810 8
        return '<optgroup label="' . e($label) . '">' . implode('', $html) . '</optgroup>';
811
    }
812
813
    /**
814
     * Create a select element option.
815
     *
816
     * @param  string  $display
817
     * @param  string  $value
818
     * @param  string  $selected
819
     *
820
     * @return string
821
     */
822 96
    private function option($display, $value, $selected)
823
    {
824 96
        $selected = $this->getSelectedValue($value, $selected);
825 96
        $options  = compact('value', 'selected');
826
827 96
        return '<option' . $this->html->attributes($options) . '>' . e($display) . '</option>';
828
    }
829
830
    /**
831
     * Create a placeholder select element option.
832
     *
833
     * @param  string  $display
834
     * @param  string  $selected
835
     *
836
     * @return string
837
     */
838 8
    private function placeholderOption($display, $selected)
839
    {
840 8
        $selected         = $this->getSelectedValue(null, $selected);
841 8
        $options          = compact('selected');
842 8
        $options['value'] = '';
843
844 8
        return '<option' . $this->html->attributes($options) . '>' . e($display) . '</option>';
845
    }
846
847
    /**
848
     * Determine if the value is selected.
849
     *
850
     * @param  string  $value
851
     * @param  string  $selected
852
     *
853
     * @return string|null
854
     */
855 96
    private function getSelectedValue($value, $selected)
856
    {
857 96
        if (is_array($selected)) {
858 32
            return in_array($value, $selected) ? 'selected' : null;
859
        }
860
861 72
        return ((string) $value == (string) $selected) ? 'selected' : null;
862
    }
863
864
    /**
865
     * Create a checkbox input field.
866
     *
867
     * @param  string     $name
868
     * @param  mixed      $value
869
     * @param  bool|null  $checked
870
     * @param  array      $options
871
     *
872
     * @return \Illuminate\Support\HtmlString
873
     */
874 32
    public function checkbox($name, $value = 1, $checked = null, array $options = [])
875
    {
876 32
        return $this->checkable('checkbox', $name, $value, $checked, $options);
877
    }
878
879
    /**
880
     * Create a radio button input field.
881
     *
882
     * @param  string  $name
883
     * @param  mixed   $value
884
     * @param  bool    $checked
885
     * @param  array   $options
886
     *
887
     * @return \Illuminate\Support\HtmlString
888
     */
889 16
    public function radio($name, $value = null, $checked = null, array $options = [])
890
    {
891 16
        if (is_null($value)) {
892 8
            $value = $name;
893 6
        }
894
895 16
        return $this->checkable('radio', $name, $value, $checked, $options);
896
    }
897
898
    /**
899
     * Create a checkable input field.
900
     *
901
     * @param  string     $type
902
     * @param  string     $name
903
     * @param  mixed      $value
904
     * @param  bool|null  $checked
905
     * @param  array      $options
906
     *
907
     * @return \Illuminate\Support\HtmlString
908
     */
909 56
    protected function checkable($type, $name, $value, $checked, array $options)
910
    {
911 56
        $checked = $this->getCheckedState($type, $name, $value, $checked);
912
913 56
        if ( ! is_null($checked) && $checked) {
914 48
            $options['checked'] = 'checked';
915 36
        }
916
917 56
        return $this->input($type, $name, $value, $options);
918
    }
919
920
    /**
921
     * Get the check state for a checkable input.
922
     *
923
     * @param  string     $type
924
     * @param  string     $name
925
     * @param  mixed      $value
926
     * @param  bool|null  $checked
927
     *
928
     * @return bool
929
     */
930 56
    private function getCheckedState($type, $name, $value, $checked)
931
    {
932
        switch($type) {
933 56
            case 'checkbox':
934 32
                return $this->getCheckboxCheckedState($name, $value, $checked);
935
936 20
            case 'radio':
937 16
                return $this->getRadioCheckedState($name, $value, $checked);
938
939 6
            default:
940 8
                return $this->getValueAttribute($name) == $value;
941 6
        }
942
    }
943
944
    /**
945
     * Get the check state for a checkbox input.
946
     *
947
     * @param  string     $name
948
     * @param  mixed      $value
949
     * @param  bool|null  $checked
950
     *
951
     * @return bool
952
     */
953 32
    private function getCheckboxCheckedState($name, $value, $checked)
954
    {
955
        if (
956 32
            isset($this->session) &&
957 32
            ! $this->oldInputIsEmpty() &&
958 14
            is_null($this->old($name))
959 24
        ) {
960 8
            return false;
961
        }
962
963 32
        if ($this->missingOldAndModel($name)) {
964 16
            return $checked;
965
        }
966
967 16
        $posted = $this->getValueAttribute($name, $checked);
968
969 16
        if (is_array($posted)) {
970 8
            return in_array($value, $posted);
971
        }
972
973 16
        if ($posted instanceof Collection) {
974 8
            return $posted->contains('id', $value);
975
        }
976
977 16
        return (bool) $posted;
978
    }
979
980
    /**
981
     * Get the check state for a radio input.
982
     *
983
     * @param  string     $name
984
     * @param  mixed      $value
985
     * @param  bool|null  $checked
986
     *
987
     * @return bool
988
     */
989 16
    private function getRadioCheckedState($name, $value, $checked)
990
    {
991 16
        return $this->missingOldAndModel($name)
992 14
            ? $checked
993 16
            : $this->getValueAttribute($name) == $value;
994
    }
995
996
    /**
997
     * Determine if old input or model input exists for a key.
998
     *
999
     * @param  string  $name
1000
     *
1001
     * @return bool
1002
     */
1003 48
    private function missingOldAndModel($name)
1004
    {
1005 48
        return (is_null($this->old($name)) && is_null($this->getModelValueAttribute($name)));
1006
    }
1007
1008
    /**
1009
     * Create a HTML reset input element.
1010
     *
1011
     * @param  string  $value
1012
     * @param  array   $attributes
1013
     *
1014
     * @return \Illuminate\Support\HtmlString
1015
     */
1016 8
    public function reset($value, array $attributes = [])
1017
    {
1018 8
        return $this->input('reset', null, $value, $attributes);
1019
    }
1020
1021
    /**
1022
    * Create a HTML image input element.
1023
    *
1024
    * @param  string  $url
1025
    * @param  string  $name
1026
    * @param  array   $attributes
1027
    *
1028
     * @return \Illuminate\Support\HtmlString
1029
    */
1030 8
    public function image($url, $name = null, array $attributes = [])
1031
    {
1032 8
        $attributes['src'] = $this->url->asset($url);
1033
1034 8
        return $this->input('image', $name, null, $attributes);
1035
    }
1036
1037
    /**
1038
     * Create a submit button element.
1039
     *
1040
     * @param  string  $value
1041
     * @param  array   $options
1042
     *
1043
     * @return \Illuminate\Support\HtmlString
1044
     */
1045 8
    public function submit($value = null, array $options = [])
1046
    {
1047 8
        return $this->input('submit', null, $value, $options);
1048
    }
1049
1050
    /**
1051
    * Create a button element.
1052
    *
1053
    * @param  string  $value
1054
    * @param  array   $options
1055
    *
1056
    * @return \Illuminate\Support\HtmlString
1057
    */
1058 8
    public function button($value = null, array $options = [])
1059
    {
1060 8
        if ( ! array_key_exists('type', $options)) {
1061 8
            $options['type'] = 'button';
1062 6
        }
1063
1064 8
        return $this->toHtmlString(
1065 8
            '<button' . $this->html->attributes($options) . '>' . $value . '</button>'
1066 6
        );
1067
    }
1068
1069
    /**
1070
     * Create a color input field.
1071
     *
1072
     * @param  string  $name
1073
     * @param  string  $value
1074
     * @param  array   $options
1075
     *
1076
     * @return string
1077
     */
1078 24
    public function color($name, $value = null, array $options = [])
1079
    {
1080 24
        return $this->input('color', $name, $value, $options);
1081
    }
1082
1083
    /**
1084
     * Dynamically handle calls to the class.
1085
     *
1086
     * @param  string  $method
1087
     * @param  array   $parameters
1088
     *
1089
     * @return \Illuminate\Contracts\View\View|mixed
1090
     *
1091
     * @throws \BadMethodCallException
1092
     */
1093
    public function __call($method, $parameters)
1094
    {
1095
        try {
1096
            return $this->componentCall($method, $parameters);
1097
        }
1098
        catch (BadMethodCallException $e) {
1099
            // Continue
1100
        }
1101
1102
        return $this->macroCall($method, $parameters);
1103
    }
1104
1105
    /* ------------------------------------------------------------------------------------------------
1106
     |  Other Functions
1107
     | ------------------------------------------------------------------------------------------------
1108
     */
1109
    /**
1110
     * Get the form action from the options.
1111
     *
1112
     * @param  array  $options
1113
     *
1114
     * @return string
1115
     */
1116 128
    private function getAction(array $options)
1117
    {
1118
        // We will also check for a "route" or "action" parameter on the array so that
1119
        // developers can easily specify a route or controller action when creating
1120
        // a form providing a convenient interface for creating the form actions.
1121 128
        if (isset($options['url'])) {
1122 40
            return $this->getUrlAction($options['url']);
1123
        }
1124 88
        elseif (isset($options['route'])) {
1125 8
            return $this->getRouteAction($options['route']);
1126
        }
1127 88
        elseif (isset($options['action'])) {
1128
            // If an action is available, we are attempting to open a form to a controller
1129
            // action route. So, we will use the URL generator to get the path to these
1130
            // actions and return them from the method. Otherwise, we'll use current.
1131 8
            return $this->getControllerAction($options['action']);
1132
        }
1133
1134 80
        return $this->url->current();
1135
    }
1136
1137
    /**
1138
     * Get the action for a "url" option.
1139
     *
1140
     * @param  array|string  $options
1141
     *
1142
     * @return string
1143
     */
1144 40
    private function getUrlAction($options)
1145
    {
1146 40
        return is_array($options)
1147 30
            ? $this->url->to($options[0], array_slice($options, 1))
1148 40
            : $this->url->to($options);
1149
    }
1150
1151
    /**
1152
     * Get the action for a "route" option.
1153
     *
1154
     * @param  array|string  $options
1155
     *
1156
     * @return string
1157
     */
1158 8
    private function getRouteAction($options)
1159
    {
1160 8
        return is_array($options)
1161 6
            ? $this->url->route($options[0], array_slice($options, 1))
1162 8
            : $this->url->route($options);
1163
    }
1164
1165
    /**
1166
     * Get the action for an "action" option.
1167
     *
1168
     * @param  array|string  $options
1169
     *
1170
     * @return string
1171
     */
1172 8
    private function getControllerAction($options)
1173
    {
1174 8
        return is_array($options)
1175 6
            ? $this->url->action($options[0], array_slice($options, 1))
1176 8
            : $this->url->action($options);
1177
    }
1178
1179
    /**
1180
     * Get the form appendage for the given method.
1181
     *
1182
     * @param  string  $method
1183
     *
1184
     * @return string
1185
     */
1186 128
    private function getAppendage($method)
1187
    {
1188 128
        list($method, $appendage) = [strtoupper($method), ''];
1189
1190
        // If the HTTP method is in this list of spoofed methods, we will attach the
1191
        // method spoofer hidden input to the form. This allows us to use regular
1192
        // form to initiate PUT and DELETE requests in addition to the typical.
1193 128
        if (in_array($method, $this->spoofedMethods)) {
1194 16
            $appendage .= $this->hidden('_method', $method);
1195 12
        }
1196
1197
        // If the method is something other than GET we will go ahead and attach the
1198
        // CSRF token to the form, as this can't hurt and is convenient to simply
1199
        // always have available on every form the developers creates for them.
1200 128
        if ($method != 'GET') {
1201 56
            $appendage .= $this->token();
1202 42
        }
1203
1204 128
        return $appendage;
1205
    }
1206
1207
    /**
1208
     * Transform the string to an Html serializable object
1209
     *
1210
     * @param $html
1211
     *
1212
     * @return \Illuminate\Support\HtmlString
1213
     */
1214 720
    protected function toHtmlString($html)
1215
    {
1216 720
        return new HtmlString($html);
1217
    }
1218
}
1219