$value = function ($value, AbstractField $field) { return $value; } * @method AbstractField|mixed hookValueSerialize($value = null) * * grid|form|detail模式:渲染自定义回调 * > $value = function(AbstractField $field, $item, $index){ return $item->title; } * @method AbstractField|mixed hookRendering($value = null) * * @method AbstractField|mixed isLayoutField($vlaue = null) * @method AbstractField|mixed isCustomField($vlaue = null) * @method AbstractField|mixed gridFixed($vlaue = null) * @method AbstractField|mixed gridEditable($vlaue = null) * * >>>>>> 数据流转换流程 >>>>>> * * grid.request * -> repository->get * -> hookValueUnserialize(function($value, AbstractField $field){return $value;}) * -> unserializeValue($value, AbstractField $field) * -> hookFormatValue(function($value, AbstractField $field){ return $value;}) * -> view->render * * form.add * -> view->render * * form.addRequest * -> prepareInput($value, $dataSubmitted) * -> serializeValue($value, $dataSubmitted) * -> hookValueSerialize(function($value, AbstractField $field){return $value;}) * -> repository->add * * form.formRequest * -> prepareInput($value, $dataSubmitted) * -> serializeValue($value, $dataSubmitted) * -> hookValueSerialize(function($value, AbstractField $field){return $value;}) * -> repository->add * * form.edit * -> repository->editing * -> hookValueUnserialize(function($value, AbstractField $field){return $value;}) * -> unserializeValue($value, AbstractField $field) * -> hookFormatValue(function($value, AbstractField $field){ return $value;}) * -> view->render * * form.editRequest * -> prepareInput($value, $dataSubmitted) * -> serializeValue($value, $dataSubmitted) * -> hookValueSerialize(function($value, AbstractField $field){return $value;}) * -> repository->edit * * detail.show * -> repository->show * -> hookValueUnserialize(function($value, AbstractField $field){return $value;}) * -> unserializeValue($value, AbstractField $field) * -> hookFormatValue(function($value, AbstractField $field){ return $value;}) * -> view->render * * form.deleteRequest * -> repository->deleting * -> repository->delete * */ class AbstractField implements Renderable { use HasFluentAttribute; protected static $css = []; protected static $js = []; private $script = ''; /** @var Form|Grid|Detail $context */ protected $context; private $id; private $name; private $column; protected $label; protected $value = null; protected $fixedValue = null; protected $rules = ''; protected $view = null; protected $variables = []; /** * 当前条目 * grid模式:当前条目 * form模式:edit当前编辑条目 * * @var Model|\stdClass */ private $item; private $fluentAttributes = [ 'listable', 'addable', 'editable', 'showable', 'sortable', 'renderMode', 'defaultValue', 'placeholder', 'help', 'width', 'styleFormField', 'readonly', 'hookFormatValue', 'hookValueUnserialize', 'hookValueSerialize', 'hookRendering', 'isLayoutField', 'isCustomField', 'gridFixed', 'gridEditable', ]; /** * 字段渲染模式,默认为 add,请查看 @see FieldRenderMode * @var string */ protected $listable = true; protected $addable = true; protected $editable = true; protected $showable = true; protected $sortable = false; private $renderMode; private $defaultValue = null; private $placeholder = null; private $help = null; private $styleFormField = null; protected $width = ''; private $readonly = false; /** * 格式化值 * @var \Closure */ private $hookFormatValue; /** * 将DB中的值反序列化 * @var \Closure */ private $hookValueUnserialize; /** * 将值序列化存储在DB中 * @var \Closure */ private $hookValueSerialize; private $hookRendering; /** * 是否为布局类 * @var bool */ protected $isLayoutField = false; /** * 是否为自定义字段(自定义字段不参与Form中的addRequest、editRequest计算) * @var bool */ protected $isCustomField = false; /** * 数据表示模式下浮动布局 * @var null|left|right */ private $gridFixed = null; /** * @var bool 行内编辑 */ private $gridEditable = false; public static function getAssets() { return [ 'css' => static::$css, 'js' => static::$js, ]; } public function __construct($column, $arguments = []) { $this->id = IdUtil::generate('Field'); $this->column = $column; if (isset($arguments[0])) { $this->label = $arguments[0]; } else { $this->label = $column; } $this->setup(); } protected function setup() { } public function postSetup() { } public function context($context = null) { if (null === $context) { return $this->context; } $this->context = $context; return $this->context; } public function rules($rules = null) { if (is_null($rules)) { return $this->rules; } $rules = array_filter(explode('|', "{$this->rules}|$rules")); $this->rules = implode('|', $rules); return $this; } /** * @return $this|string */ public function required() { return $this->rules('required'); } /** * @return $this|string */ public function ruleRegex($regex) { return $this->rules('regex:' . $regex); } /** * @return $this|string */ public function ruleUnique($table, $field = null) { if (null === $field) { $field = $this->column(); } return $this->rules('unique:' . $table . ',' . $field . ',' . CRUDUtil::id()); } public function id() { return $this->id; } public function column() { return $this->column; } private function formatName($column) { if (is_string($column)) { $names = explode('.', $column); if (count($names) == 1) { return $names[0]; } $name = array_shift($names); foreach ($names as $piece) { $name .= "[$piece]"; } return $name; } } public function name($value = null) { if (null === $value) { if (empty($this->name)) { return $this->formatName($this->column); } return $this->name; } $this->name = $value; return $this; } public function label($value = null) { if (null === $value) { return $this->label; } $this->label = $value; return $this; } public function value($value = null) { if (null === $value) { if (null === $this->value) { return $this->defaultValue(); } return $this->value; } $this->value = $value; return $this; } public function fixedValue($fixedValue = null) { if (null === $fixedValue) { return $this->fixedValue; } $this->fixedValue = $fixedValue; return $this; } public function setValue($value) { $this->value = $value; return $this; } /** * @param null $item * @return $this|Model|\stdClass */ public function item($item = null) { if (null === $item) { return $this->item; } $this->item = $item; return $this; } /** * 数据反序列化 * @param $value * @param $model * @return mixed */ public function unserializeValue($value, AbstractField $field) { return $value; } /** * 值序列化 * @param $value * @param $model * @return mixed */ public function serializeValue($value, $model) { return $value; } /** * 转换从view到提交值 * @param mixed $value * @param array $dataSubmitted * @return mixed */ public function prepareInput($value, $dataSubmitted) { return $value; } /** * 填充字段值,data包含当前记录 * @param Arrayable|array $item */ public function fill($item) { if ($this->isLayoutField()) { return; } $this->item = $item; if (is_array($this->column)) { foreach ($this->column as $key => $column) { $value = array_get($item, $column); if ($this->hookValueUnserialize) { $value = call_user_func($this->hookValueUnserialize, $value, $this); } $value = $this->unserializeValue($value, $this); if ($this->hookFormatValue) { $value = call_user_func($this->hookFormatValue, $value, $this); } $this->value[$key] = $value; } return; } if (is_array($item)) { $value = array_get($item, $this->column); } else { $value = isset($item->{$this->column}) ? $item->{$this->column} : null; } if ($this->hookValueUnserialize) { $value = call_user_func($this->hookValueUnserialize, $value, $this); } $value = $this->unserializeValue($value, $this); if ($this->hookFormatValue) { $value = call_user_func($this->hookFormatValue, $value, $this); } $this->value = $value; } /** * Add variables to field view. * * @param array $variables * * @return $this */ protected function addVariables(array $variables = []) { $this->variables = array_merge($this->variables, $variables); return $this; } public function getVariable($key, $default = null) { if (isset($this->variables[$key])) { return $this->variables[$key]; } return $default; } /** * Get validator for this field. * * @param array $input * * @return bool|Validator */ public function getValidator(array $input) { $rules = $attributes = []; if (!$fieldRules = $this->rules()) { return false; } if (is_string($this->column)) { if (!array_has($input, $this->column)) { return false; } $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] = array_get($input, $column); $rules[$column . $key] = $fieldRules; $attributes[$column . $key] = $this->label . "[$column]"; } } return Validator::make($input, $rules, [], $attributes); } protected function variables() { // echo $this->column . " : " . json_encode($this->value()) . "\n"; return array_merge($this->fluentAttributeVariables(), $this->variables, [ 'id' => $this->id, 'name' => $this->name(), 'value' => $this->value(), 'fixedValue' => $this->fixedValue(), 'label' => $this->label, 'column' => $this->column, 'placeholder' => $this->placeholder(), 'rules' => $this->rules, ]); } public function view($mode = '', $name = null) { if (!empty($this->view)) { return $this->view . ($mode ? '-' . $mode : ''); } if (null === $name) { $class = explode('\\', get_called_class()); $name = lcfirst(end($class)); } return 'modstart::core.field.' . $name . ($mode ? '-' . $mode : ''); } public function render() { return $this->renderView($this, $this->item); } public function renderView(AbstractField $field, $item, $index = 0) { try { $column = $field->column(); if ($this->hookRendering instanceof \Closure) { $ret = call_user_func($this->hookRendering, $this, $item, $index); if (null !== $ret) { if ($ret instanceof AutoRenderedFieldValue) { return view('modstart::core.field.autoRenderedField-' . $this->renderMode, [ 'label' => $this->label, 'value' => $ret->getValue(), ])->render(); } return $ret; } } ModStart::script($this->script); switch ($this->renderMode) { case FieldRenderMode::FORM: return view($this->view(), $this->variables()); case FieldRenderMode::DETAIL: if (view()->exists($view = $this->view($this->renderMode))) { return view($view, $this->variables()); } return view($this->view($this->renderMode, 'text'), $this->variables()); case FieldRenderMode::GRID: if (view()->exists($view = $this->view($this->renderMode))) { // echo json_encode($this->variables())."\n"; return View::make($view, array_merge([ 'item' => $item, '_index' => $index, ], $this->variables()))->render(); } if (is_array($item->{$column})) { return join(', ', $item->{$column}); } return htmlspecialchars((string)$item->{$column}); } } catch (\Throwable $e) { return \Exception('Field renderMode error'); } throw new \Exception('Field renderMode error'); } public function __call($method, $arguments) { if ($this->isFluentAttribute($method)) { return $this->fluentAttribute($method, $arguments); } throw new \Exception('AbstractField __call error : ' . $method); } }