html = $html;
$this->form = $form;
$this->config = $config;
}
/**
* Open a form while passing a model and the routes for storing or updating
* the model. This will set the correct route along with the correct
* method.
*
* @param array $options
* @return string
*/
public function open(array $options = [])
{
// Set the HTML5 role.
$options['role'] = 'form';
// Set the class for the form type.
if (!array_key_exists('class', $options)) {
$options['class'] = $this->getType();
}
if (array_key_exists('left_column_class', $options)) {
$this->setLeftColumnClass($options['left_column_class']);
}
if (array_key_exists('left_column_offset_class', $options)) {
$this->setLeftColumnOffsetClass($options['left_column_offset_class']);
}
if (array_key_exists('right_column_class', $options)) {
$this->setRightColumnClass($options['right_column_class']);
}
Arr::forget($options, [
'left_column_class',
'left_column_offset_class',
'right_column_class'
]);
if (array_key_exists('model', $options)) {
return $this->model($options);
}
if (array_key_exists('error_bag', $options)) {
$this->setErrorBag($options['error_bag']);
}
return $this->form->open($options);
}
/**
* Reset and close the form.
*
* @return string
*/
public function close()
{
$this->type = null;
$this->leftColumnClass = $this->rightColumnClass = null;
return $this->form->close();
}
/**
* Open a form configured for model binding.
*
* @param array $options
* @return string
*/
protected function model($options)
{
$model = $options['model'];
if (isset($options['url'])) {
// If we're explicity passed a URL, we'll use that.
Arr::forget($options, ['model', 'update', 'store']);
$options['method'] = isset($options['method']) ? $options['method'] : 'GET';
return $this->form->model($model, $options);
}
// If we're not provided store/update actions then let the form submit to itself.
if (!isset($options['store']) && !isset($options['update'])) {
Arr::forget($options, 'model');
return $this->form->model($model, $options);
}
if (!is_null($options['model']) && $options['model']->exists) {
// If the form is passed a model, we'll use the update route to update
// the model using the PUT method.
$name = is_array($options['update']) ? Arr::first($options['update']) : $options['update'];
$route = Str::contains($name, '@') ? 'action' : 'route';
$options[$route] = array_merge((array) $options['update'], [$options['model']->getRouteKey()]);
$options['method'] = 'PUT';
} else {
// Otherwise, we're storing a brand new model using the POST method.
$name = is_array($options['store']) ? Arr::first($options['store']) : $options['store'];
$route = Str::contains($name, '@') ? 'action' : 'route';
$options[$route] = $options['store'];
$options['method'] = 'POST';
}
// Forget the routes provided to the input.
Arr::forget($options, ['model', 'update', 'store']);
return $this->form->model($model, $options);
}
/**
* Open a vertical (standard) Bootstrap form.
*
* @param array $options
* @return string
*/
public function vertical(array $options = [])
{
$this->setType(Type::VERTICAL);
return $this->open($options);
}
/**
* Open an inline Bootstrap form.
*
* @param array $options
* @return string
*/
public function inline(array $options = [])
{
$this->setType(Type::INLINE);
return $this->open($options);
}
/**
* Open a horizontal Bootstrap form.
*
* @param array $options
* @return string
*/
public function horizontal(array $options = [])
{
$this->setType(Type::HORIZONTAL);
return $this->open($options);
}
/**
* Create a Bootstrap static field.
*
* @param string $name
* @param string $label
* @param string $value
* @param array $options
* @return string
*/
public function staticField($name, $label = null, $value = null, array $options = [])
{
$options = array_merge(['class' => 'form-control-static'], $options);
if (is_array($value) and isset($value['html'])) {
$value = $value['html'];
} else {
$value = e($value);
}
$label = $this->getLabelTitle($label, $name);
$inputElement = '
';
return $this->getFormGroup($name, $label, $wrapperElement);
}
/**
* Wrap the content in Laravel's HTML string class.
*
* @param string $html
* @return \Illuminate\Support\HtmlString
*/
protected function toHtmlString($html)
{
return new HtmlString($html);
}
/**
* Get the label title for a form field, first by using the provided one
* or titleizing the field name.
*
* @param string $label
* @param string $name
* @return mixed
*/
protected function getLabelTitle($label, $name)
{
if ($label === false) {
return null;
}
if (is_null($label) && Lang::has("forms.{$name}")) {
return Lang::get("forms.{$name}");
}
return $label ?: str_replace('_', ' ', Str::title($name));
}
/**
* Get a form group comprised of a form element and errors.
*
* @param string $name
* @param string $element
* @return \Illuminate\Support\HtmlString
*/
protected function getFormGroupWithoutLabel($name, $element)
{
$options = $this->getFormGroupOptions($name);
return $this->toHtmlString('
html->attributes($options) . '>' . $element . '
');
}
/**
* Get a form group comprised of a label, form element and errors.
*
* @param string $name
* @param string $value
* @param string $element
* @return \Illuminate\Support\HtmlString
*/
protected function getFormGroupWithLabel($name, $value, $element)
{
$options = $this->getFormGroupOptions($name);
return $this->toHtmlString('
');
}
/**
* Get a form group with or without a label.
*
* @param string $name
* @param string $label
* @param string $element
* @return string
*/
public function getFormGroup($name = null, $label = null, $wrapperElement)
{
if (is_null($label)) {
return $this->getFormGroupWithoutLabel($name, $wrapperElement);
}
return $this->getFormGroupWithLabel($name, $label, $wrapperElement);
}
/**
* Merge the options provided for a form group with the default options
* required for Bootstrap styling.
*
* @param string $name
* @param array $options
* @return array
*/
protected function getFormGroupOptions($name = null, array $options = [])
{
$class = 'form-group';
if ($name) {
$class .= ' ' . $this->getFieldErrorClass($name);
}
return array_merge(['class' => $class], $options);
}
/**
* Merge the options provided for a field with the default options
* required for Bootstrap styling.
*
* @param array $options
* @param string $name
* @return array
*/
protected function getFieldOptions(array $options = [], $name = null)
{
$options['class'] = trim('form-control ' . $this->getFieldOptionsClass($options));
// If we've been provided the input name and the ID has not been set in the options,
// we'll use the name as the ID to hook it up with the label.
if ($name && ! array_key_exists('id', $options)) {
$options['id'] = $name;
}
return $options;
}
/**
* Returns the class property from the options, or the empty string
*
* @param array $options
* @return string
*/
protected function getFieldOptionsClass(array $options = [])
{
return Arr::get($options, 'class');
}
/**
* Merge the options provided for a label with the default options
* required for Bootstrap styling.
*
* @param array $options
* @return array
*/
protected function getLabelOptions(array $options = [])
{
$class = 'control-label';
if ($this->isHorizontal()) {
$class .= ' ' . $this->getLeftColumnClass();
}
return array_merge(['class' => trim($class)], $options);
}
/**
* Get the form type.
*
* @return string
*/
public function getType()
{
return isset($this->type) ? $this->type : $this->config->get('bootstrap_form.type');
}
/**
* Determine if the form is of a horizontal type.
*
* @return bool
*/
public function isHorizontal()
{
return $this->getType() === Type::HORIZONTAL;
}
/**
* Set the form type.
*
* @param string $type
* @return void
*/
public function setType($type)
{
$this->type = $type;
}
/**
* Get the column class for the left column of a horizontal form.
*
* @return string
*/
public function getLeftColumnClass()
{
return $this->leftColumnClass ?: $this->config->get('bootstrap_form.left_column_class');
}
/**
* Set the column class for the left column of a horizontal form.
*
* @param string $class
* @return void
*/
public function setLeftColumnClass($class)
{
$this->leftColumnClass = $class;
}
/**
* Get the column class for the left column offset of a horizontal form.
*
* @return string
*/
public function getLeftColumnOffsetClass()
{
return $this->leftColumnOffsetClass ?: $this->config->get('bootstrap_form.left_column_offset_class');
}
/**
* Set the column class for the left column offset of a horizontal form.
*
* @param string $class
* @return void
*/
public function setLeftColumnOffsetClass($class)
{
$this->leftColumnOffsetClass = $class;
}
/**
* Get the column class for the right column of a horizontal form.
*
* @return string
*/
public function getRightColumnClass()
{
return $this->rightColumnClass ?: $this->config->get('bootstrap_form.right_column_class');
}
/**
* Set the column class for the right column of a horizontal form.
*
* @param string $class
* @return void
*/
public function setRightColumnClass($class)
{
$this->rightColumnClass = $class;
}
/**
* Get the icon prefix.
*
* @return string
*/
public function getIconPrefix()
{
return $this->iconPrefix ?: $this->config->get('bootstrap_form.icon_prefix');
}
/**
* Get the error class.
*
* @return string
*/
public function getErrorClass()
{
return $this->errorClass ?: $this->config->get('bootstrap_form.error_class');
}
/**
* Get the error bag.
*
* @return string
*/
protected function getErrorBag()
{
return $this->errorBag ?: $this->config->get('bootstrap_form.error_bag');
}
/**
* Set the error bag.
*
* @param string $errorBag
* @return void
*/
protected function setErrorBag($errorBag)
{
$this->errorBag = $errorBag;
}
/**
* Flatten arrayed field names to work with the validator, including removing "[]",
* and converting nested arrays like "foo[bar][baz]" to "foo.bar.baz".
*
* @param string $field
* @return string
*/
public function flattenFieldName($field)
{
return preg_replace_callback("/\[(.*)\\]/U", function ($matches) {
if (!empty($matches[1]) || $matches[1] === '0') {
return "." . $matches[1];
}
}, $field);
}
/**
* Get the MessageBag of errors that is populated by the
* validator.
*
* @return \Illuminate\Support\MessageBag
*/
protected function getErrors()
{
return $this->form->getSessionStore()->get('errors');
}
/**
* Get the first error for a given field, using the provided
* format, defaulting to the normal Bootstrap 3 format.
*
* @param string $field
* @param string $format
* @return mixed
*/
protected function getFieldError($field, $format = ':message')
{
$field = $this->flattenFieldName($field);
if ($this->getErrors()) {
$allErrors = $this->config->get('bootstrap_form.show_all_errors');
if ($this->getErrorBag()) {
$errorBag = $this->getErrors()->{$this->getErrorBag()};
} else {
$errorBag = $this->getErrors();
}
if ($allErrors) {
return implode('', $errorBag->get($field, $format));
}
return $errorBag->first($field, $format);
}
}
/**
* Return the error class if the given field has associated
* errors, defaulting to the normal Bootstrap 3 error class.
*
* @param string $field
* @param string $class
* @return string
*/
protected function getFieldErrorClass($field)
{
return $this->getFieldError($field) ? $this->getErrorClass() : null;
}
/**
* Get the help text for the given field.
*
* @param string $field
* @param array $options
* @return \Illuminate\Support\HtmlString
*/
protected function getHelpText($field, array $options = [])
{
if (array_key_exists('help_text', $options)) {
return $this->toHtmlString('' . e($options['help_text']) . '');
}
return '';
}
}