Completed
Pull Request — master (#20)
by ARCANEDEV
07:24
created

FormBuilder::getModel()   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 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php namespace Arcanedev\LaravelHtml;
2
3
use Arcanedev\LaravelHtml\Bases\Builder;
4
use Arcanedev\LaravelHtml\Contracts\FormBuilder as FormBuilderContract;
5
use DateTime;
6
use Illuminate\Contracts\Routing\UrlGenerator;
7
use Illuminate\Contracts\Session\Session;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\Collection;
10
11
/**
12
 * Class     FormBuilder
13
 *
14
 * @package  Arcanedev\LaravelHtml
15
 * @author   ARCANEDEV <[email protected]>
16
 */
17
class FormBuilder extends Builder implements FormBuilderContract
18
{
19
    /* -----------------------------------------------------------------
20
     |  Properties
21
     | -----------------------------------------------------------------
22
     */
23
24
    /**
25
    * The HTML builder instance.
26
    *
27
    * @var \Arcanedev\LaravelHtml\Contracts\HtmlBuilder
28
    */
29
    protected $html;
30
31
    /**
32
    * The URL generator instance.
33
    *
34
    * @var \Illuminate\Contracts\Routing\UrlGenerator
35
    */
36
    protected $url;
37
38
    /**
39
    * The CSRF token used by the form builder.
40
    *
41
    * @var string
42
    */
43
    protected $csrfToken;
44
45
    /**
46
    * The session store implementation.
47
    *
48
    * @var \Illuminate\Contracts\Session\Session
49
    */
50
    protected $session;
51
52
    /**
53
    * The current model instance for the form.
54
    *
55
    * @var \Illuminate\Database\Eloquent\Model
56
    */
57
    protected $model;
58
59
    /**
60
    * An array of label names we've created.
61
    *
62
    * @var array
63
    */
64
    protected $labels = [];
65
66
    /**
67
    * The reserved form open attributes.
68
    *
69
    * @var array
70
    */
71
    protected $reserved = ['method', 'url', 'route', 'action', 'files'];
72
73
    /**
74
    * The form methods that should be spoofed, in uppercase.
75
    *
76
    * @var array
77
    */
78
    protected $spoofedMethods = ['DELETE', 'PATCH', 'PUT'];
79
80
    /**
81
    * The types of inputs to not fill values on by default.
82
    *
83
    * @var array
84
    */
85
    protected $skipValueTypes = ['file', 'password', 'checkbox', 'radio'];
86
87
    /* -----------------------------------------------------------------
88
     |  Constructor
89
     | -----------------------------------------------------------------
90
     */
91
92
    /**
93
    * Create a new form builder instance.
94
    *
95
    * @param  \Arcanedev\LaravelHtml\Contracts\HtmlBuilder  $html
96
    * @param  \Illuminate\Contracts\Routing\UrlGenerator    $url
97
    * @param  \Illuminate\Contracts\Session\Session         $session
98
    */
99 303
    public function __construct(
100
        Contracts\HtmlBuilder $html,
101
        UrlGenerator $url,
102
        Session $session
103
    ) {
104 303
        $this->url       = $url;
105 303
        $this->html      = $html;
106 303
        $this->csrfToken = $session->token();
107
108 303
        $this->setSessionStore($session);
109 303
    }
110
111
    /* -----------------------------------------------------------------
112
     |  Getters & Setters
113
     | -----------------------------------------------------------------
114
     */
115
116
    /**
117
     * Get the session store implementation.
118
     *
119
     * @return  \Illuminate\Contracts\Session\Session
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\Contracts\Session\Session  $session
130
     *
131
     * @return self
132
     */
133 303
    public function setSessionStore(Session $session)
134
    {
135 303
        $this->session = $session;
136
137 303
        return $this;
138
    }
139
140
    /**
141
     * Set the model instance on the form builder.
142
     *
143
     * @param  \Illuminate\Database\Eloquent\Model  $model
144
     *
145
     * @return self
146
     */
147 33
    public function setModel($model)
148
    {
149 33
        $this->model = $model;
150
151 33
        return $this;
152
    }
153
154
    /**
155
     * Get the model instance on the form builder.
156
     *
157
     * @return \Illuminate\Database\Eloquent\Model
158
     */
159 24
    public function getModel()
160
    {
161 24
        return $this->model;
162
    }
163
164
    /**
165
     * Get the ID attribute for a field name.
166
     *
167
     * @param  string  $name
168
     * @param  array   $attributes
169
     *
170
     * @return string
171
     */
172 249
    public function getIdAttribute($name, array $attributes)
173
    {
174 249
        if (array_key_exists('id', $attributes))
175 21
            return $attributes['id'];
176
177 234
        if (in_array($name, $this->labels))
178 6
            return $name;
179
180 228
        return null;
181
    }
182
183
    /**
184
     * Get the value that should be assigned to the field.
185
     *
186
     * @param  string  $name
187
     * @param  mixed   $value
188
     *
189
     * @return mixed
190
     */
191 222
    public function getValueAttribute($name, $value = null)
192
    {
193 222
        if (is_null($name))
194 9
            return $value;
195
196 213
        if ( ! is_null($this->old($name)) && $name !== '_method')
197 12
            return $this->old($name);
198
199 207
        if ( ! is_null($value))
200 117
            return $value;
201
202 120
        return isset($this->model)
203 15
            ? $this->getModelValueAttribute($name)
204 120
            : null;
205
    }
206
207
    /**
208
     * Get the model value that should be assigned to the field.
209
     *
210
     * @param  string  $name
211
     *
212
     * @return mixed
213
     */
214 24
    private function getModelValueAttribute($name)
215
    {
216 24
        $key = $this->transformKey($name);
217
218 24
        return method_exists($this->getModel(), 'getFormValue')
219
            ? $this->getModel()->getFormValue($key)
220 24
            : data_get($this->getModel(), $key);
221
    }
222
223
    /**
224
     * Get a value from the session's old input.
225
     *
226
     * @param  string  $name
227
     *
228
     * @return mixed
229
     */
230 222
    public function old($name)
231
    {
232 222
        return isset($this->session)
233 222
            ? $this->session->getOldInput($this->transformKey($name))
234 222
            : null;
235
    }
236
237
    /**
238
     * Transform key from array to dot syntax.
239
     *
240
     * @param  string  $key
241
     *
242
     * @return string
243
     */
244 222
    private function transformKey($key)
245
    {
246 222
        return str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $key);
247
    }
248
249
    /**
250
     * Determine if the old input is empty.
251
     *
252
     * @return bool
253
     */
254 12
    public function oldInputIsEmpty()
255
    {
256 12
        return isset($this->session) && (count($this->session->getOldInput()) == 0);
257
    }
258
259
    /**
260
     * Parse the form action method.
261
     *
262
     * @param  string  $method
263
     *
264
     * @return string
265
     */
266 48
    private function getMethod($method)
267
    {
268 48
        $method = strtoupper($method);
269
270 48
        return $method !== 'GET' ? 'POST' : $method;
271
    }
272
273
    /* -----------------------------------------------------------------
274
     |  Main Methods
275
     | -----------------------------------------------------------------
276
     */
277
278
    /**
279
     * Open up a new HTML form.
280
     *
281
     * @param  array  $options
282
     *
283
     * @return \Illuminate\Support\HtmlString
284
     */
285 48
    public function open(array $options = [])
286
    {
287 48
        $method = Arr::get($options, 'method', 'post');
288
289
        // We need to extract the proper method from the attributes. If the method is
290
        // something other than GET or POST we'll use POST since we will spoof the
291
        // actual method since forms don't support the reserved methods in HTML.
292
        $attributes = [
293 48
            'method'         => $this->getMethod($method),
294 48
            'action'         => $this->getAction($options),
295 48
            'accept-charset' => 'UTF-8',
296
        ];
297
298 48
        if (isset($options['files']) && $options['files']) {
299 6
            $options['enctype'] = 'multipart/form-data';
300
        }
301
302
        // Finally we're ready to create the final form HTML field. We will attribute
303
        // format the array of attributes. We will also add on the appendage which
304
        // is used to spoof requests for this PUT, PATCH, etc. methods on forms.
305 48
        $attributes = array_merge(
306 48
            $attributes, array_except($options, $this->reserved)
307
        );
308
309
        // Finally, we will concatenate all of the attributes into a single string so
310
        // we can build out the final form open statement. We'll also append on an
311
        // extra value for the hidden _method field if it's needed for the form.
312 48
        $attributes = $this->html->attributes($attributes);
313
314
        // If the method is PUT, PATCH or DELETE we will need to add a spoofer hidden
315
        // field that will instruct the Symfony request to pretend the method is a
316
        // different method than it actually is, for convenience from the forms.
317 48
        $append = $this->getAppendage($method);
318
319 48
        return $this->toHtmlString('<form'.$attributes.'>' . $append);
320
    }
321
322
    /**
323
     * Create a new model based form builder.
324
     *
325
     * @param  mixed  $model
326
     * @param  array  $options
327
     *
328
     * @return \Illuminate\Support\HtmlString
329
     */
330 15
    public function model($model, array $options = [])
331
    {
332 15
        $this->setModel($model);
333
334 15
        return $this->open($options);
335
    }
336
337
    /**
338
     * Close the current form.
339
     *
340
     * @return \Illuminate\Support\HtmlString
341
     */
342 6
    public function close()
343
    {
344 6
        $this->labels = [];
345 6
        $this->setModel(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<Illuminate\Database\Eloquent\Model>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
346
347 6
        return $this->toHtmlString('</form>');
348
    }
349
350
    /**
351
     * Generate a hidden field with the current CSRF token.
352
     *
353
     * @return \Illuminate\Support\HtmlString
354
     */
355 21
    public function token()
356
    {
357 21
        $token = ! empty($this->csrfToken)
358 15
            ? $this->csrfToken
359 21
            : $this->session->token();
360
361 21
        return $this->hidden('_token', $token);
362
    }
363
364
    /**
365
     * Create a form label element.
366
     *
367
     * @param  string  $name
368
     * @param  string  $value
369
     * @param  array   $options
370
     * @param  bool    $escaped
371
     *
372
     * @return \Illuminate\Support\HtmlString
373
     */
374 15
    public function label($name, $value = null, array $options = [], $escaped = true)
375
    {
376 15
        $this->labels[] = $name;
377
378 15
        return $this->toHtmlString(
379 15
            Helpers\Label::make($name, $value, $options, $escaped)
380
        );
381
    }
382
383
    /**
384
     * Create a form input field.
385
     *
386
     * @param  string  $type
387
     * @param  string  $name
388
     * @param  string  $value
389
     * @param  array   $options
390
     *
391
     * @return \Illuminate\Support\HtmlString
392
     */
393 189
    public function input($type, $name, $value = null, array $options = [])
394
    {
395 189
        if ( ! isset($options['name'])) {
396 189
            $options['name'] = $name;
397
        }
398
399
        // We will get the appropriate value for the given field. We will look for the
400
        // value in the session for the value in the old input data then we'll look
401
        // in the model instance if one is set. Otherwise we will just use empty.
402 189
        $id = $this->getIdAttribute($name, $options);
403
404 189
        if ( ! in_array($type, $this->skipValueTypes)) {
405 153
            $value = $this->getValueAttribute($name, $value);
406
        }
407
408
        // Once we have the type, value, and ID we can merge them into the rest of the
409
        // attributes array so we can convert them into their HTML attribute format
410
        // when creating the HTML element. Then, we will return the entire input.
411 189
        $options = array_merge($options, compact('type', 'value', 'id'));
412
413 189
        return $this->toHtmlString('<input'.$this->html->attributes($options).'>');
414
    }
415
416
    /**
417
     * Create a text input field.
418
     *
419
     * @param  string  $name
420
     * @param  string  $value
421
     * @param  array   $options
422
     *
423
     * @return \Illuminate\Support\HtmlString
424
     */
425 21
    public function text($name, $value = null, array $options = [])
426
    {
427 21
        return $this->input('text', $name, $value, $options);
428
    }
429
430
    /**
431
     * Create a password input field.
432
     *
433
     * @param  string  $name
434
     * @param  array   $options
435
     *
436
     * @return \Illuminate\Support\HtmlString
437
     */
438 9
    public function password($name, array $options = [])
439
    {
440 9
        return $this->input('password', $name, '', $options);
441
    }
442
443
    /**
444
     * Create a hidden input field.
445
     *
446
     * @param  string  $name
447
     * @param  string  $value
448
     * @param  array   $options
449
     *
450
     * @return \Illuminate\Support\HtmlString
451
     */
452 30
    public function hidden($name, $value = null, array $options = [])
453
    {
454 30
        return $this->input('hidden', $name, $value, $options);
455
    }
456
457
    /**
458
     * Create an e-mail input field.
459
     *
460
     * @param  string  $name
461
     * @param  string  $value
462
     * @param  array   $options
463
     *
464
     * @return \Illuminate\Support\HtmlString
465
     */
466 9
    public function email($name, $value = null, array $options = [])
467
    {
468 9
        return $this->input('email', $name, $value, $options);
469
    }
470
471
    /**
472
     * Create a tel input field.
473
     *
474
     * @param  string  $name
475
     * @param  string  $value
476
     * @param  array   $options
477
     *
478
     * @return \Illuminate\Support\HtmlString
479
     */
480 9
    public function tel($name, $value = null, array $options = [])
481
    {
482 9
        return $this->input('tel', $name, $value, $options);
483
    }
484
485
    /**
486
     * Create a number input field.
487
     *
488
     * @param  string  $name
489
     * @param  string  $value
490
     * @param  array   $options
491
     *
492
     * @return \Illuminate\Support\HtmlString
493
     */
494 9
    public function number($name, $value = null, array $options = [])
495
    {
496 9
        return $this->input('number', $name, $value, $options);
497
    }
498
499
    /**
500
     * Create a date input field.
501
     *
502
     * @param  string  $name
503
     * @param  string  $value
504
     * @param  array   $options
505
     *
506
     * @return \Illuminate\Support\HtmlString
507
     */
508 12
    public function date($name, $value = null, array $options = [])
509
    {
510 12
        if ($value instanceof DateTime) {
511 3
            $value = $value->format('Y-m-d');
512
        }
513
514 12
        return $this->input('date', $name, $value, $options);
515
    }
516
517
    /**
518
     * Create a datetime input field.
519
     *
520
     * @param  string  $name
521
     * @param  string  $value
522
     * @param  array   $options
523
     *
524
     * @return \Illuminate\Support\HtmlString
525
     */
526 12
    public function datetime($name, $value = null, array $options = [])
527
    {
528 12
        if ($value instanceof DateTime) {
529 6
            $value = $value->format(DateTime::RFC3339);
530
        }
531
532 12
        return $this->input('datetime', $name, $value, $options);
533
    }
534
535
    /**
536
     * Create a datetime-local input field.
537
     *
538
     * @param  string  $name
539
     * @param  string  $value
540
     * @param  array   $options
541
     *
542
     * @return \Illuminate\Support\HtmlString
543
     */
544 12
    public function datetimeLocal($name, $value = null, array $options = [])
545
    {
546 12
        if ($value instanceof DateTime) {
547 6
            $value = $value->format('Y-m-d\TH:i');
548
        }
549
550 12
        return $this->input('datetime-local', $name, $value, $options);
551
    }
552
553
    /**
554
     * Create a time input field.
555
     *
556
     * @param  string  $name
557
     * @param  string  $value
558
     * @param  array   $options
559
     *
560
     * @return \Illuminate\Support\HtmlString
561
     */
562 9
    public function time($name, $value = null, array $options = [])
563
    {
564 9
        return $this->input('time', $name, $value, $options);
565
    }
566
567
    /**
568
     * Create a url input field.
569
     *
570
     * @param  string  $name
571
     * @param  string  $value
572
     * @param  array   $options
573
     *
574
     * @return \Illuminate\Support\HtmlString
575
     */
576 6
    public function url($name, $value = null, array $options = [])
577
    {
578 6
        return $this->input('url', $name, $value, $options);
579
    }
580
581
    /**
582
     * Create a file input field.
583
     *
584
     * @param  string  $name
585
     * @param  array   $options
586
     *
587
     * @return \Illuminate\Support\HtmlString
588
     */
589 9
    public function file($name, array $options = [])
590
    {
591 9
        return $this->input('file', $name, null, $options);
592
    }
593
594
    /**
595
     * Create a textarea input field.
596
     *
597
     * @param  string  $name
598
     * @param  string  $value
599
     * @param  array   $options
600
     *
601
     * @return \Illuminate\Support\HtmlString
602
     */
603 18
    public function textarea($name, $value = null, array $options = [])
604
    {
605 18
        if ( ! isset($options['name'])) {
606 18
            $options['name'] = $name;
607
        }
608
609
        // Next we will look for the rows and cols attributes, as each of these are put
610
        // on the textarea element definition. If they are not present, we will just
611
        // assume some sane default values for these attributes for the developer.
612 18
        $options       = $this->setTextAreaSize($options);
613 18
        $options['id'] = $this->getIdAttribute($name, $options);
614 18
        $value         = (string) $this->getValueAttribute($name, $value);
615
616 18
        unset($options['size']);
617
618
        // Next we will convert the attributes into a string form. Also we have removed
619
        // the size attribute, as it was merely a short-cut for the rows and cols on
620
        // the element. Then we'll create the final textarea elements HTML for us.
621 18
        $options = $this->html->attributes($options);
622
623 18
        return $this->toHtmlString('<textarea'.$options.'>'.$this->html->escape($value).'</textarea>');
624
    }
625
626
    /**
627
     * Set the text area size on the attributes.
628
     *
629
     * @param  array  $options
630
     *
631
     * @return array
632
     */
633 18
    private function setTextAreaSize(array $options)
634
    {
635 18
        if (isset($options['size'])) {
636 9
            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 9
        $cols = Arr::get($options, 'cols', 50);
643 9
        $rows = Arr::get($options, 'rows', 10);
644
645 9
        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 9
    protected function setQuickTextAreaSize(array $options)
656
    {
657 9
        list($cols, $rows) = explode('x', $options['size']);
658
659 9
        return array_merge($options, compact('cols', 'rows'));
660
    }
661
662
    /**
663
     * Create a select box field.
664
     *
665
     * @param  string                                $name
666
     * @param  array|\Illuminate\Support\Collection  $list
667
     * @param  string                                $selected
668
     * @param  array                                 $options
669
     *
670
     * @return \Illuminate\Support\HtmlString
671
     */
672 42
    public function select($name, $list = [], $selected = null, array $options = [])
673
    {
674
        // When building a select box the "value" attribute is really the selected one
675
        // so we will use that when checking the model or session for a value which
676
        // should provide a convenient method of re-populating the forms on post.
677 42
        $selected = $this->getValueAttribute($name, $selected);
678
679
        // Transform to array if it is a collection
680 42
        if ($selected instanceof Collection) {
681 3
            $selected = $selected->all();
682
        }
683
684 42
        $options['id'] = $this->getIdAttribute($name, $options);
685
686 42
        if ( ! isset($options['name'])) {
687 30
            $options['name'] = $name;
688
        }
689
690
        // We will simply loop through the options and build an HTML value for each of
691
        // them until we have an array of HTML declarations. Then we will join them
692
        // all together into one single HTML element that can be put on the form.
693 42
        $html = [];
694
695 42
        if (isset($options['placeholder'])) {
696 3
            $html[] = $this->placeholderOption($options['placeholder'], $selected);
697 3
            unset($options['placeholder']);
698
        }
699
700 42
        foreach($list as $value => $display) {
701 39
            $html[] = $this->getSelectOption($display, $value, $selected);
702
        }
703
704
        // Once we have all of this HTML, we can join this into a single element after
705
        // formatting the attributes into an HTML "attributes" string, then we will
706
        // build out a final select statement, which will contain all the values.
707 42
        $options = $this->html->attributes($options);
708
709 42
        return $this->toHtmlString("<select{$options}>".implode('', $html).'</select>');
710
    }
711
712
    /**
713
     * Create a select range field.
714
     *
715
     * @param  string  $name
716
     * @param  string  $begin
717
     * @param  string  $end
718
     * @param  string  $selected
719
     * @param  array   $options
720
     *
721
     * @return \Illuminate\Support\HtmlString
722
     */
723 6
    public function selectRange($name, $begin, $end, $selected = null, array $options = [])
724
    {
725 6
        $range = array_combine($range = range($begin, $end), $range);
726
727 6
        return $this->select($name, $range, $selected, $options);
728
    }
729
730
    /**
731
     * Create a select year field.
732
     *
733
     * @param  string  $name
734
     * @param  string  $begin
735
     * @param  string  $end
736
     * @param  string  $selected
737
     * @param  array   $options
738
     *
739
     * @return \Illuminate\Support\HtmlString
740
     */
741 3
    public function selectYear($name, $begin, $end, $selected = null, array $options = [])
742
    {
743 3
        return call_user_func_array(
744 3
            [$this, 'selectRange'],
745 3
            compact('name', 'begin', 'end', 'selected', 'options')
746
        );
747
    }
748
749
    /**
750
     * Create a select month field.
751
     *
752
     * @param  string  $name
753
     * @param  string  $selected
754
     * @param  array   $options
755
     * @param  string  $format
756
     *
757
     * @return \Illuminate\Support\HtmlString
758
     */
759 3
    public function selectMonth($name, $selected = null, array $options = [], $format = '%B')
760
    {
761 3
        $months = [];
762
763 3
        foreach(range(1, 12) as $month) {
764 3
            $months[$month] = strftime($format, mktime(0, 0, 0, $month, 1));
765
        }
766
767 3
        return $this->select($name, $months, $selected, $options);
768
    }
769
770
    /**
771
     * Get the select option for the given value.
772
     *
773
     * @param  string  $display
774
     * @param  string  $value
775
     * @param  string  $selected
776
     *
777
     * @return string
778
     */
779 39
    private function getSelectOption($display, $value, $selected)
780
    {
781 39
        return is_array($display)
782 6
            ? $this->optionGroup($display, $value, $selected)
783 39
            : $this->option($display, $value, $selected);
784
    }
785
786
    /**
787
     * Create an option group form element.
788
     *
789
     * @param  array   $list
790
     * @param  string  $label
791
     * @param  string  $selected
792
     *
793
     * @return string
794
     */
795 6
    private function optionGroup(array $list, $label, $selected)
796
    {
797 6
        $html = [];
798
799 6
        foreach($list as $value => $display) {
800 6
            $html[] = $this->option($display, $value, $selected);
801
        }
802
803 6
        return '<optgroup label="'.$this->html->escape($label).'">'.implode('', $html).'</optgroup>';
804
    }
805
806
    /**
807
     * Create a select element option.
808
     *
809
     * @param  string  $display
810
     * @param  string  $value
811
     * @param  string  $selected
812
     *
813
     * @return string
814
     */
815 39
    private function option($display, $value, $selected)
816
    {
817 39
        $selected = $this->getSelectedValue($value, $selected);
818 39
        $options  = compact('value', 'selected');
819
820 39
        return '<option'.$this->html->attributes($options).'>'.$this->html->escape($display).'</option>';
821
    }
822
823
    /**
824
     * Create a placeholder select element option.
825
     *
826
     * @param  string  $display
827
     * @param  string  $selected
828
     *
829
     * @return string
830
     */
831 3
    private function placeholderOption($display, $selected)
832
    {
833 3
        $selected = $this->getSelectedValue(null, $selected);
834 3
        $options  = array_merge(compact('selected'), ['value' => '']);
835
836 3
        return '<option'.$this->html->attributes($options).'>'.$this->html->escape($display).'</option>';
837
    }
838
839
    /**
840
     * Determine if the value is selected.
841
     *
842
     * @param  string  $value
843
     * @param  string  $selected
844
     *
845
     * @return string|null
846
     */
847 39
    private function getSelectedValue($value, $selected)
848
    {
849 39
        if (is_array($selected)) {
850 12
            return in_array($value, $selected) ? 'selected' : null;
851
        }
852
853 30
        return ((string) $value === (string) $selected) ? 'selected' : null;
854
    }
855
856
    /**
857
     * Create a checkbox input field.
858
     *
859
     * @param  string     $name
860
     * @param  mixed      $value
861
     * @param  bool|null  $checked
862
     * @param  array      $options
863
     *
864
     * @return \Illuminate\Support\HtmlString
865
     */
866 12
    public function checkbox($name, $value = 1, $checked = null, array $options = [])
867
    {
868 12
        return $this->checkable('checkbox', $name, $value, $checked, $options);
869
    }
870
871
    /**
872
     * Create a radio button input field.
873
     *
874
     * @param  string  $name
875
     * @param  mixed   $value
876
     * @param  bool    $checked
877
     * @param  array   $options
878
     *
879
     * @return \Illuminate\Support\HtmlString
880
     */
881 6
    public function radio($name, $value = null, $checked = null, array $options = [])
882
    {
883 6
        $value = $value ?? $name;
884
885 6
        return $this->checkable('radio', $name, $value, $checked, $options);
886
    }
887
888
    /**
889
     * Create a checkable input field.
890
     *
891
     * @param  string     $type
892
     * @param  string     $name
893
     * @param  mixed      $value
894
     * @param  bool|null  $checked
895
     * @param  array      $options
896
     *
897
     * @return \Illuminate\Support\HtmlString
898
     */
899 21
    protected function checkable($type, $name, $value, $checked, array $options)
900
    {
901 21
        $checked = $this->getCheckedState($type, $name, $value, $checked);
902
903 21
        if ( ! is_null($checked) && $checked) {
904 18
            $options['checked'] = 'checked';
905
        }
906
907 21
        return $this->input($type, $name, $value, $options);
908
    }
909
910
    /**
911
     * Get the check state for a checkable input.
912
     *
913
     * @param  string     $type
914
     * @param  string     $name
915
     * @param  mixed      $value
916
     * @param  bool|null  $checked
917
     *
918
     * @return bool
919
     */
920 21
    private function getCheckedState($type, $name, $value, $checked)
921
    {
922 7
        switch($type) {
923 14
            case 'checkbox':
924 12
                return $this->getCheckboxCheckedState($name, $value, $checked);
925
926 6
            case 'radio':
927 6
                return $this->getRadioCheckedState($name, $value, $checked);
928
929
            default:
930 3
                return $this->getValueAttribute($name) === $value;
931
        }
932
    }
933
934
    /**
935
     * Get the check state for a checkbox input.
936
     *
937
     * @param  string     $name
938
     * @param  mixed      $value
939
     * @param  bool|null  $checked
940
     *
941
     * @return bool
942
     */
943 12
    private function getCheckboxCheckedState($name, $value, $checked)
944
    {
945 12
        if (isset($this->session) && ! $this->oldInputIsEmpty() && is_null($this->old($name))) {
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 3
            ? $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 \Illuminate\Support\HtmlString
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 \Illuminate\Support\HtmlString
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 \Illuminate\Support\HtmlString
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 \Illuminate\Support\HtmlString
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
        }
1049
1050 3
        return $this->toHtmlString(
1051 3
            '<button'.$this->html->attributes($options).'>'.$value.'</button>'
1052
        );
1053
    }
1054
1055
    /**
1056
     * Create a color input field.
1057
     *
1058
     * @param  string  $name
1059
     * @param  string  $value
1060
     * @param  array   $options
1061
     *
1062
     * @return \Illuminate\Support\HtmlString
1063
     */
1064 9
    public function color($name, $value = null, array $options = [])
1065
    {
1066 9
        return $this->input('color', $name, $value, $options);
1067
    }
1068
1069
    /* -----------------------------------------------------------------
1070
     |  Other Methods
1071
     | -----------------------------------------------------------------
1072
     */
1073
1074
    /**
1075
     * Get the form action from the options.
1076
     *
1077
     * @param  array  $options
1078
     *
1079
     * @return string
1080
     */
1081 48
    private function getAction(array $options)
1082
    {
1083
        // We will also check for a "route" or "action" parameter on the array so that
1084
        // developers can easily specify a route or controller action when creating
1085
        // a form providing a convenient interface for creating the form actions.
1086 48
        if (isset($options['url'])) {
1087 15
            return $this->getUrlAction($options['url']);
1088
        }
1089 33
        elseif (isset($options['route'])) {
1090 3
            return $this->getRouteAction($options['route']);
1091
        }
1092 33
        elseif (isset($options['action'])) {
1093
            // If an action is available, we are attempting to open a form to a controller
1094
            // action route. So, we will use the URL generator to get the path to these
1095
            // actions and return them from the method. Otherwise, we'll use current.
1096 3
            return $this->getControllerAction($options['action']);
1097
        }
1098
1099 30
        return $this->url->current();
1100
    }
1101
1102
    /**
1103
     * Get the action for a "url" option.
1104
     *
1105
     * @param  array|string  $options
1106
     *
1107
     * @return string
1108
     */
1109 15
    private function getUrlAction($options)
1110
    {
1111 15
        return is_array($options)
1112
            ? $this->url->to($options[0], array_slice($options, 1))
1113 15
            : $this->url->to($options);
1114
    }
1115
1116
    /**
1117
     * Get the action for a "route" option.
1118
     *
1119
     * @param  array|string  $options
1120
     *
1121
     * @return string
1122
     */
1123 3
    private function getRouteAction($options)
1124
    {
1125 3
        return is_array($options)
1126
            ? $this->url->route($options[0], array_slice($options, 1))
1127 3
            : $this->url->route($options);
1128
    }
1129
1130
    /**
1131
     * Get the action for an "action" option.
1132
     *
1133
     * @param  array|string  $options
1134
     *
1135
     * @return string
1136
     */
1137 3
    private function getControllerAction($options)
1138
    {
1139 3
        return is_array($options)
1140
            ? $this->url->action($options[0], array_slice($options, 1))
1141 3
            : $this->url->action($options);
1142
    }
1143
1144
    /**
1145
     * Get the form appendage for the given method.
1146
     *
1147
     * @param  string  $method
1148
     *
1149
     * @return string
1150
     */
1151 48
    private function getAppendage($method)
1152
    {
1153 48
        list($method, $appendage) = [strtoupper($method), ''];
1154
1155
        // If the HTTP method is in this list of spoofed methods, we will attach the
1156
        // method spoofer hidden input to the form. This allows us to use regular
1157
        // form to initiate PUT and DELETE requests in addition to the typical.
1158 48
        if (in_array($method, $this->spoofedMethods)) {
1159 6
            $appendage .= $this->hidden('_method', $method);
1160
        }
1161
1162
        // If the method is something other than GET we will go ahead and attach the
1163
        // CSRF token to the form, as this can't hurt and is convenient to simply
1164
        // always have available on every form the developers creates for them.
1165 48
        if ($method !== 'GET') {
1166 21
            $appendage .= $this->token();
1167
        }
1168
1169 48
        return $appendage;
1170
    }
1171
}
1172