Completed
Push — master ( c1da70...e74ab4 )
by ARCANEDEV
03:22
created

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