123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- <?php
- namespace Dcat\Admin\Form;
- use Dcat\Admin\Form;
- use Dcat\Admin\Support\Helper;
- use Dcat\Admin\Widgets\Form as WidgetForm;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Collection;
- class NestedForm extends WidgetForm
- {
- use Form\Concerns\HandleCascadeFields;
- use Form\Concerns\HasRows;
- use Form\Concerns\HasTabs;
- use Form\Concerns\HasLayout;
- const DEFAULT_KEY_NAME = '__LA_KEY__';
- const REMOVE_FLAG_NAME = '_remove_';
- const REMOVE_FLAG_CLASS = 'fom-removed';
- /**
- * @var string
- */
- protected $relationName;
- /**
- * NestedForm key.
- *
- * @var
- */
- protected $key;
- /**
- * Fields in form.
- *
- * @var Collection
- */
- protected $fields;
- /**
- * Original data for this field.
- *
- * @var array
- */
- protected $original = [];
- /**
- * @var Form|WidgetForm
- */
- protected $form;
- /**
- * Create a new NestedForm instance.
- *
- * NestedForm constructor.
- *
- * @param string $relation
- * @param null $key
- */
- public function __construct($relation = null, $key = null)
- {
- $this->relationName = $relation;
- $this->key = $key;
- $this->disableResetButton();
- $this->disableSubmitButton();
- $this->ajax(false);
- $this->useFormTag(false);
- parent::__construct();
- }
- /**
- * Set Form.
- *
- * @param Form|WidgetForm $form
- *
- * @return $this
- */
- public function setForm($form = null)
- {
- $this->form = $form;
- return $this;
- }
- /**
- * Get form.
- *
- * @return Form
- */
- public function form()
- {
- return $this->form;
- }
- public function model()
- {
- return $this->form->model();
- }
- /**
- * Set original values for fields.
- *
- * @param array $data
- * @param string $relatedKeyName
- *
- * @return $this
- */
- public function setOriginal($data, $relatedKeyName)
- {
- if (empty($data)) {
- return $this;
- }
- foreach ($data as $value) {
- if (! isset($value[$relatedKeyName])) {
- continue;
- }
- /*
- * like $this->original[30] = [ id = 30, .....]
- */
- $this->original[$value[$relatedKeyName]] = $value;
- }
- return $this;
- }
- /**
- * Prepare for insert or update.
- *
- * @param array $input
- *
- * @return mixed
- */
- public function prepare($input)
- {
- foreach ($input as $key => $record) {
- if (! array_key_exists(static::REMOVE_FLAG_NAME, $record)) {
- continue;
- }
- $this->setFieldOriginalValue($key);
- $input[$key] = $this->prepareRecord($record);
- }
- return $input;
- }
- /**
- * Get key for current form.
- *
- * @return string
- */
- public function getKey()
- {
- return $this->key;
- }
- /**
- * Set key for current form.
- *
- * @param mixed $key
- *
- * @return $this
- */
- public function setKey($key)
- {
- $this->key = $key;
- return $this;
- }
- /**
- * Set original data for each field.
- *
- * @param string $key
- *
- * @return void
- */
- protected function setFieldOriginalValue($key)
- {
- $values = [];
- if (array_key_exists($key, $this->original)) {
- $values = $this->original[$key];
- }
- $this->fields->each(function (Field $field) use ($values) {
- $field->setOriginal($values);
- });
- }
- /**
- * Do prepare work before store and update.
- *
- * @param array $record
- *
- * @return array
- */
- protected function prepareRecord($record)
- {
- if ($record[static::REMOVE_FLAG_NAME] == 1) {
- return $record;
- }
- $prepared = [];
- /* @var Field $field */
- foreach ($this->fields as $field) {
- $columns = $field->column();
- $value = $this->fetchColumnValue($record, $columns);
- if ($value === false) {
- continue;
- }
- if (method_exists($field, 'prepare')) {
- $value = $field->prepare($value);
- }
- if (($field instanceof Form\Field\Hidden) || ! Helper::equal($field->original(), $value)) {
- if (is_array($columns)) {
- foreach ($columns as $name => $column) {
- Arr::set($prepared, $column, $value[$name]);
- }
- } elseif (is_string($columns)) {
- Arr::set($prepared, $columns, $value);
- }
- }
- }
- $prepared[static::REMOVE_FLAG_NAME] = $record[static::REMOVE_FLAG_NAME];
- return $prepared;
- }
- /**
- * Fetch value in input data by column name.
- *
- * @param array $data
- * @param string|array $columns
- *
- * @return array|mixed
- */
- protected function fetchColumnValue($data, $columns)
- {
- if (is_string($columns)) {
- if (! Arr::has($data, $columns)) {
- return false;
- }
- return Arr::get($data, $columns);
- }
- if (is_array($columns)) {
- $value = [];
- foreach ($columns as $name => $column) {
- if (! Arr::has($data, $column)) {
- continue;
- }
- $value[$name] = Arr::get($data, $column);
- }
- return $value;
- }
- return false;
- }
- /**
- * @param Field $field
- *
- * @return $this
- */
- public function pushField(Field $field)
- {
- $this->fields->push($field);
- if ($this->layout()->hasColumns()) {
- $this->layout()->addField($field);
- }
- if (method_exists($this->form, 'builder')) {
- $this->form->builder()->fields()->push($field);
- $field->attribute(Builder::BUILD_IGNORE, true);
- }
- $field->setNestedFormRelation([
- 'relation' => $this->relationName,
- 'key' => $this->key,
- ]);
- $field::requireAssets();
- $field->width($this->width['field'], $this->width['label']);
- return $this;
- }
- /**
- * Get fields of this form.
- *
- * @return Collection
- */
- public function fields()
- {
- return $this->fields;
- }
- /**
- * Fill data to all fields in form.
- *
- * @param array $data
- *
- * @return $this
- */
- public function fill($data)
- {
- /* @var Field $field */
- foreach ($this->fields() as $field) {
- $field->fill($data);
- }
- return $this;
- }
- /**
- * Set `errorKey` `elementName` `elementClass` for fields inside hasmany fields.
- *
- * @param Field $field
- *
- * @return Field
- */
- protected function formatField(Field $field)
- {
- $column = $field->column();
- $elementName = $elementClass = $errorKey = [];
- $key = $this->key ?: 'new_'.static::DEFAULT_KEY_NAME;
- if (is_array($column)) {
- foreach ($column as $k => $name) {
- $errorKey[$k] = sprintf('%s.%s.%s', $this->relationName, $key, $name);
- $elementName[$k] = sprintf('%s[%s][%s]', $this->formatName(), $key, $name);
- $elementClass[$k] = [$this->formatClass(), $this->formatClass($name)];
- }
- } else {
- $errorKey = sprintf('%s.%s.%s', $this->relationName, $key, $column);
- $elementName = sprintf('%s[%s][%s]', $this->formatName(), $key, $column);
- $elementClass = [$this->formatClass(), $this->formatClass($column)];
- }
- return $field->setErrorKey($errorKey)
- ->setElementName($elementName)
- ->setElementClass($elementClass);
- }
- protected function formatClass($name = null)
- {
- return str_replace('.', '_', $name ?: $this->relationName);
- }
- protected function formatName($name = null)
- {
- return Helper::formatElementName($name ?: $this->relationName);
- }
- protected function resolveField($method, $arguments)
- {
- if ($className = Form::findFieldClass($method)) {
- $column = Arr::get($arguments, 0, '');
- /* @var Field $field */
- $field = new $className($column, array_slice($arguments, 1));
- $field->setForm($this->form);
- $field = $this->formatField($field);
- return $field;
- }
- }
- /**
- * Add nested-form fields dynamically.
- *
- * @param string $method
- * @param array $arguments
- *
- * @return mixed
- */
- public function __call($method, $arguments)
- {
- if ($field = $this->resolveField($method, $arguments)) {
- $this->pushField($field);
- return $field;
- }
- return $this;
- }
- }
|