diff --git a/README.md b/README.md index cc22df4..4856fa2 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,25 @@ [![Latest Version on Packagist][ico-version]][link-packagist] [![Total Downloads][ico-downloads]][link-downloads] -This is a package for creating Bootstrap 4 styled form elements in Laravel 5/6. +This is a package for creating Bootstrap 4 styled form elements in Laravel 5/6. +Forked from https://github.com/netojose/laravel-bootstrap-4-forms that seems abandoned. +Contains unmerged pull request from original repository: +https://github.com/netojose/laravel-bootstrap-4-forms/pull/102 +https://github.com/netojose/laravel-bootstrap-4-forms/pull/99 +https://github.com/netojose/laravel-bootstrap-4-forms/pull/97 +https://github.com/netojose/laravel-bootstrap-4-forms/pull/86 ## Features - Labels - Error messages -- Bootstrap 4 markup and classes (including state, colors, and sizes) +- Bootstrap 4 markup and classes (including state, colors, grouping and sizes) - Error validation messages - Form fill (using Model instance, array or after form submission when a validation error occurs) - Internationalization - Add parameters using php chaining approach - Zero dependences (no Laravel Collective dependency) +- Optional [TwigBridge](https://github.com/rcrowe/TwigBridge) extension ## Introduction @@ -73,6 +80,17 @@ If you is using Laravel 5.5, the auto discovery feature will make everything for ], ``` +#### [Optional] Add TwigBridge support to config/twigbridge.php: + +```php +'extensions' => [ + //... + 'enabled' => [ + 'NetoJose\Bootstrap4Forms\Extension\TwigBridge' + ] +], +``` + ## Usage ### Basic form controls @@ -99,6 +117,16 @@ If you is using Laravel 5.5, the auto discovery feature will make everything for {!!Form::open()->formInline(false)!!} ``` +#### Multipart form + +```php +// Changes enctype of form to "multipart/form-data" +{!!Form::open()->multipart()!!} + +// You can use FALSE to turn off form multipart +{!!Form::open()->multipart(false)!!} +``` + #### Fieldset | Param | Type | Default | Description | @@ -879,6 +907,75 @@ Set max attribute for input {!!Form::text('name', 'Name')->disableIsValid()!!} ``` +### Input group +Currently it only works with Select and Inputs of text, date, time, tel and url. + +### Append +| Param | Type | Default | Description | +|---------|--------|---------|-------------------------| +| $append | string | null | Append text | +| $attrs | array | null | Append input attributes | + +```php +// Example +{!!Form::text('name', 'Name')->append('Input group append')!!} + +{!!Form::tel('phone', 'Phone')->append('Input group append')!!} +``` + +### Prepend +| Param | Type | Default | Description | +|----------|--------|---------|--------------------------| +| $prepend | string | null | Prepend text | +| $attrs | array | null | Prepend input attributes | + +```php +// Example +{!!Form::select('cars', 'Cars', [])->prepend('Input group prepend')!!} + +{!!Form::date('date', 'Date')->prepend('Input group append')!!} +``` + +### Group attributes in wrapper div +| Param | Type | Default | Description | +|:------:|:-----:|:-------:|:----------------------:| +| $attrs | array | null | Group input attributes | + +```php +// Example +{!!Form::text('name', 'Name')->prepend('Input group') + ->wrapperGroupAttrs([['id'=> 'group-wrapper']])!!} + +// will output
...
+``` + +### Append attributes in wrapper div +| Param | Type | Default | Description | +|:------:|:-----:|:-------:|:----------------------:| +| $attrs | array | null | Append input attributes | + +```php +// Example +{!!Form::text('name', 'Name')->append('Input group append') + ->wrapperAppendAttrs([['id'=> 'append-wrapper']])!!} + + +// will output
...
+``` + +### Prepend attributes in wrapper div +| Param | Type | Default | Description | +|:------:|:-----:|:-------:|:----------------------:| +| $attrs | array | null | Prepend input attributes | + +```php +// Example +{!!Form::text('name', 'Name')->append('Input group prepend') + ->wrapperPrependAttrs([['id'=> 'prepend-wrapper']])!!} + +// will output
...
+``` + ### Chaining properties You can use chaining feature to use a lot of settings for each component @@ -897,7 +994,19 @@ You can use chaining feature to use a lot of settings for each component {!!Form::close()!!} ``` +### Use in Twig templates +``` +// Examples + +{{ form_open().put().multipart().route('user.add').fill(user) | raw }} + + {{ form_text('name', 'Name').placeholder('Type your name').lg() | raw }} + {{ form_submit('Save') }} + +{{ form_close() }} +``` + [ico-version]: https://img.shields.io/packagist/v/netojose/laravel-bootstrap-4-forms.svg?style=flat-square [ico-downloads]: https://img.shields.io/packagist/dt/netojose/laravel-bootstrap-4-forms.svg?style=flat-square [link-packagist]: https://packagist.org/packages/netojose/laravel-bootstrap-4-forms -[link-downloads]: https://packagist.org/packages/netojose/laravel-bootstrap-4-forms \ No newline at end of file +[link-downloads]: https://packagist.org/packages/netojose/laravel-bootstrap-4-forms diff --git a/composer.json b/composer.json index b25e8d0..a1d112b 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "netojose/laravel-bootstrap-4-forms", + "name": "kaziu687/laravel-bootstrap-4-forms", "type": "package", "description": "Bootstrap 4 form builder for Laravel 5", "keywords": [ diff --git a/src/Extension/TwigBridge.php b/src/Extension/TwigBridge.php new file mode 100644 index 0000000..8058d85 --- /dev/null +++ b/src/Extension/TwigBridge.php @@ -0,0 +1,28 @@ +form = $form; + } +} \ No newline at end of file diff --git a/src/FormBuilder.php b/src/FormBuilder.php index 5ad8523..5e72623 100644 --- a/src/FormBuilder.php +++ b/src/FormBuilder.php @@ -1,465 +1,661 @@ -$formatter($value); - } - $this->attrs[$key] = $value; - } - - private function formatMethod($value) - { - return strtolower($value); - } - - private function formatFormData($value) - { - if (is_object($value) && method_exists($value, 'toArray')) { - return $value->toArray(); - } - return $value; - } - - private function formatOptions($value) - { - extract($this->get('optionIdKey', 'optionValueKey')); - - $idKey = $optionIdKey ?? 'id'; - $valueKey = $optionValueKey ?? 'name'; - - $options = []; - foreach ($value as $key => $item) { - if (is_object($item)) { - $options[$item->{$idKey}] = $item->{$valueKey}; - continue; - } - $options[$key] = $item; - } - return $options; - } - - public function render(): string - { - $render = $this->attrs['render']; - $methodName = 'render' . ucfirst($render); - $output = $this->$methodName(); - $this->resetAttributes(); - return $output; - } - - private function renderFormOpen(): string - { - extract($this->get('id', 'method', 'url', 'formMultipart', 'formInline', 'autocomplete')); - - if (!$method) { - $method = 'post'; - } - - $enctype = $formMultipart ? 'multipart/form-data' : null; - - $attrs = $this->buildHtmlAttrs([ - 'method' => in_array($method, ['get', 'post']) ? $method : 'post', - 'action' => $url, - 'enctype' => $enctype, - 'autocomplete' => $autocomplete, - 'class' => $formInline ? 'form-inline' : null, - 'id' => $id - ]); - - $output = '
'; - - if ($method !== 'get') { - $output .= csrf_field(); - if ($method !== 'post') { - $output .= method_field($method); - } - } - - return $output; - } - - private function renderFormClose(): string - { - $this->resetAttributes(true); - return '
'; - } - - private function renderFieldsetOpen(): string - { - $output = '
'; - extract($this->get('legend')); - - if ($legend) { - $output .= '' . $this->getText($legend) . ''; - } - - return $output; - } - - private function renderFieldsetClose(): string - { - return '
'; - } - - private function renderErrors(): string - { - $errors = $this->errors()->all(); - if (count($errors) < 1) { - return ''; - } - - extract($this->get('errorsHeader', 'id')); - $attrs = $this->buildHtmlAttrs(['class' => 'alert alert-danger', 'role' => 'alert', 'id' => $id]); - $output = '
'; - } - - private function renderInput(): string - { - $attributes = $this->getInputAttributes(); - $attrs = $this->buildHtmlAttrs($attributes); - return $this->wrapperInput(''); - } - - private function renderSelect(): string - { - extract($this->get('options')); - - $fieldValue = $this->getValue(); - $arrValues = is_array($fieldValue) ? $fieldValue : [$fieldValue]; - $optionsList = ''; - foreach ($options as $value => $label) { - $attrs = $this->buildHtmlAttrs(['value' => $value, 'selected' => in_array($value, $arrValues)], false); - $optionsList .= ''; - } - - $attributes = $this->getInputAttributes(); - $attrs = $this->buildHtmlAttrs($attributes); - return $this->wrapperInput(''); - } - - private function renderTextarea(): string - { - $attributes = $this->getInputAttributes(); - $value = $attributes['value']; - unset($attributes['value']); - $attrs = $this->buildHtmlAttrs($attributes); - return $this->wrapperInput(''); - } - - private function renderCheckbox(): string - { - $attributes = $this->getInputAttributes(); - $attrs = $this->buildHtmlAttrs($attributes); - return $this->wrapperRadioCheckbox(''); - } - - private function renderRadio(): string - { - $attributes = $this->getInputAttributes(); - $attrs = $this->buildHtmlAttrs($attributes); - return $this->wrapperRadioCheckbox(''); - } - - private function renderAnchor(): string - { - extract($this->get('url', 'value')); - $class = $this->getBtnAnchorClasses(); - $attrs = $this->buildHtmlAttrs(['href' => $url, 'class' => $class]); - return '' . $value . ''; - } - - private function renderButton(): string - { - extract($this->get('type', 'value', 'disabled')); - $class = $this->getBtnAnchorClasses(); - $attrs = $this->buildHtmlAttrs(['type' => $type, 'class' => $class, 'disabled' => $disabled]); - return ''; - } - - private function getBtnAnchorClasses() - { - extract($this->get('size', 'color', 'outline', 'block', 'type', 'value', 'formInline')); - return $this->createAttrsList( - 'btn', - [$size, 'btn-' . $size], - [$color, 'btn-' . ($outline ? 'outline-' : '') . $color], - [$block, 'btn-block'], - [$formInline, 'mx-sm-2'] - ); - } - - private function isRadioOrCheckbox(): bool - { - extract($this->get('render')); - return in_array($render, ['checkbox', 'radio']); - } - - private function getInputAttributes(): array - { - extract($this->get('render', 'type', 'multiple', 'name', 'size', 'placeholder', 'help', 'disabled', 'readonly', 'required', 'autocomplete', 'min', 'max', 'value', 'checked', 'formData', 'disableValidation')); - - $isRadioOrCheckbox = $this->isRadioOrCheckbox(); - $type = $isRadioOrCheckbox ? $render : $type; - - $class = 'form-check-input'; - if (!$isRadioOrCheckbox) { - $class = 'form-control'; - switch ($type) { - case 'file': - $class .= '-file'; - break; - case 'range': - $class .= '-range'; - break; - } - - if ($size) { - $class .= ' form-control-' . $size; - } - } - - $id = $this->getId(); - - if (!$disableValidation && $this->errors()->count() > 0) { - $class .= $this->errors()->has($name) ? ' is-invalid' : ' is-valid'; - } - - $attributes = [ - 'type' => $type, - 'name' => $name, - 'id' => $id - ]; - - if ($render !== 'select') { - $attributes['value'] = $this->getValue(); - } else { - $attributes['multiple'] = $multiple; - } - - // If the field is a hidden field, we don't need add more attributes - if ($type === 'hidden') { - return $attributes; - } - - if ($this->isRadioOrCheckbox()) { - if ($this->hasOldInput()) { - $isChecked = old($name) === $value; - } else { - $isChecked = isset($formData[$name]) ? $formData[$name] === $value : $checked; - } - $attributes['checked'] = $isChecked; - } - - return array_merge($attributes, [ - 'class' => $class, - 'min' => $min, - 'max' => $max, - 'autocomplete' => $autocomplete, - 'placeholder' => $this->getText($placeholder), - 'aria-describedby' => $help ? 'help-' . $id : null, - 'disabled' => $disabled, - 'readonly' => $readonly, - 'required' => $required - ]); - } - - private function renderLabel(): string - { - extract($this->get('label', 'formInline', 'render')); - - $class = in_array($render, ['checkbox', 'radio']) ? 'form-check-label' : ''; - if ($formInline) { - $class = join(' ', [$class, 'mx-sm-2']); - } - - $id = $this->getId(); - $attrs = $this->buildHtmlAttrs([ - 'for' => $id, - 'class' => $class - ], false); - return ''; - } - - private function getText($key) - { - extract($this->get('formLocale')); - if ($formLocale) { - return __($formLocale . '.' . $key); - } - return $key; - } - - private function resetAttributes($resetAll = false) - { - // Remove all attributes - if ($resetAll) { - $this->attrs = []; - return; - } - - // Keep attributes which key starting with 'form' - $this->attrs = array_filter($this->attrs, function ($key) { - return substr($key, 0, 4) === 'form'; - }, ARRAY_FILTER_USE_KEY); - } - - private function wrapperInput(string $input): string - { - extract($this->get('type', 'help', 'wrapperAttrs', 'formInline', 'name')); - - if ($type === 'hidden') { - return $input; - } - - $id = $this->getId(); - $label = $this->renderLabel(); - $helpText = $help ? '' . $this->getText($help) . '' : ''; - $error = $this->getInputErrorMarkup($name); - $attrs = $wrapperAttrs ?? []; - $attrs['class'] = $this->createAttrsList( - $attrs['class'] ?? null, - $formInline ? 'input-group' : 'form-group' - ); - $attributes = $this->buildHtmlAttrs($attrs, false); - - return '
' . $label . $input . $helpText . $error . '
'; - } - - private function wrapperRadioCheckbox(string $input): string - { - extract($this->get('inline', 'name', 'wrapperAttrs')); - - $attrs = $wrapperAttrs ?? []; - $attrs['class'] = $this->createAttrsList( - 'form-check', - [$inline, 'form-check-inline'], - $attrs['class'] ?? null - ); - $attributes = $this->buildHtmlAttrs($attrs, false); - $label = $this->renderLabel(); - $error = $this->getInputErrorMarkup($name); - return '
' . $input . $label . $error . '
'; - } - - private function getInputErrorMarkup(string $name): string - { - extract($this->get('disableValidation')); - - if ($disableValidation) { - return ''; - } - - $error = $this->errors()->first($name); - if (!$error) { - return ''; - } - return '
' . $this->errors()->first($name) . '
'; - } - - private function getId() - { - extract($this->get('id', 'name', 'formIdPrefix', 'render', 'value')); - - if ($id) { - return $id; - } - - return ($formIdPrefix ?? 'inp-') . $name . ($render === 'radio' ? '-' . $value : ''); - } - - private function hasOldInput() - { - return count((array) old()) != 0; - } - - private function getValue() - { - extract($this->get('name', 'value', 'formData')); - if ($this->isRadioOrCheckbox()) { - return $value; - } - - if ($this->hasOldInput()) { - return old($name, $value); - } - - $fromFill = $formData[$name] ?? null; - - return $value ?? $fromFill; - } - - private function buildHtmlAttrs(array $attributes, $appendAttrs = true): string - { - - if ($appendAttrs) { - extract($this->get('attrs')); - $fieldAttrs = $attrs ?? []; - $class = $this->createAttrsList($attributes['class'] ?? null, $fieldAttrs['class'] ?? null); - if ($class) { - $attributes['class'] = $class; - } - $attributes = array_merge($fieldAttrs, $attributes); - } - - return join(' ', array_filter( - array_map(function ($key) use ($attributes) { - $value = $attributes[$key]; - if (is_bool($value)) { - return $value ? $key : ''; - } elseif ($value !== null) { - return $key . '="' . htmlspecialchars($value) . '"'; - } - return ''; - }, array_keys($attributes)) - )); - } - - private function createAttrsList(...$items) - { - $attrs = []; - foreach ($items as $item) { - if (is_array($item)) { - $item = $item[0] ? $item[1] : null; - } - $attrs[] = $item; - } - return join(' ', array_filter($attrs)); - } - - private function errors() - { - $errors = session('errors', app(ViewErrorBag::class)); - extract($this->get('formErrorBag')); - if ($formErrorBag) { - $errors = $errors->{$formErrorBag}; - } - return $errors; - } - - private function get(...$keys): array - { - $return = []; - foreach ($keys as $key) { - $return[$key] = $this->attrs[$key] ?? null; - } - return $return; - } -} +$formatter($value); + } + $this->attrs[$key] = $value; + } + + protected function formatMethod($value) + { + return strtolower($value); + } + + protected function formatFormData($value) + { + if (is_object($value) && method_exists($value, 'toArray')) { + return $value->toArray(); + } + return $value; + } + + protected function formatOptions($value) + { + extract($this->get('optionIdKey', 'optionValueKey')); + + $idKey = $optionIdKey ?? 'id'; + $valueKey = $optionValueKey ?? 'name'; + + $options = []; + foreach ($value as $key => $item) { + if (is_object($item)) { + $options[$item->{$idKey}] = $item->{$valueKey}; + continue; + } + $options[$key] = $item; + } + return $options; + } + + public function render(): string + { + $render = $this->attrs['render']; + $methodName = 'render' . ucfirst($render); + $output = $this->$methodName(); + $this->resetAttributes(); + return $output; + } + + protected function renderFormOpen(): string + { + extract($this->get('id', 'method', 'url', 'formMultipart', 'formInline', 'autocomplete', 'attrs')); + + if (!$method) { + $method = 'post'; + } + + $enctype = $formMultipart ? 'multipart/form-data' : null; + + $attrs = $attrs ?? []; + $attrs['class'] = $this->createAttrsList( + ($formInline ? 'form-inline' : null), + $attrs['class'] ?? null + ); + + $attrs = $this->buildHtmlAttrs(array_merge($attrs, [ + 'method' => in_array($method, ['get', 'post']) ? $method : 'post', + 'action' => $url, + 'enctype' => $enctype, + 'autocomplete' => $autocomplete, + 'id' => $id + ])); + + $output = '
'; + + if ($method !== 'get') { + $output .= csrf_field(); + if ($method !== 'post') { + $output .= method_field($method); + } + } + + return $output; + } + + protected function renderFormClose(): string + { + $this->resetAttributes(true); + return '
'; + } + + protected function renderFieldsetOpen(): string + { + $output = '
'; + extract($this->get('legend')); + + if ($legend) { + $output .= '' . $this->getText($legend) . ''; + } + + return $output; + } + + protected function renderFieldsetClose(): string + { + return '
'; + } + + protected function renderErrors(): string + { + $errors = $this->errors()->all(); + if (count($errors) < 1) { + return ''; + } + + extract($this->get('errorsHeader', 'id')); + $attrs = $this->buildHtmlAttrs(['class' => 'alert alert-danger', 'role' => 'alert', 'id' => $id]); + $output = '
'; + } + + protected function renderInput(): string + { + $attributes = $this->getInputAttributes(); + $attrs = $this->buildHtmlAttrs($attributes); + return $this->wrapperInput(''); + } + + protected function renderSelect(): string + { + extract($this->get('options', 'placeholder')); + + $fieldValue = $this->getValue(); + $arrValues = is_array($fieldValue) ? $fieldValue : [$fieldValue]; + $optionsList = $this->getSelectOptions($arrValues, $options); + + if ($placeholder) { + $optionsList = '' . $optionsList; + } + + $attributes = $this->getInputAttributes(); + $attrs = $this->buildHtmlAttrs($attributes); + return $this->wrapperInput(''); + } + + protected function renderTextarea(): string + { + $attributes = $this->getInputAttributes(); + $value = $attributes['value']; + unset($attributes['value']); + $attrs = $this->buildHtmlAttrs($attributes); + return $this->wrapperInput(''); + } + + protected function renderCheckbox(): string + { + $attributes = $this->getInputAttributes(); + $attrs = $this->buildHtmlAttrs($attributes); + return $this->wrapperRadioCheckbox(''); + } + + protected function renderRadio(): string + { + $attributes = $this->getInputAttributes(); + $attrs = $this->buildHtmlAttrs($attributes); + return $this->wrapperRadioCheckbox(''); + } + + protected function renderAnchor(): string + { + extract($this->get('url', 'value')); + $class = $this->getBtnAnchorClasses(); + $attrs = $this->buildHtmlAttrs(['href' => $url, 'class' => $class]); + return '' . $value . ''; + } + + protected function renderButton(): string + { + extract($this->get('type', 'value', 'disabled')); + $class = $this->getBtnAnchorClasses(); + $attrs = $this->buildHtmlAttrs(['type' => $type, 'class' => $class, 'disabled' => $disabled]); + return ''; + } + + protected function getBtnAnchorClasses() + { + extract($this->get('size', 'color', 'outline', 'block', 'type', 'value', 'formInline')); + return $this->createAttrsList( + 'btn', + [$size, 'btn-' . $size], + [$color, 'btn-' . ($outline ? 'outline-' : '') . $color], + [$block, 'btn-block'], + [$formInline, 'mx-sm-2'] + ); + } + + protected function isRadioOrCheckbox(): bool + { + extract($this->get('render')); + return in_array($render, ['checkbox', 'radio']); + } + + protected function getInputAttributes(): array + { + extract($this->get('render', 'type', 'multiple', 'name', 'size', 'placeholder', 'help', 'disabled', 'readonly', 'required', 'autocomplete', 'min', 'max', 'value', 'checked', 'formData', 'disableValidation', 'custom')); + + $isRadioOrCheckbox = $this->isRadioOrCheckbox(); + $type = $isRadioOrCheckbox ? $render : $type; + + $class = 'form-check-input'; + if ($custom) { + $class = $this->customClass('input'); + } elseif (!$isRadioOrCheckbox) { + $class = 'form-control'; + switch ($type) { + case 'file': + $class .= '-file'; + break; + case 'range': + $class .= '-range'; + break; + } + + if ($size) { + $class .= ' form-control-' . $size; + } + } + + $id = $this->getId(); + + if (!$disableValidation && $this->errors()->count() > 0) { + $class .= $this->errors()->has(\rtrim(\str_replace(['][', '[', ']'], '.', $name), '.')) ? ' is-invalid' : ' is-valid'; + } + + $attributes = [ + 'type' => $type, + 'name' => $name, + 'id' => $id + ]; + + if ($render !== 'select') { + $attributes['value'] = $this->getValue(); + } else { + $attributes['multiple'] = $multiple; + if ($multiple) { + $attributes['name'] .= '[]'; + } + } + + // If the field is a hidden field, we don't need add more attributes + if ($type === 'hidden') { + return $attributes; + } + + if ($this->isRadioOrCheckbox()) { + if ($this->hasOldInput()) { + $isChecked = old($name) === $value; + } else { + $value = $value === 'on' ? true : false; + $isChecked = isset($formData[$name]) ? $formData[$name] === $value : $checked; + } + $attributes['checked'] = $isChecked; + } + + return array_merge($attributes, [ + 'class' => $class, + 'min' => $min, + 'max' => $max, + 'autocomplete' => $autocomplete, + 'placeholder' => $this->getText($placeholder), + 'aria-describedby' => $help ? 'help-' . $id : null, + 'disabled' => $disabled, + 'readonly' => $readonly, + 'required' => $required + ]); + } + + protected function getSelectOptions($arrValues, $options, $optgroup_label = '') + { + extract($this->get('optgroup')); + + $optionsList = ''; + foreach ($options as $value => $label) { + if (is_array($label)) { + $optionsList .= '' + . $this->getSelectOptions($arrValues, $label, $value.';') . ''; + }else{ + if ($optgroup) { + $value = $optgroup_label.$value; + } + $attrs = $this->buildHtmlAttrs([ + 'value' => $value, + 'selected' => in_array($value, $arrValues) + ], false); + $optionsList .= ''; + } + } + return $optionsList; + } + + protected function renderLabel(): string + { + extract($this->get('label', 'formInline', 'render', 'labelAttrs', 'custom')); + + if (is_null($label)) { + return ''; + } + + $class = ''; + if ($custom) { + $class = $this->customClass('label'); + } elseif (in_array($render, ['checkbox', 'radio'])) { + $class = 'form-check-label'; + } + + if ($formInline) { + $class = join(' ', [$class, 'mx-sm-2']); + } + + $attrs = $labelAttrs ?? []; + $attrs['class'] = $this->createAttrsList( + $attrs['class'] ?? null, + $class + ); + $attrs['for'] = $this->getId(); + $attrs = $this->buildHtmlAttrs($attrs, false); + return ''; + } + + protected function getText($key) + { + extract($this->get('formLocale')); + if ($formLocale) { + return __($formLocale . '.' . $key); + } + return $key; + } + + protected function wrapperInputGroup(string $input): string + { + extract($this->get('append', 'prepend', 'formInline', 'wrapperGroupAttrs', 'type', 'options', 'disableValidation', 'name')); + + if ((!$append && !$prepend) || !(in_array($type, ['text', 'date', 'time', 'tel', 'url', 'password']) || is_array($options))) { + return $input; + } + + $output = ($prepend ? $this->getInputGroup('prepend', $prepend) : '') . $input; + $output .= $append ? $this->getInputGroup('append', $append) : ''; + $attrs = $wrapperGroupAttrs ?? []; + + $class = 'input-group'; + + if (!$disableValidation && $this->errors()->count() > 0) { + $class .= $this->errors()->has(\rtrim(\str_replace(['][', '[', ']'], '.', $name), '.')) ? ' is-invalid' : ' is-valid'; + } + + $attrs['class'] = $this->createAttrsList( + $class, + $attrs['class'] ?? null + ); + $attrs = $this->buildHtmlAttrs($attrs, false); + + if (!$formInline) { + $output = '
' . $output . '
'; + } + + return $output; + } + + protected function getInputGroup(string $type, $value): string + { + $wrapperType = 'wrapper'. ucwords($type) . 'Attrs'; + extract($this->get('onlyInput', $wrapperType)); + + $attrs = $$wrapperType ?? []; + $attrs['class'] = $this->createAttrsList( + 'input-group-' . $type, + $attrs['class'] ?? null + ); + + $attrs = $this->buildHtmlAttrs($attrs, false); + $output = '
'; + + if (is_array($value)) { + foreach ($value as $text) { + $output .= $this->getInputGroupText($type, $text); + } + }else{ + $output .= $this->getInputGroupText($type, $value); + } + + return $output . '
'; + } + + protected function getInputGroupText(string $type, string $value): string + { + extract($this->get($type . 'Attrs', $type . 'Style')); + + $attrs = ${$type . 'Attrs'} ?? []; + $attrs['class'] = $this->createAttrsList( + ( ${$type . 'Style'} ? 'input-group-text' : ''), + $attrs['class'] ?? null + ); + + if (!array_key_exists('id', $attrs)) { + $attrs['id'] = $type . '-' . $this->getId(); + } + + $attrs = $this->buildHtmlAttrs($attrs, false); + return '
' . $this->getText($value) . '
'; + } + + protected function resetAttributes($resetAll = false) + { + // Remove all attributes + if ($resetAll) { + $this->attrs = []; + return; + } + + // Keep attributes which key starting with 'form' + $this->attrs = array_filter($this->attrs, function ($key) { + return substr($key, 0, 4) === 'form'; + }, ARRAY_FILTER_USE_KEY); + } + + protected function wrapperInput(string $input): string + { + extract($this->get('type', 'help', 'wrapperAttrs', 'formInline', 'name', 'custom')); + + if ($type === 'hidden') { + return $input; + } + + $id = $this->getId(); + $label = $this->renderLabel(); + $helpText = $help ? '' . $this->getText($help) . '' : ''; + $error = $this->getInputErrorMarkup($name); + $attrs = $wrapperAttrs ?? []; + $attrs['class'] = $this->createAttrsList( + $custom ? $this->customClass('wrapper') : '', + $attrs['class'] ?? null, + $formInline ? 'input-group' : 'form-group' + ); + $attributes = $this->buildHtmlAttrs($attrs, false); + $input = $this->wrapperInputGroup($input); + + if ($custom && $type === 'file') { + $placeholder = $label; + $this->set('custom', false); + $label = $this->renderLabel(); + $this->set('custom', true); + + return '
' . $label . '
' . $placeholder . $input . $helpText . $error . '
'; + } else { + return '
' . $label . $input . $helpText . $error . '
'; + } + } + + protected function wrapperRadioCheckbox(string $input): string + { + extract($this->get('inline', 'name', 'wrapperAttrs', 'onlyInput', 'custom')); + + if ($onlyInput) { + return $input; + } + + $attrs = $wrapperAttrs ?? []; + $attrs['class'] = $this->createAttrsList( + $custom ? $this->customClass('wrapper') : 'form-check', + [$inline, ($custom ? 'form-check-inline' : 'custom-control-inline')], + $attrs['class'] ?? null + ); + $attributes = $this->buildHtmlAttrs($attrs, false); + $label = $this->renderLabel(); + $error = $this->getInputErrorMarkup($name); + return '
' . $input . $label . $error . '
'; + } + + protected function getInputErrorMarkup(string $name): string + { + extract($this->get('disableValidation')); + + if ($disableValidation) { + return ''; + } + + $error = $this->errors()->has(\rtrim(\str_replace(['][', '[', ']'], '.', $name), '.')); + if (!$error) { + return ''; + } + return '
' . $this->errors()->first(\rtrim(\str_replace(['][', '[', ']'], '.', $name), '.')) . '
'; + } + + protected function getId() + { + extract($this->get('id', 'name', 'formIdPrefix', 'render', 'value')); + + if ($id) { + return $id; + } + + return ($formIdPrefix ?? 'inp-') . $name . ($render === 'radio' ? '-' . $value : ''); + } + + protected function hasOldInput() + { + return count((array) old()) != 0; + } + + protected function getValue() + { + extract($this->get('name', 'value', 'formData')); + if ($this->isRadioOrCheckbox()) { + return $value; + } + + if ($this->hasOldInput()) { + if (isset(old()[$name])) { + return old(preg_replace("/\[\]/", "", $name), $value); + } + } + + $fromFill = $formData[$name] ?? null; + + return $value ?? $fromFill; + } + + protected function buildHtmlAttrs(array $attributes, $appendAttrs = true): string + { + + if ($appendAttrs) { + extract($this->get('attrs')); + $fieldAttrs = $attrs ?? []; + $class = $this->createAttrsList($attributes['class'] ?? null, $fieldAttrs['class'] ?? null); + if ($class) { + $attributes['class'] = $class; + } + $attributes = array_merge($fieldAttrs, $attributes); + } + + return join(' ', array_filter( + array_map(function ($key) use ($attributes) { + $value = $attributes[$key]; + if (is_bool($value)) { + return $value ? $key : ''; + } elseif ($value !== null) { + return $key . '="' . htmlspecialchars($value) . '"'; + } + return ''; + }, array_keys($attributes)) + )); + } + + protected function customClass(string $element = 'input') + { + extract($this->get('type', 'size', 'inline', 'render')); + + $type = $type ?? $render; + $input = $element === 'input'; + $wrapper = $element === 'wrapper'; + $label = $element === 'label'; + + if($input){ + $class = 'custom-control-input'; + } elseif($wrapper){ + $class = 'custom-control' . (isset($inline) && $inline ? ' custom-control-inline' : ''); + } else { + $class = 'custom-control-label'; + } + + switch($type){ + case 'checkbox': + if($wrapper){ + $class .= ' custom-checkbox'; + } + break; + case 'radio': + if($wrapper){ + $class .= ' custom-radio'; + } + break; + case 'switch': + if($wrapper){ + $class .= ' custom-switch'; + } + break; + case 'select': + if($input){ + $class = 'custom-select'; + $class = $size ? $class . '-' . $size : $class; + } elseif($label || $wrapper){ + $class = ''; + } + break; + case 'range': + $class = $input ? 'custom-range' : ''; + break; + case 'file': + if($wrapper) { + $class = 'custom-file'; + } elseif($input) { + $class = 'custom-file-input'; + } else{ + $class = 'custom-file-label'; + } + break; + default: + // do nothing + } + return $class; + } + + protected function createAttrsList(...$items) + { + $attrs = []; + foreach ($items as $item) { + if (is_array($item)) { + $item = $item[0] ? $item[1] : null; + } + $attrs[] = $item; + } + return join(' ', array_filter($attrs)); + } + + protected function errors() + { + $errors = session('errors', app(ViewErrorBag::class)); + extract($this->get('formErrorBag')); + if ($formErrorBag) { + $errors = $errors->{$formErrorBag}; + } + return $errors; + } + + protected function get(...$keys): array + { + $return = []; + foreach ($keys as $key) { + $return[$key] = $this->attrs[$key] ?? null; + } + return $return; + } +} diff --git a/src/FormService.php b/src/FormService.php index 3f43062..7ab4d35 100644 --- a/src/FormService.php +++ b/src/FormService.php @@ -1,856 +1,959 @@ -_builder = new FormBuilder; - } - - /** - * Magic method to return a class string version - * - * @return string - */ - public function __toString() - { - return $this->_builder->render(); - } - - /** - * Set error bag name - * - * @param string $value - * @return FormService - */ - public function errorBag(string $value = null): FormService - { - return $this->_set('formErrorBag', $value); - } - - /** - * Open the form - * - * @return FormService - */ - public function open(): FormService - { - return $this->_set('render', 'formOpen'); - } - - /** - * Close the form - * - * @return FormService - */ - public function close(): FormService - { - return $this->_set('render', 'formClose'); - } - - /** - * Show all validation errors - * - * @param string $title - * @return FormService - */ - public function errors(string $title = null): FormService - { - return $this->_set('render', 'errors')->_set('errorsHeader', $title); - } - - /** - * Set a prefix id for all inputs - * - * @param string $prefix - * @return FormService - */ - public function idPrefix(string $prefix = ''): FormService - { - return $this->_set('formIdPrefix', $prefix); - } - - /** - * Set multipart attribute for a form - * - * @param bool $multipart - * @return FormService - */ - public function multipart(bool $multipart = true): FormService - { - return $this->_set('formMultipart', $multipart); - } - - /** - * Set a method attribute for the form - * - * @param string $method - * @return FormService - */ - public function method(string $method): FormService - { - return $this->_set('method', $method); - } - - /** - * Set get method for the form attribute - * - * @return FormService - */ - public function get(): FormService - { - return $this->method('get'); - } - - /** - * Set post method for the form attribute - * - * @return FormService - */ - public function post(): FormService - { - return $this->method('post'); - } - - /** - * Set put method for the form attribute - * - * @return FormService - */ - public function put(): FormService - { - return $this->method('put'); - } - - /** - * Set patch method for the form attribute - * - * @return FormService - */ - public function patch(): FormService - { - return $this->method('patch'); - } - - /** - * Set delete method for the form attribute - * - * @return FormService - */ - public function delete(): FormService - { - return $this->method('delete'); - } - - /** - * Fill the form values - * - * @param array|object $data - * @return FormService - */ - public function fill($data): FormService - { - return $this->_set('formData', $data); - } - - /** - * Set locale file for inputs translations - * - * @param string $path - * @return FormService - */ - public function locale(string $path): FormService - { - return $this->_set('formLocale', $path); - } - - /** - * Set autocomplete attribute on form, or on individual input fields - * - * @param string $value - * @return FormService - */ - public function autocomplete($value = true): FormService - { - return $this->_set('autocomplete', $value); - } - - /** - * Set inline form style - * - * @param bool $inline - * @return FormService - */ - public function formInline(bool $inline = true): FormService - { - return $this->_set('formInline', $inline); - } - - /** - * Set url for links and form action - * - * @param string $url - * @return FormService - */ - public function url(string $url = null): FormService - { - return $this->_set('url', url($url ?? '')); - } - - /** - * Set route for links and form action - * - * @param string $route - * @param array $params - * @return FormService - */ - public function route(string $route, array $params = []): FormService - { - return $this->_set('url', route($route, $params)); - } - - /** - * Open a fieldset - * - * @param string $legend - * @return FormService - */ - public function fieldsetOpen(string $legend = null): FormService - { - return $this->render('fieldsetOpen')->_set('legend', $legend); - } - - /** - * Close a fieldset - * - * @return FormService - */ - public function fieldsetClose(): FormService - { - return $this->render('fieldsetClose'); - } - - /** - * Set a help text - * - * @param string $text - * @return FormService - */ - public function help(string $text): FormService - { - return $this->_set('help', $text); - } - - /** - * Create a file input - * - * @param string $name - * @param string $label - * @return FormService - */ - public function file(string $name = null, string $label = null): FormService - { - return $this->render('input')->type('file')->name($name)->label($label); - } - - /** - * Create a text input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function text(string $name = null, $label = null, string $default = null): FormService - { - return $this->render('input')->type('text')->name($name)->label($label)->value($default); - } - - /** - * Create a date input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function date(string $name = null, $label = null, string $default = null): FormService - { - return $this->render('input')->type('date')->name($name)->label($label)->value($default); - } - - /** - * Create a time input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function time(string $name = null, $label = null, string $default = null): FormService - { - return $this->render('input')->type('time')->name($name)->label($label)->value($default); - } - - /** - * Create a telephone input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function tel(string $name = null, $label = null, string $default = null): FormService - { - return $this->render('input')->type('tel')->name($name)->label($label)->value($default); - } - - /** - * Create a url input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function urlInput(string $name = null, $label = null, string $default = null): FormService - { - return $this->render('input')->type('url')->name($name)->label($label)->value($default); - } - - /** - * Create a range input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function range(string $name = null, $label = null, string $default = null): FormService - { - return $this->render('input')->type('range')->name($name)->label($label)->value($default); - } - - /** - * Set a minimum value for a field - * - * @param string $value - * @return FormService - */ - public function min($value) - { - return $this->_set('min', $value); - } - - /** - * Set a maximum value for a field - * - * @param string $value - * @return FormService - */ - public function max($value) - { - return $this->_set('max', $value); - } - - /** - * Create a hidden input - * - * @param string $name - * @param string $default - * @return FormService - */ - public function hidden(string $name = null, string $default = null): FormService - { - return $this->render('input')->type('hidden')->name($name)->value($default); - } - - /** - * Create a select input - * - * @param string $name - * @param string $label - * @param array $options - * @param string|array $default - * @return FormService - */ - public function select(string $name = null, string $label = null, $options = [], $default = null): FormService - { - return $this->render('select')->name($name)->label($label)->options($options)->value($default); - } - - /** - * Set options for a select field - * - * @param mixed $options - * @param string $valueKey - * @param string $idKey - * @return FormService - */ - public function options($options = [], string $valueKey = null, string $idKey = null): FormService - { - return $this->_set('optionValueKey', $valueKey)->_set('optionIdKey', $idKey)->_set('options', $options); - } - - /** - * Set a multiple select attribute - * - * @param bool $multiple - * @return FormService - */ - public function multiple(bool $status = true): FormService - { - return $this->_set('multiple', $status); - } - - /** - * Create a checkbox input - * - * @param string $name - * @param string $value - * @param string $label - * @param bool $checked - * @return FormService - */ - public function checkbox(string $name = null, string $label = null, string $value = 'on', bool $checked = null): FormService - { - return $this->_radioOrCheckbox('checkbox', $name, $label, $value, $checked); - } - - /** - * Create a radio input - * - * @param string $name - * @param string $value - * @param string $label - * @param bool $checked - * @return FormService - */ - public function radio(string $name = null, string $label = null, string $value = null, bool $checked = null): FormService - { - return $this->_radioOrCheckbox('radio', $name, $label, $value, $checked); - } - - /** - * Set inline input style - * @param bool $inline - * @return FormService - */ - public function inline(bool $inline = true): FormService - { - return $this->_set('inline', $inline); - } - - /** - * Create a textarea input - * - * @param string $name - * @param string $label - * @param string $default - * @return FormService - */ - public function textarea(string $name = null, $label = null, string $default = null): FormService - { - return $this->_set('render', 'textarea')->name($name)->label($label)->value($default); - } - - /** - * Set a label - * - * @param string $label - * @return FormService - */ - public function label($label): FormService - { - return $this->_set('label', $label); - } - - /** - * Create a button - * - * @param string $value - * @param string $color - * @param null $size - * @return FormService - */ - public function button(string $value = null, $color = 'primary', $size = null): FormService - { - return $this->type('button')->_set('render', 'button')->value($value)->color($color)->size($size); - } - - /** - * Create a button type submit - * - * @param string $value - * @param string $color - * @param null $size - * @return FormService - */ - public function submit(string $value, $color = 'primary', $size = null): FormService - { - return $this->button($value, $color, $size)->type('submit'); - } - - /** - * Create a button type reset - * - * @param string $value - * @param string $color - * @param null $size - * @return FormService - */ - public function reset(string $value, $color = 'primary', $size = null): FormService - { - return $this->button($value, $color, $size)->type('reset'); - } - - /** - * Create a anchor - * - * @param string $value - * @param string $url - * @return FormService - */ - public function anchor(string $value, $url = null, $color = 'primary', $size = null): FormService - { - return $this->_set('render', 'anchor')->value($value)->url($url)->color($color)->size($size); - } - - /** - * Flag a checkbox or a radio input as checked - * - * @param bool $checked - * @return FormService - */ - public function checked(bool $checked = true): FormService - { - return $this->_set('checked', $checked); - } - - /** - * Set a input value - * - * @param string $value - * @return FormService - */ - public function value($value = null): FormService - { - return $this->_set('value', $value); - } - - /** - * Set a input type - * - * @param string $type - * @return FormService - */ - public function type($type): FormService - { - return $this->_set('type', $type); - } - - /** - * Set a render - * - * @param string $render - * @return FormService - */ - public function render(string $render): FormService - { - return $this->_set('render', $render); - } - - /** - * Set a field id - * - * @param string $id - * @return FormService - */ - public function id($id): FormService - { - return $this->_set('id', $id); - } - - /** - * Set a field name - * - * @param string $name - * @return FormService - */ - public function name($name): FormService - { - return $this->_set('name', $name); - } - - /** - * Set the size - * - * @param string $size - * @return FormService - */ - public function size(string $size = null): FormService - { - return $this->_set('size', $size); - } - - /** - * Set the size as lg - * - * @return FormService - */ - public function lg(): FormService - { - return $this->size('lg'); - } - - /** - * Set the size as sm - * - * @return FormService - */ - public function sm(): FormService - { - return $this->size('sm'); - } - - /** - * Set the color - * - * @param string $color - * @return FormService - */ - public function color(string $color = null): FormService - { - return $this->_set('color', $color); - } - - /** - * Set primary color - * - * @return FormService - */ - public function primary(): FormService - { - return $this->color('primary'); - } - - /** - * Set secondary color - * - * @return FormService - */ - public function secondary(): FormService - { - return $this->color('secondary'); - } - - /** - * Set success color - * - * @return FormService - */ - public function success(): FormService - { - return $this->color('success'); - } - - /** - * Set danger color - * - * @return FormService - */ - public function danger(): FormService - { - return $this->color('danger'); - } - - /** - * Set warning color - * - * @return FormService - */ - public function warning(): FormService - { - return $this->color('warning'); - } - - /** - * Set info color - * - * @return FormService - */ - public function info(): FormService - { - return $this->color('info'); - } - - /** - * Set light color - * - * @return FormService - */ - public function light(): FormService - { - return $this->color('light'); - } - - /** - * Set dark color - * - * @return FormService - */ - public function dark(): FormService - { - return $this->color('dark'); - } - - /** - * Set link style - * - * @return FormService - */ - public function link(): FormService - { - return $this->color('link'); - } - - /** - * Set outline style - * - * @param bool $status - * @return FormService - */ - public function outline(bool $status = true): FormService - { - return $this->_set('outline', $status); - } - - /** - * Set block style - * - * @param bool $status - * @return FormService - */ - public function block(bool $status = true): FormService - { - return $this->_set('block', $status); - } - - /** - * Set readonly style - * - * @param bool $status - * @return FormService - */ - public function readonly($status = true): FormService - { - return $this->_set('readonly', $status); - } - - /** - * Set the input disabled status - * - * @param bool $status - * @return FormService - */ - public function disabled($status = true): FormService - { - return $this->_set('disabled', $status); - } - - /** - * Set the input required status - * - * @param bool $status - * @return FormService - */ - public function required($status = true): FormService - { - return $this->_set('required', $status); - } - - /** - * Set the input placeholder - * - * @param string $placeholder - * @return FormService - */ - public function placeholder($placeholder): FormService - { - return $this->_set('placeholder', $placeholder); - } - - /** - * Set custom attributes for an input - * - * @param array $attrs - * @return FormService - */ - public function attrs(array $attrs = []): FormService - { - return $this->_set('attrs', $attrs); - } - - /** - * Disable input states (valid and invalid classes) and error message - * - * @param string $disable - * @return FormService - */ - public function disableValidation(bool $disable = true): FormService - { - return $this->_set('disableValidation', $disable); - } - - /** - * Set custom attributes for a wrapper input - * - * @param array $attrs - * @return FormService - */ - public function wrapperAttrs(array $attrs = []): FormService - { - return $this->_set('wrapperAttrs', $attrs); - } - - /** - * Create radio or checkbox input - * - * @param string $render - * @param string $name - * @param string $value - * @param string $label - * @param mixed $checked - * @return FormService - */ - private function _radioOrCheckbox($render, $name, $label, $value, $checked): FormService - { - if (is_bool($checked)) { - $this->checked($checked); - } - return $this->_set('render', $render)->name($name)->label($label)->value($value); - } - - /** - * Set the size - * - * @param string $size - * @return FormService - */ - private function _set(string $key, $value): FormService - { - $this->_builder->set($key, $value); - return $this; - } -} +_builder = new FormBuilder; + } + + /** + * Magic method to return a class string version + * + * @return string + */ + public function __toString() + { + return $this->_builder->render(); + } + + /** + * Set error bag name + * + * @param string $value + * @return FormService + */ + public function errorBag(string $value = null): FormService + { + return $this->_set('formErrorBag', $value); + } + + /** + * Open the form + * + * @return FormService + */ + public function open(): FormService + { + return $this->_set('render', 'formOpen'); + } + + /** + * Close the form + * + * @return FormService + */ + public function close(): FormService + { + return $this->_set('render', 'formClose'); + } + + /** + * Show all validation errors + * + * @param string $title + * @return FormService + */ + public function errors(string $title = null): FormService + { + return $this->_set('render', 'errors')->_set('errorsHeader', $title); + } + + /** + * Set a prefix id for all inputs + * + * @param string $prefix + * @return FormService + */ + public function idPrefix(string $prefix = ''): FormService + { + return $this->_set('formIdPrefix', $prefix); + } + + /** + * Set multipart attribute for a form + * + * @param bool $multipart + * @return FormService + */ + public function multipart(bool $multipart = true): FormService + { + return $this->_set('formMultipart', $multipart); + } + + /** + * Set a method attribute for the form + * + * @param string $method + * @return FormService + */ + public function method(string $method): FormService + { + return $this->_set('method', $method); + } + + /** + * Set get method for the form attribute + * + * @return FormService + */ + public function get(): FormService + { + return $this->method('get'); + } + + /** + * Set post method for the form attribute + * + * @return FormService + */ + public function post(): FormService + { + return $this->method('post'); + } + + /** + * Set put method for the form attribute + * + * @return FormService + */ + public function put(): FormService + { + return $this->method('put'); + } + + /** + * Set patch method for the form attribute + * + * @return FormService + */ + public function patch(): FormService + { + return $this->method('patch'); + } + + /** + * Set delete method for the form attribute + * + * @return FormService + */ + public function delete(): FormService + { + return $this->method('delete'); + } + + /** + * Fill the form values + * + * @param array|object $data + * @return FormService + */ + public function fill($data): FormService + { + return $this->_set('formData', $data); + } + + /** + * Set locale file for inputs translations + * + * @param string $path + * @return FormService + */ + public function locale(string $path): FormService + { + return $this->_set('formLocale', $path); + } + + /** + * Set autocomplete attribute on form, or on individual input fields + * + * @param string $value + * @return FormService + */ + public function autocomplete($value = true): FormService + { + return $this->_set('autocomplete', $value); + } + + /** + * Set inline form style + * + * @param bool $inline + * @return FormService + */ + public function formInline(bool $inline = true): FormService + { + return $this->_set('formInline', $inline); + } + + /** + * Set url for links and form action + * + * @param string $url + * @return FormService + */ + public function url(string $url = null): FormService + { + return $this->_set('url', url($url ?? '')); + } + + /** + * Set route for links and form action + * + * @param string $route + * @param array|string $params + * @return FormService + */ + public function route(string $route, $params = []): FormService + { + return $this->_set('url', route($route, $params)); + } + + /** + * Open a fieldset + * + * @param string $legend + * @return FormService + */ + public function fieldsetOpen(string $legend = null): FormService + { + return $this->render('fieldsetOpen')->_set('legend', $legend); + } + + /** + * Close a fieldset + * + * @return FormService + */ + public function fieldsetClose(): FormService + { + return $this->render('fieldsetClose'); + } + + /** + * Set a help text + * + * @param string $text + * @return FormService + */ + public function help(string $text): FormService + { + return $this->_set('help', $text); + } + + /** + * Create a file input + * + * @param string $name + * @param string $label + * @return FormService + */ + public function file(string $name = null, string $label = null): FormService + { + return $this->render('input')->type('file')->name($name)->label($label)->custom()->placeholder('Choose file'); + } + + /** + * Create a text input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function text(string $name = null, $label = null, string $default = null): FormService + { + return $this->render('input')->type('text')->name($name)->label($label)->value($default); + } + + /** + * Create a date input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function date(string $name = null, $label = null, string $default = null): FormService + { + return $this->render('input')->type('date')->name($name)->label($label)->value($default); + } + + /** + * Create a time input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function time(string $name = null, $label = null, string $default = null): FormService + { + return $this->render('input')->type('time')->name($name)->label($label)->value($default); + } + + /** + * Create a telephone input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function tel(string $name = null, $label = null, string $default = null): FormService + { + return $this->render('input')->type('tel')->name($name)->label($label)->value($default); + } + + /** + * Create a url input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function urlInput(string $name = null, $label = null, string $default = null): FormService + { + return $this->render('input')->type('url')->name($name)->label($label)->value($default); + } + + /** + * Create a range input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function range(string $name = null, $label = null, string $default = null): FormService + { + return $this->render('input')->type('range')->name($name)->label($label)->value($default)->custom(); + } + + /** + * Set a minimum value for a field + * + * @param string $value + * @return FormService + */ + public function min($value) + { + return $this->_set('min', $value); + } + + /** + * Set a maximum value for a field + * + * @param string $value + * @return FormService + */ + public function max($value) + { + return $this->_set('max', $value); + } + + /** + * Set a append for a field + * + * @param mixed $value + * @return FormService + */ + public function append(string $value, array $attrs = null, bool $style = true): FormService + { + return $this->_set('append', $value)->_set('appendAttrs', $attrs)->_set('appendStyle', $style); + } + + /** + * Set a prepend for a field + * + * @param mixed $value + * @return FormService + */ + public function prepend(string $value, array $attrs = null, bool $style = true): FormService + { + return $this->_set('prepend', $value)->_set('prependAttrs', $attrs)->_set('prependStyle', $style); + } + + /** + * Create a hidden input + * + * @param string $name + * @param string $default + * @return FormService + */ + public function hidden(string $name = null, string $default = null): FormService + { + return $this->render('input')->type('hidden')->name($name)->value($default); + } + + /** + * Create a select input + * + * @param string $name + * @param string $label + * @param array $options + * @param string|array $default + * @return FormService + */ + public function select(string $name = null, string $label = null, $options = [], $default = null): FormService + { + return $this->render('select')->name($name)->label($label)->options($options)->value($default)->custom(); + } + + /** + * Set options for a select field + * + * @param mixed $options + * @param string $valueKey + * @param string $idKey + * @return FormService + */ + public function options($options = [], string $valueKey = null, string $idKey = null): FormService + { + return $this->_set('optionValueKey', $valueKey)->_set('optionIdKey', $idKey)->_set('options', $options); + } + + /** + * Set a multiple select attribute + * + * @param bool $multiple + * @return FormService + */ + public function multiple(bool $status = true): FormService + { + return $this->_set('multiple', $status); + } + + /** + * Create a checkbox input + * + * @param string $name + * @param string $value + * @param string $label + * @param bool $checked + * @return FormService + */ + public function checkbox(string $name = null, string $label = null, string $value = 'on', bool $checked = null): FormService + { + return $this->_radioOrCheckbox('checkbox', $name, $label, $value, $checked); + } + + /** + * Create a radio input + * + * @param string $name + * @param string $value + * @param string $label + * @param bool $checked + * @return FormService + */ + public function radio(string $name = null, string $label = null, string $value = null, bool $checked = null): FormService + { + return $this->_radioOrCheckbox('radio', $name, $label, $value, $checked); + } + + /** + * Create a switch input + * + * @param string $name + * @param string $value + * @param string $label + * @param bool $checked + * @return FormService + */ + public function switch(string $name = null, string $label = null, string $value = null, bool $checked = null): FormService + { + return $this->_radioOrCheckbox('checkbox', $name, $label, $value, $checked)->type('switch'); + } + + /** + * Set inline input style + * @param bool $inline + * @return FormService + */ + public function inline(bool $inline = true): FormService + { + return $this->_set('inline', $inline); + } + + /** + * Create a textarea input + * + * @param string $name + * @param string $label + * @param string $default + * @return FormService + */ + public function textarea(string $name = null, $label = null, string $default = null): FormService + { + return $this->_set('render', 'textarea')->name($name)->label($label)->value($default); + } + + /** + * Set a label + * + * @param string $label + * @param array $attrs + * @return FormService + */ + public function label($label, array $attrs = []): FormService + { + return $this->_set('label', $label)->labelAttrs($attrs); + } + + /** + * Create a button + * + * @param string $value + * @param string $color + * @param null $size + * @return FormService + */ + public function button(string $value = null, $color = 'primary', $size = null): FormService + { + return $this->type('button')->_set('render', 'button')->value($value)->color($color)->size($size); + } + + /** + * Create a button type submit + * + * @param string $value + * @param string $color + * @param null $size + * @return FormService + */ + public function submit(string $value, $color = 'primary', $size = null): FormService + { + return $this->button($value, $color, $size)->type('submit'); + } + + /** + * Create a button type reset + * + * @param string $value + * @param string $color + * @param null $size + * @return FormService + */ + public function reset(string $value, $color = 'primary', $size = null): FormService + { + return $this->button($value, $color, $size)->type('reset'); + } + + /** + * Create a anchor + * + * @param string $value + * @param string $url + * @return FormService + */ + public function anchor(string $value, $url = null, $color = 'primary', $size = null): FormService + { + return $this->_set('render', 'anchor')->value($value)->url($url)->color($color)->size($size); + } + + /** + * Flag a checkbox or a radio input as checked + * + * @param bool $checked + * @return FormService + */ + public function checked(bool $checked = true): FormService + { + return $this->_set('checked', $checked); + } + + /** + * Set optgroup label inside options value + * + * @param bool $optgroup + * @return FormService + */ + public function optgroup(bool $optgroup = true): FormService + { + return $this->_set('optgroup', $optgroup); + } + + /** + * Set a input value + * + * @param string $value + * @return FormService + */ + public function value($value = null): FormService + { + return $this->_set('value', $value); + } + + /** + * Set a input type + * + * @param string $type + * @return FormService + */ + public function type($type): FormService + { + return $this->_set('type', $type); + } + + /** + * Set a render + * + * @param string $render + * @return FormService + */ + public function render(string $render): FormService + { + return $this->_set('render', $render); + } + + /** + * Set a field id + * + * @param string $id + * @return FormService + */ + public function id($id): FormService + { + return $this->_set('id', $id); + } + + /** + * Set a field name + * + * @param string $name + * @return FormService + */ + public function name($name): FormService + { + return $this->_set('name', $name); + } + + /** + * Set the size + * + * @param string $size + * @return FormService + */ + public function size(string $size = null): FormService + { + return $this->_set('size', $size); + } + + /** + * Set the field as bootstrap custom + * + * @param bool $custom + * @return FormService + */ + public function custom(bool $custom = true): FormService + { + return $this->_set('custom', $custom); + } + + /** + * Set the size as lg + * + * @return FormService + */ + public function lg(): FormService + { + return $this->size('lg'); + } + + /** + * Set the size as sm + * + * @return FormService + */ + public function sm(): FormService + { + return $this->size('sm'); + } + + /** + * Set the color + * + * @param string $color + * @return FormService + */ + public function color(string $color = null): FormService + { + return $this->_set('color', $color); + } + + /** + * Set primary color + * + * @return FormService + */ + public function primary(): FormService + { + return $this->color('primary'); + } + + /** + * Set secondary color + * + * @return FormService + */ + public function secondary(): FormService + { + return $this->color('secondary'); + } + + /** + * Set success color + * + * @return FormService + */ + public function success(): FormService + { + return $this->color('success'); + } + + /** + * Set danger color + * + * @return FormService + */ + public function danger(): FormService + { + return $this->color('danger'); + } + + /** + * Set warning color + * + * @return FormService + */ + public function warning(): FormService + { + return $this->color('warning'); + } + + /** + * Set info color + * + * @return FormService + */ + public function info(): FormService + { + return $this->color('info'); + } + + /** + * Set light color + * + * @return FormService + */ + public function light(): FormService + { + return $this->color('light'); + } + + /** + * Set dark color + * + * @return FormService + */ + public function dark(): FormService + { + return $this->color('dark'); + } + + /** + * Set link style + * + * @return FormService + */ + public function link(): FormService + { + return $this->color('link'); + } + + /** + * Set outline style + * + * @param bool $status + * @return FormService + */ + public function outline(bool $status = true): FormService + { + return $this->_set('outline', $status); + } + + /** + * Set block style + * + * @param bool $status + * @return FormService + */ + public function block(bool $status = true): FormService + { + return $this->_set('block', $status); + } + + /** + * Set readonly style + * + * @param bool $status + * @return FormService + */ + public function readonly($status = true): FormService + { + return $this->_set('readonly', $status); + } + + /** + * Set the input disabled status + * + * @param bool $status + * @return FormService + */ + public function disabled($status = true): FormService + { + return $this->_set('disabled', $status); + } + + /** + * Set the input required status + * + * @param bool $status + * @return FormService + */ + public function required($status = true): FormService + { + return $this->_set('required', $status); + } + + /** + * Set the input placeholder + * + * @param string $placeholder + * @return FormService + */ + public function placeholder($placeholder): FormService + { + return $this->_set('placeholder', $placeholder); + } + + /** + * Set custom attributes for an input + * + * @param array $attrs + * @return FormService + */ + public function attrs(array $attrs = []): FormService + { + return $this->_set('attrs', $attrs); + } + + /** + * Set custom attributes for a label input + * + * @param array $attrs + * @return FormService + */ + public function labelAttrs(array $attrs = []): FormService + { + return $this->_set('labelAttrs', $attrs); + } + + /** + * Disable input states (valid and invalid classes) and error message + * + * @param bool $disable + * @return FormService + */ + public function disableValidation(bool $disable = true): FormService + { + return $this->_set('disableValidation', $disable); + } + + /** + * Set custom attributes for a wrapper input + * + * @param array $attrs + * @return FormService + */ + public function wrapperAttrs(array $attrs = []): FormService + { + return $this->_set('wrapperAttrs', $attrs); + } + + /** + * Set custom attributes for a wrapper input group + * + * @param array $attrs + * @return FormService + */ + public function wrapperGroupAttrs(array $attrs = []): FormService + { + return $this->_set('wrapperGroupAttrs', $attrs); + } + + /** + * Set custom attributes for a wrapper append input + * + * @param array $attrs + * @return FormService + */ + public function wrapperAppendAttrs(array $attrs = []): FormService + { + return $this->_set('wrapperAppendAttrs', $attrs); + } + + /** + * Set custom attributes for a wrapper prepend input + * + * @param array $attrs + * @return FormService + */ + public function wrapperPrependAttrs(array $attrs = []): FormService + { + return $this->_set('wrapperPrependAttrs', $attrs); + } + + /** + * Create radio or checkbox input + * + * @param string $render + * @param string $name + * @param string $value + * @param string $label + * @param mixed $checked + * @return FormService + */ + protected function _radioOrCheckbox($render, $name, $label, $value, $checked): FormService + { + if (is_bool($checked)) { + $this->checked($checked); + } + return $this->_set('render', $render)->name($name)->label($label)->value($value)->custom(); + } + + /** + * Set the size + * + * @param string $size + * @return FormService + */ + protected function _set(string $key, $value): FormService + { + $this->_builder->set($key, $value); + return $this; + } +}