Html::token()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php namespace Anomaly\Streams\Platform\Support;
2
3
use DateTime;
4
use BadMethodCallException;
5
use Illuminate\Support\Collection;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Anomaly\Streams\Platform\Support\Collection.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Illuminate\Support\HtmlString;
7
use Illuminate\Contracts\View\Factory;
8
use Illuminate\Session\SessionInterface;
9
use Illuminate\Support\Traits\Macroable;
10
use Illuminate\Contracts\Routing\UrlGenerator;
11
12
class Html
13
{
14
    use Macroable, Componentable {
15
        Macroable::__call as macroCall;
16
        Componentable::__call as componentCall;
17
    }
18
19
    /**
20
     * The HTML builder instance.
21
     *
22
     * @var \Collective\Html\HtmlBuilder
23
     */
24
    protected $html;
25
26
    /**
27
     * The URL generator instance.
28
     *
29
     * @var \Illuminate\Contracts\Routing\UrlGenerator
30
     */
31
    protected $url;
32
33
    /**
34
     * The View factory instance.
35
     *
36
     * @var \Illuminate\Contracts\View\Factory
37
     */
38
    protected $view;
39
40
    /**
41
     * The CSRF token used by the form builder.
42
     *
43
     * @var string
44
     */
45
    protected $csrfToken;
46
47
    /**
48
     * The session store implementation.
49
     *
50
     * @var \Illuminate\Session\SessionInterface
51
     */
52
    protected $session;
53
54
    /**
55
     * The current model instance for the form.
56
     *
57
     * @var mixed
58
     */
59
    protected $model;
60
61
    /**
62
     * An array of label names we've created.
63
     *
64
     * @var array
65
     */
66
    protected $labels = [];
67
68
    /**
69
     * The reserved form open attributes.
70
     *
71
     * @var array
72
     */
73
    protected $reserved = ['method', 'url', 'route', 'action', 'files'];
74
75
    /**
76
     * The form methods that should be spoofed, in uppercase.
77
     *
78
     * @var array
79
     */
80
    protected $spoofedMethods = ['DELETE', 'PATCH', 'PUT'];
81
82
    /**
83
     * The types of inputs to not fill values on by default.
84
     *
85
     * @var array
86
     */
87
    protected $skipValueTypes = ['file', 'password', 'checkbox', 'radio'];
88
89
    /**
90
     * Create a new form builder instance.
91
     *
92
     * @param \Collective\Html\HtmlBuilder               $html
93
     * @param \Illuminate\Contracts\Routing\UrlGenerator $url
94
     * @param \Illuminate\Contracts\View\Factory         $view
95
     * @param string                                     $csrfToken
96
     */
97
    public function __construct(HtmlBuilder $html, UrlGenerator $url, Factory $view, $csrfToken)
98
    {
99
        $this->url       = $url;
100
        $this->html      = $html;
0 ignored issues
show
Documentation Bug introduced by
It seems like $html of type object<Anomaly\Streams\P...rm\Support\HtmlBuilder> is incompatible with the declared type object<Collective\Html\HtmlBuilder> of property $html.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
101
        $this->view      = $view;
102
        $this->csrfToken = $csrfToken;
103
    }
104
105
    /**
106
     * Open up a new HTML form.
107
     *
108
     * @param array $options
109
     *
110
     * @return \Illuminate\Support\HtmlString
111
     */
112
    public function open(array $options = [])
113
    {
114
        $method = array_get($options, 'method', 'post');
115
116
        // We need to extract the proper method from the attributes. If the method is
117
        // something other than GET or POST we'll use POST since we will spoof the
118
        // actual method since forms don't support the reserved methods in HTML.
119
        $attributes['method'] = $this->getMethod($method);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$attributes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $attributes = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
120
121
        $attributes['action'] = $this->getAction($options);
122
123
        $attributes['accept-charset'] = 'UTF-8';
124
125
        // If the method is PUT, PATCH or DELETE we will need to add a spoofer hidden
126
        // field that will instruct the Symfony request to pretend the method is a
127
        // different method than it actually is, for convenience from the forms.
128
        $append = $this->getAppendage($method);
129
130
        if (isset($options['files']) && $options['files']) {
131
            $options['enctype'] = 'multipart/form-data';
132
        }
133
134
        // Finally we're ready to create the final form HTML field. We will attribute
135
        // format the array of attributes. We will also add on the appendage which
136
        // is used to spoof requests for this PUT, PATCH, etc. methods on forms.
137
        $attributes = array_merge(
138
139
          $attributes, array_except($options, $this->reserved)
140
141
        );
142
143
        // Finally, we will concatenate all of the attributes into a single string so
144
        // we can build out the final form open statement. We'll also append on an
145
        // extra value for the hidden _method field if it's needed for the form.
146
        $attributes = $this->html->attributes($attributes);
147
148
        return $this->toHtmlString('<form' . $attributes . '>' . $append);
149
    }
150
151
    /**
152
     * Create a new model based form builder.
153
     *
154
     * @param mixed $model
155
     * @param array $options
156
     *
157
     * @return \Illuminate\Support\HtmlString
158
     */
159
    public function model($model, array $options = [])
160
    {
161
        $this->model = $model;
162
163
        return $this->open($options);
164
    }
165
166
    /**
167
     * Set the model instance on the form builder.
168
     *
169
     * @param mixed $model
170
     *
171
     * @return void
172
     */
173
    public function setModel($model)
174
    {
175
        $this->model = $model;
176
    }
177
178
    /**
179
     * Close the current form.
180
     *
181
     * @return string
182
     */
183
    public function close()
184
    {
185
        $this->labels = [];
186
187
        $this->model = null;
188
189
        return $this->toHtmlString('</form>');
190
    }
191
192
    /**
193
     * Generate a hidden field with the current CSRF token.
194
     *
195
     * @return string
196
     */
197
    public function token()
198
    {
199
        $token = ! empty($this->csrfToken) ? $this->csrfToken : $this->session->getToken();
200
201
        return $this->hidden('_token', $token);
202
    }
203
204
    /**
205
     * Create a form label element.
206
     *
207
     * @param string $name
208
     * @param string $value
209
     * @param array  $options
210
     * @param bool   $escape_html
211
     *
212
     * @return \Illuminate\Support\HtmlString
213
     */
214
    public function label($name, $value = null, $options = [], $escape_html = true)
215
    {
216
        $this->labels[] = $name;
217
218
        $options = $this->html->attributes($options);
219
220
        $value = $this->formatLabel($name, $value);
221
222
        if ($escape_html) {
223
            $value = $this->html->entities($value);
224
        }
225
226
        return $this->toHtmlString('<label for="' . $name . '"' . $options . '>' . $value . '</label>');
227
    }
228
229
    /**
230
     * Format the label value.
231
     *
232
     * @param string      $name
233
     * @param string|null $value
234
     *
235
     * @return string
236
     */
237
    protected function formatLabel($name, $value)
238
    {
239
        return $value ?: ucwords(str_replace('_', ' ', $name));
240
    }
241
242
    /**
243
     * Create a form input field.
244
     *
245
     * @param string $type
246
     * @param string $name
247
     * @param string $value
248
     * @param array  $options
249
     *
250
     * @return \Illuminate\Support\HtmlString
251
     */
252
    public function input($type, $name, $value = null, $options = [])
253
    {
254
        if (! isset($options['name'])) {
255
            $options['name'] = $name;
256
        }
257
258
        // We will get the appropriate value for the given field. We will look for the
259
        // value in the session for the value in the old input data then we'll look
260
        // in the model instance if one is set. Otherwise we will just use empty.
261
        $id = $this->getIdAttribute($name, $options);
262
263
        if (! in_array($type, $this->skipValueTypes)) {
264
            $value = $this->getValueAttribute($name, $value);
265
        }
266
267
        // Once we have the type, value, and ID we can merge them into the rest of the
268
        // attributes array so we can convert them into their HTML attribute format
269
        // when creating the HTML element. Then, we will return the entire input.
270
        $merge = compact('type', 'value', 'id');
271
272
        $options = array_merge($options, $merge);
273
274
        return $this->toHtmlString('<input' . $this->html->attributes($options) . '>');
275
    }
276
277
    /**
278
     * Create a text input field.
279
     *
280
     * @param string $name
281
     * @param string $value
282
     * @param array  $options
283
     *
284
     * @return \Illuminate\Support\HtmlString
285
     */
286
    public function text($name, $value = null, $options = [])
287
    {
288
        return $this->input('text', $name, $value, $options);
289
    }
290
291
    /**
292
     * Create a password input field.
293
     *
294
     * @param string $name
295
     * @param array  $options
296
     *
297
     * @return \Illuminate\Support\HtmlString
298
     */
299
    public function password($name, $options = [])
300
    {
301
        return $this->input('password', $name, '', $options);
302
    }
303
304
    /**
305
     * Create a hidden input field.
306
     *
307
     * @param string $name
308
     * @param string $value
309
     * @param array  $options
310
     *
311
     * @return \Illuminate\Support\HtmlString
312
     */
313
    public function hidden($name, $value = null, $options = [])
314
    {
315
        return $this->input('hidden', $name, $value, $options);
316
    }
317
318
    /**
319
     * Create an e-mail input field.
320
     *
321
     * @param string $name
322
     * @param string $value
323
     * @param array  $options
324
     *
325
     * @return \Illuminate\Support\HtmlString
326
     */
327
    public function email($name, $value = null, $options = [])
328
    {
329
        return $this->input('email', $name, $value, $options);
330
    }
331
332
    /**
333
     * Create a tel input field.
334
     *
335
     * @param string $name
336
     * @param string $value
337
     * @param array  $options
338
     *
339
     * @return \Illuminate\Support\HtmlString
340
     */
341
    public function tel($name, $value = null, $options = [])
342
    {
343
        return $this->input('tel', $name, $value, $options);
344
    }
345
346
    /**
347
     * Create a number input field.
348
     *
349
     * @param string $name
350
     * @param string $value
351
     * @param array  $options
352
     *
353
     * @return \Illuminate\Support\HtmlString
354
     */
355
    public function number($name, $value = null, $options = [])
356
    {
357
        return $this->input('number', $name, $value, $options);
358
    }
359
360
    /**
361
     * Create a date input field.
362
     *
363
     * @param string $name
364
     * @param string $value
365
     * @param array  $options
366
     *
367
     * @return \Illuminate\Support\HtmlString
368
     */
369 View Code Duplication
    public function date($name, $value = null, $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
370
    {
371
        if ($value instanceof DateTime) {
372
            $value = $value->format('Y-m-d');
373
        }
374
375
        return $this->input('date', $name, $value, $options);
376
    }
377
378
    /**
379
     * Create a datetime input field.
380
     *
381
     * @param string $name
382
     * @param string $value
383
     * @param array  $options
384
     *
385
     * @return \Illuminate\Support\HtmlString
386
     */
387 View Code Duplication
    public function datetime($name, $value = null, $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
388
    {
389
        if ($value instanceof DateTime) {
390
            $value = $value->format(DateTime::RFC3339);
391
        }
392
393
        return $this->input('datetime', $name, $value, $options);
394
    }
395
396
    /**
397
     * Create a datetime-local input field.
398
     *
399
     * @param string $name
400
     * @param string $value
401
     * @param array  $options
402
     *
403
     * @return \Illuminate\Support\HtmlString
404
     */
405 View Code Duplication
    public function datetimeLocal($name, $value = null, $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
406
    {
407
        if ($value instanceof DateTime) {
408
            $value = $value->format('Y-m-d\TH:i');
409
        }
410
411
        return $this->input('datetime-local', $name, $value, $options);
412
    }
413
414
    /**
415
     * Create a time input field.
416
     *
417
     * @param string $name
418
     * @param string $value
419
     * @param array  $options
420
     *
421
     * @return \Illuminate\Support\HtmlString
422
     */
423
    public function time($name, $value = null, $options = [])
424
    {
425
        return $this->input('time', $name, $value, $options);
426
    }
427
428
    /**
429
     * Create a url input field.
430
     *
431
     * @param string $name
432
     * @param string $value
433
     * @param array  $options
434
     *
435
     * @return \Illuminate\Support\HtmlString
436
     */
437
    public function url($name, $value = null, $options = [])
438
    {
439
        return $this->input('url', $name, $value, $options);
440
    }
441
442
    /**
443
     * Create a file input field.
444
     *
445
     * @param string $name
446
     * @param array  $options
447
     *
448
     * @return \Illuminate\Support\HtmlString
449
     */
450
    public function file($name, $options = [])
451
    {
452
        return $this->input('file', $name, null, $options);
453
    }
454
455
    /**
456
     * Create a textarea input field.
457
     *
458
     * @param string $name
459
     * @param string $value
460
     * @param array  $options
461
     *
462
     * @return \Illuminate\Support\HtmlString
463
     */
464
    public function textarea($name, $value = null, $options = [])
465
    {
466
        if (! isset($options['name'])) {
467
            $options['name'] = $name;
468
        }
469
470
        // Next we will look for the rows and cols attributes, as each of these are put
471
        // on the textarea element definition. If they are not present, we will just
472
        // assume some sane default values for these attributes for the developer.
473
        $options = $this->setTextAreaSize($options);
474
475
        $options['id'] = $this->getIdAttribute($name, $options);
476
477
        $value = (string) $this->getValueAttribute($name, $value);
478
479
        unset($options['size']);
480
481
        // Next we will convert the attributes into a string form. Also we have removed
482
        // the size attribute, as it was merely a short-cut for the rows and cols on
483
        // the element. Then we'll create the final textarea elements HTML for us.
484
        $options = $this->html->attributes($options);
485
486
        return $this->toHtmlString('<textarea' . $options . '>' . e($value) . '</textarea>');
487
    }
488
489
    /**
490
     * Set the text area size on the attributes.
491
     *
492
     * @param array $options
493
     *
494
     * @return array
495
     */
496
    protected function setTextAreaSize($options)
497
    {
498
        if (isset($options['size'])) {
499
            return $this->setQuickTextAreaSize($options);
500
        }
501
502
        // If the "size" attribute was not specified, we will just look for the regular
503
        // columns and rows attributes, using sane defaults if these do not exist on
504
        // the attributes array. We'll then return this entire options array back.
505
        $cols = array_get($options, 'cols', 50);
506
507
        $rows = array_get($options, 'rows', 10);
508
509
        return array_merge($options, compact('cols', 'rows'));
510
    }
511
512
    /**
513
     * Set the text area size using the quick "size" attribute.
514
     *
515
     * @param array $options
516
     *
517
     * @return array
518
     */
519
    protected function setQuickTextAreaSize($options)
520
    {
521
        $segments = explode('x', $options['size']);
522
523
        return array_merge($options, ['cols' => $segments[0], 'rows' => $segments[1]]);
524
    }
525
526
    /**
527
     * Create a select box field.
528
     *
529
     * @param string $name
530
     * @param array  $list
531
     * @param string $selected
532
     * @param array  $options
533
     *
534
     * @return \Illuminate\Support\HtmlString
535
     */
536
    public function select($name, $list = [], $selected = null, $options = [])
537
    {
538
        // When building a select box the "value" attribute is really the selected one
539
        // so we will use that when checking the model or session for a value which
540
        // should provide a convenient method of re-populating the forms on post.
541
        $selected = $this->getValueAttribute($name, $selected);
542
543
        $options['id'] = $this->getIdAttribute($name, $options);
544
545
        if (! isset($options['name'])) {
546
            $options['name'] = $name;
547
        }
548
549
        // We will simply loop through the options and build an HTML value for each of
550
        // them until we have an array of HTML declarations. Then we will join them
551
        // all together into one single HTML element that can be put on the form.
552
        $html = [];
553
554
        if (isset($options['placeholder'])) {
555
            $html[] = $this->placeholderOption($options['placeholder'], $selected);
556
            unset($options['placeholder']);
557
        }
558
559
        foreach ($list as $value => $display) {
560
            $html[] = $this->getSelectOption($display, $value, $selected);
561
        }
562
563
        // Once we have all of this HTML, we can join this into a single element after
564
        // formatting the attributes into an HTML "attributes" string, then we will
565
        // build out a final select statement, which will contain all the values.
566
        $options = $this->html->attributes($options);
567
568
        $list = implode('', $html);
569
570
        return $this->toHtmlString("<select{$options}>{$list}</select>");
571
    }
572
573
    /**
574
     * Create a select range field.
575
     *
576
     * @param string $name
577
     * @param string $begin
578
     * @param string $end
579
     * @param string $selected
580
     * @param array  $options
581
     *
582
     * @return \Illuminate\Support\HtmlString
583
     */
584
    public function selectRange($name, $begin, $end, $selected = null, $options = [])
585
    {
586
        $range = array_combine($range = range($begin, $end), $range);
587
588
        return $this->select($name, $range, $selected, $options);
589
    }
590
591
    /**
592
     * Create a select year field.
593
     *
594
     * @param string $name
0 ignored issues
show
Bug introduced by
There is no parameter named $name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
595
     * @param string $begin
0 ignored issues
show
Bug introduced by
There is no parameter named $begin. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
596
     * @param string $end
0 ignored issues
show
Bug introduced by
There is no parameter named $end. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
597
     * @param string $selected
0 ignored issues
show
Bug introduced by
There is no parameter named $selected. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
598
     * @param array  $options
0 ignored issues
show
Bug introduced by
There is no parameter named $options. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
599
     *
600
     * @return mixed
601
     */
602
    public function selectYear()
603
    {
604
        return call_user_func_array([$this, 'selectRange'], func_get_args());
605
    }
606
607
    /**
608
     * Create a select month field.
609
     *
610
     * @param string $name
611
     * @param string $selected
612
     * @param array  $options
613
     * @param string $format
614
     *
615
     * @return \Illuminate\Support\HtmlString
616
     */
617
    public function selectMonth($name, $selected = null, $options = [], $format = '%B')
618
    {
619
        $months = [];
620
621
        foreach (range(1, 12) as $month) {
622
            $months[$month] = strftime($format, mktime(0, 0, 0, $month, 1));
623
        }
624
625
        return $this->select($name, $months, $selected, $options);
626
    }
627
628
    /**
629
     * Get the select option for the given value.
630
     *
631
     * @param string $display
632
     * @param string $value
633
     * @param string $selected
634
     *
635
     * @return \Illuminate\Support\HtmlString
636
     */
637
    public function getSelectOption($display, $value, $selected)
638
    {
639
        if (is_array($display)) {
640
            return $this->optionGroup($display, $value, $selected);
641
        }
642
643
        return $this->option($display, $value, $selected);
644
    }
645
646
    /**
647
     * Create an option group form element.
648
     *
649
     * @param array  $list
650
     * @param string $label
651
     * @param string $selected
652
     *
653
     * @return \Illuminate\Support\HtmlString
654
     */
655
    protected function optionGroup($list, $label, $selected)
656
    {
657
        $html = [];
658
659
        foreach ($list as $value => $display) {
660
            $html[] = $this->option($display, $value, $selected);
661
        }
662
663
        return $this->toHtmlString('<optgroup label="' . e($label) . '">' . implode('', $html) . '</optgroup>');
664
    }
665
666
    /**
667
     * Create a select element option.
668
     *
669
     * @param string $display
670
     * @param string $value
671
     * @param string $selected
672
     *
673
     * @return \Illuminate\Support\HtmlString
674
     */
675
    protected function option($display, $value, $selected)
676
    {
677
        $selected = $this->getSelectedValue($value, $selected);
678
679
        $options = ['value' => $value, 'selected' => $selected];
680
681
        return $this->toHtmlString('<option' . $this->html->attributes($options) . '>' . e($display) . '</option>');
682
    }
683
684
    /**
685
     * Create a placeholder select element option.
686
     *
687
     * @param $display
688
     * @param $selected
689
     *
690
     * @return \Illuminate\Support\HtmlString
691
     */
692
    protected function placeholderOption($display, $selected)
693
    {
694
        $selected = $this->getSelectedValue(null, $selected);
695
696
        $options          = compact('selected');
697
        $options['value'] = '';
698
699
        return $this->toHtmlString('<option' . $this->html->attributes($options) . '>' . e($display) . '</option>');
700
    }
701
702
    /**
703
     * Determine if the value is selected.
704
     *
705
     * @param string $value
706
     * @param string $selected
707
     *
708
     * @return null|string
709
     */
710
    protected function getSelectedValue($value, $selected)
711
    {
712
        if (is_array($selected)) {
713
            return in_array($value, $selected) ? 'selected' : null;
714
        }
715
716
        return ((string) $value == (string) $selected) ? 'selected' : null;
717
    }
718
719
    /**
720
     * Create a checkbox input field.
721
     *
722
     * @param string $name
723
     * @param mixed  $value
724
     * @param bool   $checked
725
     * @param array  $options
726
     *
727
     * @return \Illuminate\Support\HtmlString
728
     */
729
    public function checkbox($name, $value = 1, $checked = null, $options = [])
730
    {
731
        return $this->checkable('checkbox', $name, $value, $checked, $options);
732
    }
733
734
    /**
735
     * Create a radio button input field.
736
     *
737
     * @param string $name
738
     * @param mixed  $value
739
     * @param bool   $checked
740
     * @param array  $options
741
     *
742
     * @return \Illuminate\Support\HtmlString
743
     */
744
    public function radio($name, $value = null, $checked = null, $options = [])
745
    {
746
        if (is_null($value)) {
747
            $value = $name;
748
        }
749
750
        return $this->checkable('radio', $name, $value, $checked, $options);
751
    }
752
753
    /**
754
     * Create a checkable input field.
755
     *
756
     * @param string $type
757
     * @param string $name
758
     * @param mixed  $value
759
     * @param bool   $checked
760
     * @param array  $options
761
     *
762
     * @return \Illuminate\Support\HtmlString
763
     */
764
    protected function checkable($type, $name, $value, $checked, $options)
765
    {
766
        $checked = $this->getCheckedState($type, $name, $value, $checked);
767
768
        if ($checked) {
769
            $options['checked'] = 'checked';
770
        }
771
772
        return $this->input($type, $name, $value, $options);
773
    }
774
775
    /**
776
     * Get the check state for a checkable input.
777
     *
778
     * @param string $type
779
     * @param string $name
780
     * @param mixed  $value
781
     * @param bool   $checked
782
     *
783
     * @return bool
784
     */
785
    protected function getCheckedState($type, $name, $value, $checked)
786
    {
787
        switch ($type) {
788
            case 'checkbox':
789
                return $this->getCheckboxCheckedState($name, $value, $checked);
790
791
            case 'radio':
792
                return $this->getRadioCheckedState($name, $value, $checked);
793
794
            default:
795
                return $this->getValueAttribute($name) == $value;
796
        }
797
    }
798
799
    /**
800
     * Get the check state for a checkbox input.
801
     *
802
     * @param string $name
803
     * @param mixed  $value
804
     * @param bool   $checked
805
     *
806
     * @return bool
807
     */
808
    protected function getCheckboxCheckedState($name, $value, $checked)
809
    {
810
        if (isset($this->session) && ! $this->oldInputIsEmpty() && is_null($this->old($name))) {
811
            return false;
812
        }
813
814
        if ($this->missingOldAndModel($name)) {
815
            return $checked;
816
        }
817
818
        $posted = $this->getValueAttribute($name, $checked);
819
820
        if (is_array($posted)) {
821
            return in_array($value, $posted);
822
        } elseif ($posted instanceof Collection) {
823
            return $posted->contains('id', $value);
824
        } else {
825
            return (bool) $posted;
826
        }
827
    }
828
829
    /**
830
     * Get the check state for a radio input.
831
     *
832
     * @param string $name
833
     * @param mixed  $value
834
     * @param bool   $checked
835
     *
836
     * @return bool
837
     */
838
    protected function getRadioCheckedState($name, $value, $checked)
839
    {
840
        if ($this->missingOldAndModel($name)) {
841
            return $checked;
842
        }
843
844
        return $this->getValueAttribute($name) == $value;
845
    }
846
847
    /**
848
     * Determine if old input or model input exists for a key.
849
     *
850
     * @param string $name
851
     *
852
     * @return bool
853
     */
854
    protected function missingOldAndModel($name)
855
    {
856
        return (is_null($this->old($name)) && is_null($this->getModelValueAttribute($name)));
857
    }
858
859
    /**
860
     * Create a HTML reset input element.
861
     *
862
     * @param string $value
863
     * @param array  $attributes
864
     *
865
     * @return \Illuminate\Support\HtmlString
866
     */
867
    public function reset($value, $attributes = [])
868
    {
869
        return $this->input('reset', null, $value, $attributes);
870
    }
871
872
    /**
873
     * Create a HTML image input element.
874
     *
875
     * @param string $url
876
     * @param string $name
877
     * @param array  $attributes
878
     *
879
     * @return \Illuminate\Support\HtmlString
880
     */
881
    public function image($url, $name = null, $attributes = [])
882
    {
883
        $attributes['src'] = $this->url->asset($url);
884
885
        return $this->input('image', $name, null, $attributes);
886
    }
887
888
    /**
889
     * Create a color input field.
890
     *
891
     * @param string $name
892
     * @param string $value
893
     * @param array  $options
894
     *
895
     * @return \Illuminate\Support\HtmlString
896
     */
897
    public function color($name, $value = null, $options = [])
898
    {
899
        return $this->input('color', $name, $value, $options);
900
    }
901
902
    /**
903
     * Create a submit button element.
904
     *
905
     * @param string $value
906
     * @param array  $options
907
     *
908
     * @return \Illuminate\Support\HtmlString
909
     */
910
    public function submit($value = null, $options = [])
911
    {
912
        return $this->input('submit', null, $value, $options);
913
    }
914
915
    /**
916
     * Create a button element.
917
     *
918
     * @param string $value
919
     * @param array  $options
920
     *
921
     * @return \Illuminate\Support\HtmlString
922
     */
923
    public function button($value = null, $options = [])
924
    {
925
        if (! array_key_exists('type', $options)) {
926
            $options['type'] = 'button';
927
        }
928
929
        return $this->toHtmlString('<button' . $this->html->attributes($options) . '>' . $value . '</button>');
930
    }
931
932
    /**
933
     * Parse the form action method.
934
     *
935
     * @param string $method
936
     *
937
     * @return string
938
     */
939
    protected function getMethod($method)
940
    {
941
        $method = strtoupper($method);
942
943
        return $method != 'GET' ? 'POST' : $method;
944
    }
945
946
    /**
947
     * Get the form action from the options.
948
     *
949
     * @param array $options
950
     *
951
     * @return string
952
     */
953
    protected function getAction(array $options)
954
    {
955
        // We will also check for a "route" or "action" parameter on the array so that
956
        // developers can easily specify a route or controller action when creating
957
        // a form providing a convenient interface for creating the form actions.
958
        if (isset($options['url'])) {
959
            return $this->getUrlAction($options['url']);
960
        }
961
962
        if (isset($options['route'])) {
963
            return $this->getRouteAction($options['route']);
964
        }
965
966
        // If an action is available, we are attempting to open a form to a controller
967
        // action route. So, we will use the URL generator to get the path to these
968
        // actions and return them from the method. Otherwise, we'll use current.
969
        elseif (isset($options['action'])) {
970
            return $this->getControllerAction($options['action']);
971
        }
972
973
        return $this->url->current();
974
    }
975
976
    /**
977
     * Get the action for a "url" option.
978
     *
979
     * @param array|string $options
980
     *
981
     * @return string
982
     */
983
    protected function getUrlAction($options)
984
    {
985
        if (is_array($options)) {
986
            return $this->url->to($options[0], array_slice($options, 1));
987
        }
988
989
        return $this->url->to($options);
990
    }
991
992
    /**
993
     * Get the action for a "route" option.
994
     *
995
     * @param array|string $options
996
     *
997
     * @return string
998
     */
999 View Code Duplication
    protected function getRouteAction($options)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1000
    {
1001
        if (is_array($options)) {
1002
            return $this->url->route($options[0], array_slice($options, 1));
1003
        }
1004
1005
        return $this->url->route($options);
1006
    }
1007
1008
    /**
1009
     * Get the action for an "action" option.
1010
     *
1011
     * @param array|string $options
1012
     *
1013
     * @return string
1014
     */
1015 View Code Duplication
    protected function getControllerAction($options)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1016
    {
1017
        if (is_array($options)) {
1018
            return $this->url->action($options[0], array_slice($options, 1));
1019
        }
1020
1021
        return $this->url->action($options);
1022
    }
1023
1024
    /**
1025
     * Get the form appendage for the given method.
1026
     *
1027
     * @param string $method
1028
     *
1029
     * @return string
1030
     */
1031
    protected function getAppendage($method)
1032
    {
1033
        list($method, $appendage) = [strtoupper($method), ''];
1034
1035
        // If the HTTP method is in this list of spoofed methods, we will attach the
1036
        // method spoofer hidden input to the form. This allows us to use regular
1037
        // form to initiate PUT and DELETE requests in addition to the typical.
1038
        if (in_array($method, $this->spoofedMethods)) {
1039
            $appendage .= $this->hidden('_method', $method);
1040
        }
1041
1042
        // If the method is something other than GET we will go ahead and attach the
1043
        // CSRF token to the form, as this can't hurt and is convenient to simply
1044
        // always have available on every form the developers creates for them.
1045
        if ($method != 'GET') {
1046
            $appendage .= $this->token();
1047
        }
1048
1049
        return $appendage;
1050
    }
1051
1052
    /**
1053
     * Get the ID attribute for a field name.
1054
     *
1055
     * @param string $name
1056
     * @param array  $attributes
1057
     *
1058
     * @return string
1059
     */
1060
    public function getIdAttribute($name, $attributes)
1061
    {
1062
        if (array_key_exists('id', $attributes)) {
1063
            return $attributes['id'];
1064
        }
1065
1066
        if (in_array($name, $this->labels)) {
1067
            return $name;
1068
        }
1069
    }
1070
1071
    /**
1072
     * Get the value that should be assigned to the field.
1073
     *
1074
     * @param string $name
1075
     * @param string $value
1076
     *
1077
     * @return mixed
1078
     */
1079
    public function getValueAttribute($name, $value = null)
1080
    {
1081
        if (is_null($name)) {
1082
            return $value;
1083
        }
1084
1085
        if (! is_null($this->old($name)) && $name != '_method') {
1086
            return $this->old($name);
1087
        }
1088
1089
        if (! is_null($value)) {
1090
            return $value;
1091
        }
1092
1093
        if (isset($this->model)) {
1094
            return $this->getModelValueAttribute($name);
1095
        }
1096
    }
1097
1098
    /**
1099
     * Get the model value that should be assigned to the field.
1100
     *
1101
     * @param string $name
1102
     *
1103
     * @return mixed
1104
     */
1105
    protected function getModelValueAttribute($name)
1106
    {
1107
        if (method_exists($this->model, 'getFormValue')) {
1108
            return $this->model->getFormValue($this->transformKey($name));
1109
        }
1110
1111
        return data_get($this->model, $this->transformKey($name));
1112
    }
1113
1114
    /**
1115
     * Get a value from the session's old input.
1116
     *
1117
     * @param string $name
1118
     *
1119
     * @return mixed
1120
     */
1121
    public function old($name)
1122
    {
1123
        if (isset($this->session)) {
1124
            return $this->session->getOldInput($this->transformKey($name));
1125
        }
1126
    }
1127
1128
    /**
1129
     * Determine if the old input is empty.
1130
     *
1131
     * @return bool
1132
     */
1133
    public function oldInputIsEmpty()
1134
    {
1135
        return (isset($this->session) && count($this->session->getOldInput()) == 0);
1136
    }
1137
1138
    /**
1139
     * Transform key from array to dot syntax.
1140
     *
1141
     * @param string $key
1142
     *
1143
     * @return mixed
1144
     */
1145
    protected function transformKey($key)
1146
    {
1147
        return str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $key);
1148
    }
1149
1150
    /**
1151
     * Transform the string to an Html serializable object
1152
     *
1153
     * @param $html
1154
     *
1155
     * @return \Illuminate\Support\HtmlString
1156
     */
1157
    protected function toHtmlString($html)
1158
    {
1159
        return new HtmlString($html);
1160
    }
1161
1162
    /**
1163
     * Get the session store implementation.
1164
     *
1165
     * @return \Illuminate\Session\SessionInterface $session
1166
     */
1167
    public function getSessionStore()
1168
    {
1169
        return $this->session;
1170
    }
1171
1172
    /**
1173
     * Set the session store implementation.
1174
     *
1175
     * @param \Illuminate\Session\SessionInterface $session
1176
     *
1177
     * @return $this
1178
     */
1179
    public function setSessionStore(SessionInterface $session)
1180
    {
1181
        $this->session = $session;
1182
1183
        return $this;
1184
    }
1185
1186
    /**
1187
     * Dynamically handle calls to the class.
1188
     *
1189
     * @param string $method
1190
     * @param array  $parameters
1191
     *
1192
     * @return \Illuminate\Contracts\View\View|mixed
1193
     *
1194
     * @throws \BadMethodCallException
1195
     */
1196
    public function __call($method, $parameters)
1197
    {
1198
        try {
1199
            return $this->componentCall($method, $parameters);
1200
        } catch (BadMethodCallException $e) {
1201
            //
1202
        }
1203
1204
        try {
1205
            return $this->macroCall($method, $parameters);
1206
        } catch (BadMethodCallException $e) {
1207
            //
1208
        }
1209
1210
        throw new BadMethodCallException("Method {$method} does not exist.");
1211
    }
1212
}
1213