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

FormBuilder::datetimeLocal()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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