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 = '';
- }
-
- 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 = '';
- if ($errorsHeader) {
- $output .= '' . $this->getText($errorsHeader) . ' ';
- }
- foreach ($errors as $error) {
- $output .= '' . $error . ' ';
- }
- return $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 .= '' . $label . ' ';
- }
-
- $attributes = $this->getInputAttributes();
- $attrs = $this->buildHtmlAttrs($attributes);
- return $this->wrapperInput('' . $optionsList . ' ');
- }
-
- 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 '' . $value . ' ';
- }
-
- 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 '' . $this->getText($label) . ' ';
- }
-
- 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 = '';
+ }
+
+ 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 = '';
+ if ($errorsHeader) {
+ $output .= '' . $this->getText($errorsHeader) . ' ';
+ }
+ foreach ($errors as $error) {
+ $output .= '' . $error . ' ';
+ }
+ return $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 = '' . $placeholder . ' ' . $optionsList;
+ }
+
+ $attributes = $this->getInputAttributes();
+ $attrs = $this->buildHtmlAttrs($attributes);
+ return $this->wrapperInput('' . $optionsList . ' ');
+ }
+
+ 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 '' . $value . ' ';
+ }
+
+ 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 .= '' : ' disabled hidden>') . $label . ' ';
+ }
+ }
+ 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 '' . $this->getText($label) . ' ';
+ }
+
+ 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 '';
+ } 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;
+ }
+}