2, 'field' => 8, ]; /** * If the form horizontal layout. * * @var bool */ protected $horizontal = true; /** * column data format. * * @var \Closure */ protected $customFormat = null; /** * @var bool */ protected $display = true; /** * @var array */ protected $labelClass = []; /** * @var \Closure */ protected $customPrepare; /** * Field constructor. * * @param $column * @param array $arguments */ public function __construct($column, $arguments = []) { $this->column = $column; $this->label = $this->formatLabel($arguments); $this->id = $this->formatId($column); } /** * Get the field element id. * * @return string */ public function getElementId() { return $this->id; } /** * Format the field element id. * * @param string|array $column * * @return string|array */ protected function formatId($column) { if (is_array($column)) { return str_replace('.', '-', $column); } return 'form-field-'.str_replace('.', '-', $column); } /** * Format the label value. * * @param array $arguments * * @return string */ protected function formatLabel($arguments = []) { $column = is_array($this->column) ? current($this->column) : $this->column; $label = isset($arguments[0]) ? $arguments[0] : ucfirst(admin_trans_field($column)); return str_replace(['.', '_'], ' ', $label); } /** * Format the name of the field. * * @param string $column * * @return array|mixed|string */ protected function formatName($column) { if (is_string($column)) { $name = explode('.', $column); if (count($name) == 1) { return $name[0]; } $html = array_shift($name); foreach ($name as $piece) { $html .= "[$piece]"; } return $html; } if (is_array($this->column)) { $names = []; foreach ($this->column as $key => $name) { $names[$key] = $this->formatName($name); } return $names; } return ''; } /** * Set form element name. * * @param string $name * * @return $this * * @author Edwin Hui */ public function setElementName($name) { $this->elementName = $name; return $this; } /** * Fill data to the field. * * @param array $data * * @return void */ final public function fill($data) { $this->data($data); $this->value = $this->formatAttributeFromQuery($data); $this->callCustomFormatter(); } /** * Format attribute. * * @param array $data * @return mixed */ protected function formatAttributeFromQuery($data) { if (is_array($this->column)) { $value = []; foreach ($this->column as $key => $column) { $value[$key] = Arr::get($data, $column); } return $value; } return Arr::get($data, $this->column); } /** * custom format form column data when edit. * * @param \Closure $call * * @return $this */ public function customFormat(\Closure $call) { $this->customFormat = $call; return $this; } /** * Set original value to the field. * * @param array $data * @return void */ final public function setOriginal($data) { $this->original = $this->formatAttributeFromQuery($data); $this->callCustomFormatter('original', new Fluent($data)); } /** * @param string $key * @param Fluent|null $dataremoveField */ protected function callCustomFormatter($key = 'value', Fluent $data = null) { if ($this->customFormat) { $this->{$key} = $this->customFormat ->call( $data ?: $this->data(), $this->{$key}, $this->column, $this ); } } /** * @param Form $form * * @return $this */ public function setForm(Form $form = null) { $this->form = $form; return $this; } /** * @return Fluent */ public function getFormModel() { return $this->form ? $this->form->model() : new Fluent; } /** * Set width for field and label. * * @param int $field * @param int $label * * @return $this */ public function setWidth($field = 8, $label = 2) { $this->width = [ 'label' => $label, 'field' => $field, ]; return $this; } /** * Set the field options. * * @param array $options * * @return $this */ public function options($options = []) { if ($options instanceof Arrayable) { $options = $options->toArray(); } $this->options = array_merge($this->options, $options); return $this; } /** * Set the field option checked. * * @param array $checked * * @return $this */ public function checked($checked = []) { if ($checked instanceof Arrayable) { $checked = $checked->toArray(); } $this->checked = array_merge($this->checked, (array)$checked); return $this; } /** * Get or set rules. * * @param null $rules * @param array $messages * * @return $this */ public function rules($rules = null, $messages = []) { if ($rules instanceof \Closure) { $this->rules = $rules; } if (is_array($rules)) { $thisRuleArr = array_filter(explode('|', $this->rules)); $this->rules = array_merge($thisRuleArr, $rules); } elseif (is_string($rules)) { $rules = array_filter(explode('|', "{$this->rules}|$rules")); $this->rules = implode('|', $rules); } $this->validationMessages = $messages; return $this; } /** * Get field validation rules. * * @return string */ public function getRules() { if ($this->rules instanceof \Closure) { return $this->rules->call($this, $this->form); } return $this->rules; } /** * Remove a specific rule by keyword. * * @param string $rule * * @return void */ public function removeRule($rule) { if (!$this->rules || !is_string($this->rules)) { return; } $pattern = "/{$rule}[^\|]?(\||$)/"; $this->rules = preg_replace($pattern, '', $this->rules, -1); } /** * @param string $rule * * @return bool */ public function hasRule($rule) { if (!$this->rules || !is_string($this->rules)) { return false; } $pattern = "/{$rule}[^\|]?(\||$)/"; return preg_match($pattern, $this->rules); } /** * Set field validator. * * @param callable $validator * * @return $this */ public function validator(callable $validator) { $this->validator = $validator; return $this; } /** * Get key for error message. * * @return string */ public function getErrorKey() { return $this->errorKey ?: $this->column; } /** * Set key for error message. * * @param string $key * * @return $this */ public function setErrorKey($key) { $this->errorKey = $key; return $this; } /** * Set or get value of the field. * * @param null $value * * @return mixed */ public function value($value = null) { if (is_null($value)) { return is_null($this->value) ? $this->getDefault() : $this->value; } $this->value = $value; return $this; } /** * Set or get data. * * @param array $data * * @return $this */ public function data(array $data = null) { if (is_null($data)) { return $this->data ?: ($this->data = new Fluent); } $this->data = new Fluent($data); return $this; } /** * Set default value for field. * * @param $default * * @return $this */ public function default($default) { $this->default = $default; return $this; } /** * Get default value. * * @return mixed */ public function getDefault() { if ($this->default instanceof \Closure) { return call_user_func($this->default, $this->form); } return $this->default; } /** * Set help block for current field. * * @param string $text * @param string $icon * * @return $this */ public function help($text = '', $icon = 'fa-info-circle') { $this->help = compact('text', 'icon'); return $this; } /** * Get column of the field. * * @return string|array */ public function column() { return $this->column; } /** * Get or set label of the field. * * @param null $label * @return $this|string */ public function label($label = null) { if ($label == null) { return $this->label; } if ($label instanceof \Closure) { $label = $label($this->label); } $this->label = $label; return $this; } /** * Get original value of the field. * * @return mixed */ public function original() { return $this->original; } /** * Get validator for this field. * * @param array $input * * @return bool|Validator */ public function getValidator(array $input) { if ($this->validator) { return $this->validator->call($this, $input); } $rules = $attributes = []; if (!$fieldRules = $this->getRules()) { return false; } if (is_string($this->column)) { if (!Arr::has($input, $this->column)) { return false; } $input = $this->sanitizeInput($input, $this->column); $rules[$this->column] = $fieldRules; $attributes[$this->column] = $this->label; } if (is_array($this->column)) { foreach ($this->column as $key => $column) { if (!array_key_exists($column, $input)) { continue; } $input[$column.$key] = Arr::get($input, $column); $rules[$column.$key] = $fieldRules; $attributes[$column.$key] = $this->label."[$column]"; } } return Validator::make($input, $rules, $this->validationMessages, $attributes); } /** * Sanitize input data. * * @param array $input * @param string $column * * @return array */ protected function sanitizeInput($input, $column) { if ($this instanceof Field\MultipleSelect) { $value = Arr::get($input, $column); Arr::set($input, $column, array_filter($value)); } return $input; } /** * Add html attributes to elements. * * @param array|string $attribute * @param mixed $value * * @return $this */ public function attribute($attribute, $value = null) { if (is_array($attribute)) { $this->attributes = array_merge($this->attributes, $attribute); } else { $this->attributes[$attribute] = (string) $value; } return $this; } /** * Specifies a regular expression against which to validate the value of the input. * * @param string $regexp * * @return $this */ public function pattern($regexp) { return $this->attribute('pattern', $regexp); } /** * set the input filed required. * * @param bool $isLabelAsterisked * * @return $this */ public function required($isLabelAsterisked = true) { if ($isLabelAsterisked) { $this->setLabelClass(['asterisk']); } $this->rules('required'); return $this->attribute('required', true); } /** * Set the field automatically get focus. * * @return $this */ public function autofocus() { return $this->attribute('autofocus', true); } /** * Set the field as readonly mode. * * @return $this */ public function readOnly() { return $this->attribute('readonly', true); } /** * Set field as disabled. * * @return $this */ public function disable() { return $this->attribute('disabled', true); } /** * Set field placeholder. * * @param string $placeholder * * @return $this */ public function placeholder($placeholder = '') { $this->placeholder = $placeholder; return $this; } /** * Get placeholder. * * @return string */ public function getPlaceholder() { return $this->placeholder ?: trans('admin.input').' '.$this->label; } /** * Prepare for a field value before update or insert. * * @param mixed $value * @return mixed */ public function prepare($value) { return $value; } /** * @param \Closure $closure * @return $this */ public function customPrepare(\Closure $closure) { $this->customPrepare = $closure; return $this; } /** * Prepare for a field value before update or insert. * * @param mixed $value * @return mixed */ final public function prepareInputValue($value) { $value = $this->prepare($value); if ($handler = $this->customPrepare) { $handler->bindTo($this->data); return $handler($value); } return $value; } /** * Format the field attributes. * * @return string */ protected function formatAttributes() { $html = []; foreach ($this->attributes as $name => $value) { $html[] = $name.'="'.e($value).'"'; } return implode(' ', $html); } /** * @return $this */ public function disableHorizontal() { $this->horizontal = false; return $this; } /** * @return array */ public function getViewElementClasses() { if ($this->horizontal) { return [ 'label' => "col-sm-{$this->width['label']} {$this->getLabelClass()}", 'field' => "col-sm-{$this->width['field']}", 'form-group' => 'form-group ', ]; } return ['label' => $this->getLabelClass(), 'field' => '', 'form-group' => '']; } /** * Set form element class. * * @param string|array $class * * @return $this */ public function setElementClass($class) { $this->elementClass = array_merge($this->elementClass, (array) $class); return $this; } /** * Get element class. * * @return array */ protected function getElementClass() { if (!$this->elementClass) { $name = $this->elementName ?: $this->formatName($this->column); $this->elementClass = (array) str_replace(['[', ']'], '_', $name); } return $this->elementClass; } /** * Get element class string. * * @return mixed */ protected function getElementClassString() { $elementClass = $this->getElementClass(); if (Arr::isAssoc($elementClass)) { $classes = []; foreach ($elementClass as $index => $class) { $classes[$index] = is_array($class) ? implode(' ', $class) : $class; } return $classes; } return implode(' ', $elementClass); } /** * Get element class selector. * * @return string|array */ protected function getElementClassSelector() { $elementClass = $this->getElementClass(); $formId = $this->getFormId(); $formId = $formId ? '#'.$formId : ''; if (Arr::isAssoc($elementClass)) { $classes = []; foreach ($elementClass as $index => $class) { $classes[$index] = $formId . ' .'.(is_array($class) ? implode('.', $class) : $class); } return $classes; } return $formId . ' .'.implode('.', $elementClass); } /** * @return string|null */ protected function getFormId() { return $this->form ? $this->form->getFormId() : null; } /** * Add the element class. * * @param $class * * @return $this */ public function addElementClass($class) { if (is_array($class) || is_string($class)) { $this->elementClass = array_merge($this->elementClass, (array) $class); $this->elementClass = array_unique($this->elementClass); } return $this; } /** * Remove element class. * * @param $class * * @return $this */ public function removeElementClass($class) { $delClass = []; if (is_string($class) || is_array($class)) { $delClass = (array) $class; } foreach ($delClass as $del) { if (($key = array_search($del, $this->elementClass))) { unset($this->elementClass[$key]); } } return $this; } /** * Add variables to field view. * * @param array $variables * * @return $this */ protected function addVariables(array $variables = []) { $this->variables = array_merge($this->variables, $variables); return $this; } /** * @return string */ public function getLabelClass(): string { return implode(' ', $this->labelClass); } /** * @param array $labelClass * * @return $this */ public function setLabelClass(array $labelClass) { $this->labelClass = $labelClass; return $this; } /** * @return string */ public function getElementName() { return $this->elementName ?: $this->formatName($this->column); } /** * Get the view variables of this field. * * @return array */ public function variables() { return array_merge($this->variables, [ 'id' => $this->id, 'name' => $this->getElementName(), 'help' => $this->help, 'class' => $this->getElementClassString(), 'value' => $this->value(), 'label' => $this->label, 'viewClass' => $this->getViewElementClasses(), 'column' => $this->column, 'errorKey' => $this->getErrorKey(), 'attributes' => $this->formatAttributes(), 'placeholder' => $this->getPlaceholder(), 'disabled' => $this->attributes['disabled'] ?? false, 'formId' => $this->getFormId(), ]); } /** * Get view of this field. * * @return string */ public function getView() { return $this->view ?: 'admin::form.'.strtolower(class_basename(static::class)); } /** * Set view of current field. * * @return string */ public function setView($view) { $this->view = $view; return $this; } /** * Get script of current field. * * @return string */ public function getScript() { return $this->script; } /** * Set script of current field. * * @return self */ public function setScript($script) { $this->script = $script; return $this; } /** * To set this field should render or not. * * @return self */ public function setDisplay(bool $display) { $this->display = $display; return $this; } /** * If this field should render. * * @return bool */ protected function shouldRender() { if (!$this->display) { return false; } return true; } /** * Collect assets required by this field. */ public static function collectAssets() { static::$js && Admin::js(static::$js); static::$css && Admin::css(static::$css); } /** * Render this filed. * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string */ public function render() { if (!$this->shouldRender()) { return ''; } Admin::script($this->script); return view($this->getView(), $this->variables()); } /** * @return string */ public function __toString() { return $this->render()->render(); } }