Completed
Push — master ( 25b073...1592a3 )
by ARCANEDEV
13s
created

FormBuilder   D

Complexity

Total Complexity 111

Size/Duplication

Total Lines 1150
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 98.44%

Importance

Changes 0
Metric Value
wmc 111
c 0
b 0
f 0
lcom 1
cbo 7
dl 0
loc 1150
rs 4.4102
ccs 253
cts 257
cp 0.9844

58 Methods

Rating   Name   Duplication   Size   Complexity  
A option() 0 7 1
A placeholderOption() 0 8 1
A getSelectedValue() 0 8 4
A checkbox() 0 4 1
A model() 0 6 1
A close() 0 7 1
A token() 0 8 2
A text() 0 4 1
A hidden() 0 4 1
A email() 0 4 1
A tel() 0 4 1
A number() 0 4 1
A time() 0 4 1
A url() 0 4 1
A file() 0 4 1
A setTextAreaSize() 0 14 2
A selectRange() 0 6 1
A getSelectOption() 0 6 2
A getAppendage() 0 20 3
A __construct() 0 11 1
A getSessionStore() 0 4 1
A setSessionStore() 0 6 1
A setModel() 0 6 1
A getIdAttribute() 0 10 3
B getValueAttribute() 0 15 6
A old() 0 6 2
A transformKey() 0 4 1
A oldInputIsEmpty() 0 4 2
A getMethod() 0 6 2
C getCheckboxCheckedState() 0 22 7
A getRadioCheckedState() 0 6 2
A missingOldAndModel() 0 4 2
A reset() 0 4 1
A image() 0 6 1
A submit() 0 4 1
A color() 0 4 1
A getAction() 0 20 4
A getModelValueAttribute() 0 8 2
B open() 0 35 3
A label() 0 8 1
A input() 0 22 3
A password() 0 4 1
A date() 0 8 2
A datetime() 0 8 2
A datetimeLocal() 0 8 2
A textarea() 0 22 2
A setQuickTextAreaSize() 0 9 1
B select() 0 39 5
A selectYear() 0 7 1
A selectMonth() 0 10 2
A optionGroup() 0 10 2
A radio() 0 8 2
A checkable() 0 10 3
A getCheckedState() 0 13 3
A button() 0 10 2
A getUrlAction() 0 6 2
A getRouteAction() 0 6 2
A getControllerAction() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like FormBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FormBuilder, and based on these observations, apply Extract Interface, too.

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 404
    public function __construct(
100
        Contracts\HtmlBuilder $html,
101
        UrlGenerator $url,
102
        Session $session
103
    ) {
104 404
        $this->url       = $url;
105 404
        $this->html      = $html;
106 404
        $this->csrfToken = $session->token();
107
108 404
        $this->setSessionStore($session);
109 404
    }
110
111
    /* -----------------------------------------------------------------
112
     |  Getters & Setters
113
     | -----------------------------------------------------------------
114
     */
115
116
    /**
117
     * Get the session store implementation.
118
     *
119
     * @return  \Illuminate\Contracts\Session\Session
120
     */
121 4
    public function getSessionStore()
122
    {
123 4
        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 404
    public function setSessionStore(Session $session)
134
    {
135 404
        $this->session = $session;
136
137 404
        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 44
    public function setModel($model)
148
    {
149 44
        $this->model = $model;
150
151 44
        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 332
    public function getIdAttribute($name, array $attributes)
163
    {
164 332
        if (array_key_exists('id', $attributes))
165 28
            return $attributes['id'];
166
167 312
        if (in_array($name, $this->labels))
168 8
            return $name;
169
170 304
        return null;
171
    }
172
173
    /**
174
     * Get the value that should be assigned to the field.
175
     *
176
     * @param  string  $name
177
     * @param  mixed   $value
178
     *
179
     * @return mixed
180
     */
181 296
    public function getValueAttribute($name, $value = null)
182
    {
183 296
        if (is_null($name))
184 12
            return $value;
185
186 284
        if ( ! is_null($this->old($name)) && $name !== '_method')
187 16
            return $this->old($name);
188
189 276
        if ( ! is_null($value))
190 156
            return $value;
191
192 160
        return isset($this->model)
193 20
            ? $this->getModelValueAttribute($name)
194 160
            : null;
195
    }
196
197
    /**
198
     * Get the model value that should be assigned to the field.
199
     *
200
     * @param  string  $name
201
     *
202
     * @return mixed
203
     */
204 32
    private function getModelValueAttribute($name)
205
    {
206 32
        $key = $this->transformKey($name);
207
208 32
        return method_exists($this->model, 'getFormValue')
209
            ? $this->model->getFormValue($key)
210 32
            : data_get($this->model, $key);
211
    }
212
213
    /**
214
     * Get a value from the session's old input.
215
     *
216
     * @param  string  $name
217
     *
218
     * @return mixed
219
     */
220 296
    public function old($name)
221
    {
222 296
        return isset($this->session)
223 296
            ? $this->session->getOldInput($this->transformKey($name))
0 ignored issues
show
Bug introduced by
The method getOldInput() does not seem to exist on object<Illuminate\Contracts\Session\Session>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
224 296
            : null;
225
    }
226
227
    /**
228
     * Transform key from array to dot syntax.
229
     *
230
     * @param  string  $key
231
     *
232
     * @return string
233
     */
234 296
    private function transformKey($key)
235
    {
236 296
        return str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $key);
237
    }
238
239
    /**
240
     * Determine if the old input is empty.
241
     *
242
     * @return bool
243
     */
244 16
    public function oldInputIsEmpty()
245
    {
246 16
        return isset($this->session) && (count($this->session->getOldInput()) == 0);
0 ignored issues
show
Bug introduced by
The method getOldInput() does not seem to exist on object<Illuminate\Contracts\Session\Session>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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