These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Arcanedev\LaravelHtml; |
||
6 | |||
7 | use Arcanedev\Html\Elements\{Button, File, Form, Input, Label, Select, Textarea}; |
||
8 | use Arcanedev\LaravelHtml\Contracts\FormBuilder as FormBuilderContract; |
||
9 | use DateTime; |
||
10 | use Illuminate\Contracts\Routing\UrlGenerator; |
||
11 | use Illuminate\Contracts\Session\Session; |
||
12 | use Illuminate\Support\{Arr, Collection, HtmlString, Str}; |
||
13 | |||
14 | /** |
||
15 | * Class FormBuilder |
||
16 | * |
||
17 | * @package Arcanedev\LaravelHtml |
||
18 | * @author ARCANEDEV <[email protected]> |
||
19 | */ |
||
20 | class FormBuilder extends AbstractBuilder implements FormBuilderContract |
||
21 | { |
||
22 | /* ----------------------------------------------------------------- |
||
23 | | Properties |
||
24 | | ----------------------------------------------------------------- |
||
25 | */ |
||
26 | |||
27 | /** |
||
28 | * The HTML builder instance. |
||
29 | * |
||
30 | * @var \Arcanedev\LaravelHtml\Contracts\HtmlBuilder |
||
31 | */ |
||
32 | protected $html; |
||
33 | |||
34 | /** |
||
35 | * The URL generator instance. |
||
36 | * |
||
37 | * @var \Illuminate\Contracts\Routing\UrlGenerator |
||
38 | */ |
||
39 | protected $url; |
||
40 | |||
41 | /** |
||
42 | * The CSRF token used by the form builder. |
||
43 | * |
||
44 | * @var string |
||
45 | */ |
||
46 | protected $csrfToken; |
||
47 | |||
48 | /** |
||
49 | * The session store implementation. |
||
50 | * |
||
51 | * @var \Illuminate\Contracts\Session\Session|\Illuminate\Session\Store |
||
52 | */ |
||
53 | protected $session; |
||
54 | |||
55 | /** |
||
56 | * The current model instance for the form. |
||
57 | * |
||
58 | * @var \Illuminate\Database\Eloquent\Model|null |
||
59 | */ |
||
60 | protected $model; |
||
61 | |||
62 | /** |
||
63 | * An array of label names we've created. |
||
64 | * |
||
65 | * @var array |
||
66 | */ |
||
67 | protected $labels = []; |
||
68 | |||
69 | /** |
||
70 | * The reserved form open attributes. |
||
71 | * |
||
72 | * @var array |
||
73 | */ |
||
74 | protected $reserved = ['method', 'url', 'route', 'action', 'files']; |
||
75 | |||
76 | /** |
||
77 | * The form methods that should be spoofed, in uppercase. |
||
78 | * |
||
79 | * @var array |
||
80 | */ |
||
81 | protected $spoofedMethods = ['DELETE', 'PATCH', 'PUT']; |
||
82 | |||
83 | /** |
||
84 | * The types of inputs to not fill values on by default. |
||
85 | * |
||
86 | * @var array |
||
87 | */ |
||
88 | protected $skipValueTypes = ['file', 'password', 'checkbox', 'radio']; |
||
89 | |||
90 | /* ----------------------------------------------------------------- |
||
91 | | Constructor |
||
92 | | ----------------------------------------------------------------- |
||
93 | */ |
||
94 | |||
95 | /** |
||
96 | * Create a new form builder instance. |
||
97 | * |
||
98 | * @param \Arcanedev\LaravelHtml\Contracts\HtmlBuilder $html |
||
99 | * @param \Illuminate\Contracts\Routing\UrlGenerator $url |
||
100 | * @param \Illuminate\Contracts\Session\Session $session |
||
101 | */ |
||
102 | 606 | public function __construct(Contracts\HtmlBuilder $html, UrlGenerator $url, Session $session) |
|
103 | { |
||
104 | 606 | $this->url = $url; |
|
105 | 606 | $this->html = $html; |
|
106 | 606 | $this->csrfToken = $session->token(); |
|
107 | |||
108 | 606 | $this->setSessionStore($session); |
|
109 | 606 | } |
|
110 | |||
111 | /* ----------------------------------------------------------------- |
||
112 | | Getters & Setters |
||
113 | | ----------------------------------------------------------------- |
||
114 | */ |
||
115 | |||
116 | /** |
||
117 | * Get the session store implementation. |
||
118 | * |
||
119 | * @return \Illuminate\Contracts\Session\Session|null |
||
120 | */ |
||
121 | 468 | public function getSessionStore(): ?Session |
|
122 | { |
||
123 | 468 | return $this->session; |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * Set the session store implementation. |
||
128 | * |
||
129 | * @param \Illuminate\Contracts\Session\Session $session |
||
130 | * |
||
131 | * @return $this |
||
132 | */ |
||
133 | 606 | public function setSessionStore(Session $session) |
|
134 | { |
||
135 | 606 | $this->session = $session; |
|
136 | |||
137 | 606 | return $this; |
|
138 | } |
||
139 | |||
140 | /** |
||
141 | * Set the model instance on the form builder. |
||
142 | * |
||
143 | * @param \Illuminate\Database\Eloquent\Model|mixed|null $model |
||
144 | * |
||
145 | * @return $this |
||
146 | */ |
||
147 | 66 | public function setModel($model) |
|
148 | { |
||
149 | 66 | $this->model = $model; |
|
150 | |||
151 | 66 | return $this; |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * Get the model instance on the form builder. |
||
156 | * |
||
157 | * @return \Illuminate\Database\Eloquent\Model|mixed|null |
||
158 | */ |
||
159 | 264 | public function getModel() |
|
160 | { |
||
161 | 264 | return $this->model; |
|
162 | } |
||
163 | |||
164 | /** |
||
165 | * Get the ID attribute for a field name. |
||
166 | * |
||
167 | * @param string|null $name |
||
168 | * @param array $attributes |
||
169 | * |
||
170 | * @return string|null |
||
171 | */ |
||
172 | 480 | public function getIdAttribute($name, array $attributes): ?string |
|
173 | { |
||
174 | 480 | if (array_key_exists('id', $attributes)) |
|
175 | 42 | return $attributes['id']; |
|
176 | |||
177 | 456 | if ( ! is_null($name) && in_array($name, $this->labels)) |
|
178 | 12 | return $name; |
|
179 | |||
180 | 444 | 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 | 450 | public function getValueAttribute($name, $value = null) |
|
192 | { |
||
193 | 450 | if (is_null($name)) |
|
194 | 6 | return $value; |
|
195 | |||
196 | 444 | if ( ! is_null($this->old($name)) && $name !== '_method') |
|
197 | 30 | return $this->old($name); |
|
198 | |||
199 | 432 | if ( ! is_null($value)) |
|
200 | 252 | return $value; |
|
201 | |||
202 | 234 | return $this->getModelValueAttribute($name); |
|
203 | } |
||
204 | |||
205 | /** |
||
206 | * Get the model value that should be assigned to the field. |
||
207 | * |
||
208 | * @param string $name |
||
209 | * @param \Illuminate\Database\Eloquent\Model|mixed|null $model |
||
210 | * |
||
211 | * @return mixed |
||
212 | */ |
||
213 | 252 | private function getModelValueAttribute(string $name, $model = null) |
|
214 | { |
||
215 | 252 | $model = $model ?: $this->getModel(); |
|
216 | |||
217 | 252 | $key = static::transformKey($name); |
|
218 | |||
219 | 252 | if (strpos($key, '.') !== false) { |
|
220 | 30 | $keys = explode('.', $key, 2); |
|
221 | |||
222 | 30 | return $this->getModelValueAttribute( |
|
223 | 30 | $keys[1], |
|
224 | 30 | $this->getModelValueAttribute($keys[0], $model) |
|
225 | ); |
||
226 | } |
||
227 | |||
228 | 252 | return method_exists($model, 'getFormValue') |
|
229 | 6 | ? $model->getFormValue($key) |
|
230 | 252 | : data_get($model, $key); |
|
231 | } |
||
232 | |||
233 | /** |
||
234 | * Get a value from the session's old input. |
||
235 | * |
||
236 | * @param string $name |
||
237 | * |
||
238 | * @return mixed |
||
239 | */ |
||
240 | 462 | public function old(string $name) |
|
241 | { |
||
242 | 462 | $session = $this->getSessionStore(); |
|
243 | |||
244 | 462 | return is_null($session) ? null : $session->getOldInput(static::transformKey($name)); |
|
245 | } |
||
246 | |||
247 | /** |
||
248 | * Transform key from array to dot syntax. |
||
249 | * |
||
250 | * @param string $key |
||
251 | * |
||
252 | * @return string |
||
253 | */ |
||
254 | 462 | private static function transformKey(string $key): string |
|
255 | { |
||
256 | 462 | return str_replace( |
|
257 | 462 | ['.', '[]', '[', ']'], |
|
258 | 462 | ['_', '', '.', ''], |
|
259 | 154 | $key |
|
260 | ); |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * Determine if the old input is empty. |
||
265 | * |
||
266 | * @return bool |
||
267 | */ |
||
268 | 24 | public function oldInputIsEmpty(): bool |
|
269 | { |
||
270 | 24 | $session = $this->getSessionStore(); |
|
271 | |||
272 | 24 | return ! is_null($session) |
|
273 | 24 | && (count($session->getOldInput()) === 0); |
|
274 | } |
||
275 | |||
276 | /* ----------------------------------------------------------------- |
||
277 | | Main Methods |
||
278 | | ----------------------------------------------------------------- |
||
279 | */ |
||
280 | |||
281 | /** |
||
282 | * Open up a new HTML form. |
||
283 | * |
||
284 | * @param array $attributes |
||
285 | * |
||
286 | * @return \Illuminate\Support\HtmlString |
||
287 | */ |
||
288 | 84 | public function open(array $attributes = []): HtmlString |
|
289 | { |
||
290 | 84 | $method = Str::upper(Arr::pull($attributes, 'method', 'POST')); |
|
291 | |||
292 | 84 | return Form::make() |
|
293 | 84 | ->method($method !== 'GET' ? 'POST' : $method) |
|
294 | 84 | ->action($this->getAction($attributes)) |
|
295 | 84 | ->attributes(array_merge( |
|
296 | 84 | ['accept-charset' => 'UTF-8'], |
|
297 | 84 | Arr::except($attributes, $this->reserved) |
|
298 | )) |
||
299 | ->if(Arr::pull($attributes, 'files', false), function (Form $form) { |
||
300 | 6 | return $form->acceptsFiles(); |
|
301 | 84 | }) |
|
302 | ->if(in_array($method, $this->spoofedMethods), function (Form $form) use ($method) { |
||
303 | 6 | return $form->addChild($this->hidden('_method', $method)); |
|
304 | 84 | }) |
|
305 | ->if($method !== 'GET', function (Form $form) { |
||
306 | 48 | return $form->addChild($this->token()); |
|
307 | 84 | }) |
|
308 | 84 | ->open(); |
|
309 | } |
||
310 | |||
311 | /** |
||
312 | * Create a new model based form builder. |
||
313 | * |
||
314 | * @param mixed $model |
||
315 | * @param array $attributes |
||
316 | * |
||
317 | * @return \Illuminate\Support\HtmlString |
||
318 | */ |
||
319 | 30 | public function model($model, array $attributes = []): HtmlString |
|
320 | { |
||
321 | 30 | return $this->setModel($model)->open($attributes); |
|
322 | } |
||
323 | |||
324 | /** |
||
325 | * Close the current form. |
||
326 | * |
||
327 | * @return \Illuminate\Support\HtmlString |
||
328 | */ |
||
329 | 6 | public function close(): HtmlString |
|
330 | { |
||
331 | 6 | $this->labels = []; |
|
332 | 6 | $this->setModel(null); |
|
333 | |||
334 | 6 | return Form::make()->close(); |
|
335 | } |
||
336 | |||
337 | /** |
||
338 | * Generate a hidden field with the current CSRF token. |
||
339 | * |
||
340 | * @return \Arcanedev\Html\Elements\Input |
||
341 | */ |
||
342 | 48 | public function token(): Input |
|
343 | { |
||
344 | 48 | $token = empty($this->csrfToken) |
|
345 | ? $this->getSessionStore()->token() |
||
346 | 48 | : $this->csrfToken; |
|
347 | |||
348 | 48 | return $this->hidden('_token', $token); |
|
349 | } |
||
350 | |||
351 | /** |
||
352 | * Create a form label element. |
||
353 | * |
||
354 | * @param string $name |
||
355 | * @param string|mixed $value |
||
356 | * @param array $attributes |
||
357 | * @param bool $escaped |
||
358 | * |
||
359 | * @return \Arcanedev\Html\Elements\Label |
||
360 | */ |
||
361 | 30 | public function label(string $name, $value = null, array $attributes = [], $escaped = true): Label |
|
362 | { |
||
363 | 30 | $this->labels[] = $name; |
|
364 | |||
365 | 30 | $value = $value ?: Str::title(str_replace(['_', '-'], ' ', $name)); |
|
366 | |||
367 | 30 | return Label::make() |
|
368 | 30 | ->for($name) |
|
369 | 30 | ->attributes($attributes) |
|
370 | 30 | ->html($escaped ? e($value) : $value); |
|
371 | } |
||
372 | |||
373 | /** |
||
374 | * Create a form input field. |
||
375 | * |
||
376 | * @param string $type |
||
377 | * @param string|null $name |
||
378 | * @param string|mixed $value |
||
379 | * @param array $attributes |
||
380 | * |
||
381 | * @return \Arcanedev\Html\Elements\Input |
||
382 | */ |
||
383 | 354 | public function input(string $type, $name, $value = null, array $attributes = []): Input |
|
384 | { |
||
385 | 354 | if ( ! in_array($type, $this->skipValueTypes)) |
|
386 | 300 | $value = $this->getValueAttribute($name, $value); |
|
387 | |||
388 | 354 | $id = $this->getIdAttribute($name, $attributes); |
|
389 | |||
390 | 354 | return Input::make() |
|
391 | 354 | ->type($type) |
|
392 | 354 | ->attributeIfNotNull($name, 'name', $name) |
|
0 ignored issues
–
show
|
|||
393 | 354 | ->attributeIfNotNull($id, 'id', $id) |
|
394 | 354 | ->attributeUnless(is_null($value) || empty($value), 'value', $value) |
|
395 | 354 | ->attributes($attributes); |
|
396 | } |
||
397 | |||
398 | /** |
||
399 | * Create a text input field. |
||
400 | * |
||
401 | * @param string $name |
||
402 | * @param string|mixed $value |
||
403 | * @param array $attributes |
||
404 | * |
||
405 | * @return \Arcanedev\Html\Elements\Input |
||
406 | */ |
||
407 | 42 | public function text(string $name, $value = null, array $attributes = []): Input |
|
408 | { |
||
409 | 42 | return $this->input('text', $name, $value, $attributes); |
|
410 | } |
||
411 | |||
412 | /** |
||
413 | * Create a password input field. |
||
414 | * |
||
415 | * @param string $name |
||
416 | * @param array $attributes |
||
417 | * |
||
418 | * @return \Arcanedev\Html\Elements\Input |
||
419 | */ |
||
420 | 18 | public function password(string $name, array $attributes = []): Input |
|
421 | { |
||
422 | 18 | return $this->input('password', $name, null, $attributes); |
|
423 | } |
||
424 | |||
425 | /** |
||
426 | * Create a hidden input field. |
||
427 | * |
||
428 | * @param string $name |
||
429 | * @param string|mixed $value |
||
430 | * @param array $attributes |
||
431 | * |
||
432 | * @return \Arcanedev\Html\Elements\Input |
||
433 | */ |
||
434 | 66 | public function hidden(string $name, $value = null, array $attributes = []): Input |
|
435 | { |
||
436 | 66 | return $this->input('hidden', $name, $value, $attributes); |
|
437 | } |
||
438 | |||
439 | /** |
||
440 | * Create an e-mail input field. |
||
441 | * |
||
442 | * @param string $name |
||
443 | * @param string|mixed $value |
||
444 | * @param array $attributes |
||
445 | * |
||
446 | * @return \Arcanedev\Html\Elements\Input |
||
447 | */ |
||
448 | 18 | public function email(string $name, $value = null, array $attributes = []): Input |
|
449 | { |
||
450 | 18 | return $this->input('email', $name, $value, $attributes); |
|
451 | } |
||
452 | |||
453 | /** |
||
454 | * Create a tel input field. |
||
455 | * |
||
456 | * @param string $name |
||
457 | * @param string|mixed $value |
||
458 | * @param array $attributes |
||
459 | * |
||
460 | * @return \Arcanedev\Html\Elements\Input |
||
461 | */ |
||
462 | 18 | public function tel(string $name, $value = null, array $attributes = []): Input |
|
463 | { |
||
464 | 18 | return $this->input('tel', $name, $value, $attributes); |
|
465 | } |
||
466 | |||
467 | /** |
||
468 | * Create a number input field. |
||
469 | * |
||
470 | * @param string $name |
||
471 | * @param string|mixed $value |
||
472 | * @param array $attributes |
||
473 | * |
||
474 | * @return \Arcanedev\Html\Elements\Input |
||
475 | */ |
||
476 | 18 | public function number(string $name, $value = null, array $attributes = []): Input |
|
477 | { |
||
478 | 18 | return $this->input('number', $name, $value, $attributes); |
|
479 | } |
||
480 | |||
481 | /** |
||
482 | * Create a date input field. |
||
483 | * |
||
484 | * @param string $name |
||
485 | * @param string $value |
||
486 | * @param array $attributes |
||
487 | * |
||
488 | * @return \Arcanedev\Html\Elements\Input |
||
489 | */ |
||
490 | 24 | public function date(string $name, $value = null, array $attributes = []): Input |
|
491 | { |
||
492 | 24 | if ($value instanceof DateTime) |
|
493 | 6 | $value = $value->format('Y-m-d'); |
|
494 | |||
495 | 24 | return $this->input('date', $name, $value, $attributes); |
|
496 | } |
||
497 | |||
498 | /** |
||
499 | * Create a datetime input field. |
||
500 | * |
||
501 | * @param string $name |
||
502 | * @param string|mixed $value |
||
503 | * @param array $attributes |
||
504 | * |
||
505 | * @return \Arcanedev\Html\Elements\Input |
||
506 | */ |
||
507 | 24 | public function datetime(string $name, $value = null, array $attributes = []): Input |
|
508 | { |
||
509 | 24 | if ($value instanceof DateTime) |
|
510 | 12 | $value = $value->format(DateTime::RFC3339); |
|
511 | |||
512 | 24 | return $this->input('datetime', $name, $value, $attributes); |
|
513 | } |
||
514 | |||
515 | /** |
||
516 | * Create a datetime-local input field. |
||
517 | * |
||
518 | * @param string $name |
||
519 | * @param string|mixed $value |
||
520 | * @param array $attributes |
||
521 | * |
||
522 | * @return \Arcanedev\Html\Elements\Input |
||
523 | */ |
||
524 | 24 | public function datetimeLocal(string $name, $value = null, array $attributes = []): Input |
|
525 | { |
||
526 | 24 | if ($value instanceof DateTime) |
|
527 | 12 | $value = $value->format('Y-m-d\TH:i'); |
|
528 | |||
529 | 24 | return $this->input('datetime-local', $name, $value, $attributes); |
|
530 | } |
||
531 | |||
532 | /** |
||
533 | * Create a time input field. |
||
534 | * |
||
535 | * @param string $name |
||
536 | * @param string|mixed $value |
||
537 | * @param array $attributes |
||
538 | * |
||
539 | * @return \Arcanedev\Html\Elements\Input |
||
540 | */ |
||
541 | 18 | public function time(string $name, $value = null, array $attributes = []): Input |
|
542 | { |
||
543 | 18 | return $this->input('time', $name, $value, $attributes); |
|
544 | } |
||
545 | |||
546 | /** |
||
547 | * Create a url input field. |
||
548 | * |
||
549 | * @param string $name |
||
550 | * @param string $value |
||
551 | * @param array $attributes |
||
552 | * |
||
553 | * @return \Arcanedev\Html\Elements\Input |
||
554 | */ |
||
555 | 12 | public function url(string $name, $value = null, array $attributes = []): Input |
|
556 | { |
||
557 | 12 | return $this->input('url', $name, $value, $attributes); |
|
558 | } |
||
559 | |||
560 | /** |
||
561 | * Create a file input field. |
||
562 | * |
||
563 | * @param string $name |
||
564 | * @param array $attributes |
||
565 | * |
||
566 | * @return \Arcanedev\Html\Elements\File |
||
567 | */ |
||
568 | 18 | public function file(string $name, array $attributes = []): File |
|
569 | { |
||
570 | 18 | return File::make()->name($name)->attributes($attributes); |
|
571 | } |
||
572 | |||
573 | /** |
||
574 | * Create a textarea input field. |
||
575 | * |
||
576 | * @param string $name |
||
577 | * @param string $value |
||
578 | * @param array $attributes |
||
579 | * |
||
580 | * @return \Arcanedev\Html\Elements\Textarea |
||
581 | */ |
||
582 | 36 | public function textarea(string $name, $value = null, array $attributes = []): Textarea |
|
583 | { |
||
584 | 36 | $id = $this->getIdAttribute($name, $attributes); |
|
585 | 36 | $size = Arr::pull($attributes, 'size'); |
|
586 | 36 | $value = (string) $this->getValueAttribute($name, $value); |
|
587 | |||
588 | 36 | return Textarea::make() |
|
589 | 36 | ->name($name) |
|
590 | 36 | ->attributeUnless(is_null($id), 'id', $id) |
|
591 | ->unless(is_null($size), function (Textarea $elt) use ($size) { |
||
592 | 18 | return $elt->size($size); |
|
593 | 36 | }) |
|
594 | 36 | ->attributes($attributes) |
|
595 | 36 | ->html($this->html->escape($value)); |
|
596 | } |
||
597 | |||
598 | /** |
||
599 | * Create a select box field. |
||
600 | * |
||
601 | * @param string $name |
||
602 | * @param array|\Illuminate\Support\Collection|iterable $list |
||
603 | * @param string|bool $selected |
||
604 | * @param array $attributes |
||
605 | * @param array $optionsAttributes |
||
606 | * @param array $optgroupsAttributes |
||
607 | * |
||
608 | * @return \Arcanedev\Html\Elements\Select |
||
609 | */ |
||
610 | 90 | public function select( |
|
611 | string $name, |
||
612 | iterable $list = [], |
||
613 | $selected = null, |
||
614 | array $attributes = [], |
||
615 | array $optionsAttributes = [], |
||
616 | array $optgroupsAttributes = [] |
||
617 | ): Select { |
||
618 | 90 | return Select::make() |
|
619 | 90 | ->name($name) |
|
620 | 90 | ->options($list, $optionsAttributes, $optgroupsAttributes) |
|
621 | 90 | ->attributes($attributes) |
|
622 | 90 | ->attributeUnless(is_null($id = $this->getIdAttribute($name, $attributes)), 'id', $id) |
|
623 | 90 | ->value($this->getValueAttribute($name, $selected)); |
|
624 | } |
||
625 | |||
626 | /** |
||
627 | * Create a select range field. |
||
628 | * |
||
629 | * @param string $name |
||
630 | * @param string $begin |
||
631 | * @param string $end |
||
632 | * @param string $selected |
||
633 | * @param array $attributes |
||
634 | * |
||
635 | * @return \Arcanedev\Html\Elements\Select |
||
636 | */ |
||
637 | 12 | public function selectRange(string $name, $begin, $end, $selected = null, array $attributes = []): Select |
|
638 | { |
||
639 | 12 | $range = array_combine($range = range($begin, $end), $range); |
|
640 | |||
641 | 12 | return $this->select($name, $range, $selected, $attributes); |
|
642 | } |
||
643 | |||
644 | /** |
||
645 | * Create a select year field. |
||
646 | * |
||
647 | * @param string $name |
||
648 | * @param string $begin |
||
649 | * @param string $end |
||
650 | * @param string $selected |
||
651 | * @param array $attributes |
||
652 | * |
||
653 | * @return \Arcanedev\Html\Elements\Select |
||
654 | */ |
||
655 | 6 | public function selectYear(string $name, $begin, $end, $selected = null, array $attributes = []): Select |
|
656 | { |
||
657 | 6 | return $this->selectRange($name, $begin, $end, $selected, $attributes); |
|
658 | } |
||
659 | |||
660 | /** |
||
661 | * Create a select month field. |
||
662 | * |
||
663 | * @param string $name |
||
664 | * @param string $selected |
||
665 | * @param array $attributes |
||
666 | * @param string $format |
||
667 | * |
||
668 | * @return \Arcanedev\Html\Elements\Select |
||
669 | */ |
||
670 | 6 | public function selectMonth(string $name, $selected = null, array $attributes = [], $format = '%B'): Select |
|
671 | { |
||
672 | 6 | $months = []; |
|
673 | |||
674 | 6 | foreach(range(1, 12) as $month) { |
|
675 | 6 | $months[$month] = strftime($format, mktime(0, 0, 0, $month, 1)); |
|
676 | } |
||
677 | |||
678 | 6 | return $this->select($name, $months, $selected, $attributes); |
|
679 | } |
||
680 | |||
681 | /** |
||
682 | * Create a checkbox input field. |
||
683 | * |
||
684 | * @param string $name |
||
685 | * @param mixed $value |
||
686 | * @param bool|null $checked |
||
687 | * @param array $attributes |
||
688 | * |
||
689 | * @return \Arcanedev\Html\Elements\Input |
||
690 | */ |
||
691 | 24 | public function checkbox(string $name, $value = 1, $checked = null, array $attributes = []): Input |
|
692 | { |
||
693 | 24 | return $this->checkable('checkbox', $name, $value, $checked, $attributes); |
|
694 | } |
||
695 | |||
696 | /** |
||
697 | * Create a radio button input field. |
||
698 | * |
||
699 | * @param string $name |
||
700 | * @param mixed $value |
||
701 | * @param bool $checked |
||
702 | * @param array $attributes |
||
703 | * |
||
704 | * @return \Arcanedev\Html\Elements\Input |
||
705 | */ |
||
706 | 12 | public function radio(string $name, $value = null, $checked = null, array $attributes = []): Input |
|
707 | { |
||
708 | 12 | return $this->checkable('radio', $name, $value ?: $name, $checked, $attributes); |
|
709 | } |
||
710 | |||
711 | /** |
||
712 | * Create a HTML reset input element. |
||
713 | * |
||
714 | * @param string|mixed $value |
||
715 | * @param array $attributes |
||
716 | * |
||
717 | * @return \Arcanedev\Html\Elements\Button |
||
718 | */ |
||
719 | 6 | public function reset($value, array $attributes = []): Button |
|
720 | { |
||
721 | 6 | return $this->button($value, array_merge(['type' => 'reset'], $attributes)); |
|
722 | } |
||
723 | |||
724 | /** |
||
725 | * Create a HTML image input element. |
||
726 | * |
||
727 | * @param string $url |
||
728 | * @param string|null $name |
||
729 | * @param array $attributes |
||
730 | * |
||
731 | * @return \Arcanedev\Html\Elements\Input |
||
732 | */ |
||
733 | 6 | public function image(string $url, $name = null, array $attributes = []): Input |
|
734 | { |
||
735 | 6 | return $this->input('image', $name, null, array_merge($attributes, [ |
|
736 | 6 | 'src' => $this->url->asset($url), |
|
737 | ])); |
||
738 | } |
||
739 | |||
740 | /** |
||
741 | * Create a submit button element. |
||
742 | * |
||
743 | * @param string|mixed $value |
||
744 | * @param array $attributes |
||
745 | * |
||
746 | * @return \Arcanedev\Html\Elements\Button |
||
747 | */ |
||
748 | 6 | public function submit($value = null, array $attributes = []): Button |
|
749 | { |
||
750 | 6 | return $this->button($value, array_merge(['type' => 'submit'], $attributes)); |
|
751 | } |
||
752 | |||
753 | /** |
||
754 | * Create a button element. |
||
755 | * |
||
756 | * @param string|mixed $value |
||
757 | * @param array $attributes |
||
758 | * |
||
759 | * @return \Arcanedev\Html\Elements\Button |
||
760 | */ |
||
761 | 18 | public function button($value = null, array $attributes = []): Button |
|
762 | { |
||
763 | 18 | return Button::make() |
|
764 | 18 | ->type(Arr::pull($attributes, 'type', 'button')) |
|
765 | 18 | ->attributes($attributes) |
|
766 | 18 | ->html($value); |
|
767 | } |
||
768 | |||
769 | /** |
||
770 | * Create a color input field. |
||
771 | * |
||
772 | * @param string $name |
||
773 | * @param string|mixed $value |
||
774 | * @param array $attributes |
||
775 | * |
||
776 | * @return \Arcanedev\Html\Elements\Input |
||
777 | */ |
||
778 | 18 | public function color(string $name, $value = null, array $attributes = []): Input |
|
779 | { |
||
780 | 18 | return $this->input('color', $name, $value, $attributes); |
|
781 | } |
||
782 | |||
783 | /* ----------------------------------------------------------------- |
||
784 | | Other Methods |
||
785 | | ----------------------------------------------------------------- |
||
786 | */ |
||
787 | |||
788 | /** |
||
789 | * Create a checkable input field. |
||
790 | * |
||
791 | * @param string $type |
||
792 | * @param string $name |
||
793 | * @param mixed $value |
||
794 | * @param bool|null $checked |
||
795 | * @param array $attributes |
||
796 | * |
||
797 | * @return \Arcanedev\Html\Elements\Input |
||
798 | */ |
||
799 | 42 | protected function checkable(string $type, string $name, $value, $checked, array $attributes): Input |
|
800 | { |
||
801 | 42 | $checked = $this->getCheckedState($type, $name, $value, $checked); |
|
802 | |||
803 | 42 | if ( ! is_null($checked) && $checked) |
|
804 | 36 | $attributes['checked'] = 'checked'; |
|
805 | |||
806 | 42 | return $this->input($type, $name, $value, $attributes); |
|
807 | } |
||
808 | |||
809 | /** |
||
810 | * Get the check state for a checkable input. |
||
811 | * |
||
812 | * @param string $type |
||
813 | * @param string $name |
||
814 | * @param mixed $value |
||
815 | * @param bool|null $checked |
||
816 | * |
||
817 | * @return bool |
||
818 | */ |
||
819 | 42 | private function getCheckedState(string $type, string $name, $value, $checked): bool |
|
820 | { |
||
821 | 42 | switch($type) { |
|
822 | 42 | case 'checkbox': |
|
823 | 24 | return $this->getCheckboxCheckedState($name, $value, $checked); |
|
824 | |||
825 | 18 | case 'radio': |
|
826 | 12 | return $this->getRadioCheckedState($name, $value, $checked); |
|
827 | |||
828 | default: |
||
829 | 6 | return $this->getValueAttribute($name) === $value; |
|
830 | } |
||
831 | } |
||
832 | |||
833 | /** |
||
834 | * Get the check state for a checkbox input. |
||
835 | * |
||
836 | * @param string $name |
||
837 | * @param mixed $value |
||
838 | * @param bool|null $checked |
||
839 | * |
||
840 | * @return bool |
||
841 | */ |
||
842 | 24 | private function getCheckboxCheckedState(string $name, $value, $checked): bool |
|
843 | { |
||
844 | if ( |
||
845 | 24 | isset($this->session) && |
|
846 | 24 | ! $this->oldInputIsEmpty() && |
|
847 | 24 | is_null($this->old($name)) |
|
848 | ) { |
||
849 | 6 | return false; |
|
850 | } |
||
851 | |||
852 | 24 | if ($this->missingOldAndModel($name)) { |
|
853 | 12 | return (bool) $checked; |
|
854 | } |
||
855 | |||
856 | 12 | $posted = $this->getValueAttribute($name, $checked); |
|
857 | |||
858 | 12 | if (is_array($posted)) { |
|
859 | 6 | return in_array($value, $posted); |
|
860 | } |
||
861 | |||
862 | 12 | if ($posted instanceof Collection) { |
|
863 | 6 | return $posted->contains('id', $value); |
|
864 | } |
||
865 | |||
866 | 12 | return (bool) $posted; |
|
867 | } |
||
868 | |||
869 | /** |
||
870 | * Get the check state for a radio input. |
||
871 | * |
||
872 | * @param string $name |
||
873 | * @param mixed $value |
||
874 | * @param bool|null $checked |
||
875 | * |
||
876 | * @return bool |
||
877 | */ |
||
878 | 12 | private function getRadioCheckedState(string $name, $value, $checked): bool |
|
879 | { |
||
880 | 12 | if ($this->missingOldAndModel($name)) { |
|
881 | 6 | return (bool) $checked; |
|
882 | } |
||
883 | |||
884 | 6 | return $this->getValueAttribute($name) === $value; |
|
885 | } |
||
886 | |||
887 | /** |
||
888 | * Determine if old input or model input exists for a key. |
||
889 | * |
||
890 | * @param string $name |
||
891 | * |
||
892 | * @return bool |
||
893 | */ |
||
894 | 36 | private function missingOldAndModel(string $name): bool |
|
895 | { |
||
896 | 36 | return is_null($this->old($name)) |
|
897 | 36 | && is_null($this->getModelValueAttribute($name)); |
|
898 | } |
||
899 | |||
900 | /** |
||
901 | * Get the form action from the options. |
||
902 | * |
||
903 | * @param array $attributes |
||
904 | * |
||
905 | * @return string |
||
906 | */ |
||
907 | 84 | private function getAction(array $attributes): string |
|
908 | { |
||
909 | 84 | if (isset($attributes['url'])) |
|
910 | 6 | return $this->getUrlAction($attributes['url']); |
|
911 | |||
912 | 78 | if (isset($attributes['route'])) |
|
913 | 12 | return $this->getRouteAction($attributes['route']); |
|
914 | |||
915 | 72 | if (isset($attributes['action'])) |
|
916 | 12 | return $this->getControllerAction($attributes['action']); |
|
917 | |||
918 | 60 | return $this->url->current(); |
|
919 | } |
||
920 | |||
921 | /** |
||
922 | * Get the action for a "url" option. |
||
923 | * |
||
924 | * @param array|string $attribute |
||
925 | * |
||
926 | * @return string |
||
927 | */ |
||
928 | 6 | private function getUrlAction($attribute): string |
|
929 | { |
||
930 | 6 | return is_array($attribute) |
|
931 | 6 | ? $this->url->to($attribute[0], array_slice($attribute, 1)) |
|
932 | 6 | : $this->url->to($attribute); |
|
933 | } |
||
934 | |||
935 | /** |
||
936 | * Get the action for a "route" option. |
||
937 | * |
||
938 | * @param array|string $attribute |
||
939 | * |
||
940 | * @return string |
||
941 | */ |
||
942 | 12 | private function getRouteAction($attribute): string |
|
943 | { |
||
944 | 12 | return is_array($attribute) |
|
945 | 6 | ? $this->url->route($attribute[0], array_slice($attribute, 1)) |
|
946 | 12 | : $this->url->route($attribute); |
|
947 | } |
||
948 | |||
949 | /** |
||
950 | * Get the action for an "action" option. |
||
951 | * |
||
952 | * @param array|string $attribute |
||
953 | * |
||
954 | * @return string |
||
955 | */ |
||
956 | 12 | private function getControllerAction($attribute): string |
|
957 | { |
||
958 | 12 | return is_array($attribute) |
|
959 | 6 | ? $this->url->action($attribute[0], array_slice($attribute, 1)) |
|
960 | 12 | : $this->url->action($attribute); |
|
961 | } |
||
962 | } |
||
963 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.