Field.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375
  1. <?php
  2. namespace Dcat\Admin\Form;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Form;
  5. use Dcat\Admin\Support\Helper;
  6. use Dcat\Admin\Traits\HasBuilderEvents;
  7. use Dcat\Admin\Traits\HasVariables;
  8. use Dcat\Admin\Widgets\Form as WidgetForm;
  9. use Illuminate\Contracts\Support\Arrayable;
  10. use Illuminate\Contracts\Support\Renderable;
  11. use Illuminate\Support\Arr;
  12. use Illuminate\Support\Fluent;
  13. use Illuminate\Support\Str;
  14. use Illuminate\Support\Traits\Macroable;
  15. /**
  16. * Class Field.
  17. */
  18. class Field implements Renderable
  19. {
  20. use Macroable;
  21. use Form\Concerns\HasFieldValidator;
  22. use HasBuilderEvents;
  23. use HasVariables;
  24. const FILE_DELETE_FLAG = '_file_del_';
  25. const FIELD_CLASS_PREFIX = 'field_';
  26. const BUILD_IGNORE = 'build-ignore';
  27. const NORMAL_CLASS = '_normal_';
  28. /**
  29. * Element value.
  30. *
  31. * @var mixed
  32. */
  33. protected $value;
  34. /**
  35. * Data of all original columns of value.
  36. *
  37. * @var mixed
  38. */
  39. protected $data;
  40. /**
  41. * Field original value.
  42. *
  43. * @var mixed
  44. */
  45. protected $original;
  46. /**
  47. * Field default value.
  48. *
  49. * @var mixed
  50. */
  51. protected $default;
  52. /**
  53. * @var bool
  54. */
  55. protected $allowDefaultValueInEditPage = false;
  56. /**
  57. * Element label.
  58. *
  59. * @var string
  60. */
  61. protected $label = '';
  62. /**
  63. * Column name.
  64. *
  65. * @var string|array
  66. */
  67. protected $column = '';
  68. /**
  69. * Form element name.
  70. *
  71. * @var string|array
  72. */
  73. protected $elementName = [];
  74. /**
  75. * Form element classes.
  76. *
  77. * @var array
  78. */
  79. protected $elementClass = [];
  80. /**
  81. * Options for specify elements.
  82. *
  83. * @var array
  84. */
  85. protected $options = [];
  86. /**
  87. * Checked for specify elements.
  88. *
  89. * @var array
  90. */
  91. protected $checked = [];
  92. /**
  93. * Css required by this field.
  94. *
  95. * @var array
  96. */
  97. protected static $css = [];
  98. /**
  99. * Js required by this field.
  100. *
  101. * @var array
  102. */
  103. protected static $js = [];
  104. /**
  105. * Script for field.
  106. *
  107. * @var string
  108. */
  109. protected $script = '';
  110. /**
  111. * Element attributes.
  112. *
  113. * @var array
  114. */
  115. protected $attributes = [];
  116. /**
  117. * Parent form.
  118. *
  119. * @var Form|WidgetForm
  120. */
  121. protected $form;
  122. /**
  123. * @var WidgetForm
  124. */
  125. protected $parent;
  126. /**
  127. * View for field to render.
  128. *
  129. * @var string
  130. */
  131. protected $view = '';
  132. /**
  133. * Help block.
  134. *
  135. * @var array
  136. */
  137. protected $help = [];
  138. /**
  139. * Key for errors.
  140. *
  141. * @var string|array
  142. */
  143. protected $errorKey;
  144. /**
  145. * Placeholder for this field.
  146. *
  147. * @var string|array
  148. */
  149. protected $placeholder;
  150. /**
  151. * Width for label and field.
  152. *
  153. * @var array
  154. */
  155. protected $width = [
  156. 'label' => 2,
  157. 'field' => 8,
  158. ];
  159. /**
  160. * If the form horizontal layout.
  161. *
  162. * @var bool
  163. */
  164. protected $horizontal = true;
  165. /**
  166. * column data format.
  167. *
  168. * @var \Closure
  169. */
  170. protected $customFormat = null;
  171. /**
  172. * @var bool
  173. */
  174. protected $display = true;
  175. /**
  176. * @var array
  177. */
  178. protected $labelClass = ['text-capitalize'];
  179. /**
  180. * @var array
  181. */
  182. protected $fieldClass = [];
  183. /**
  184. * @var array
  185. */
  186. protected $formGroupClass = ['form-field'];
  187. /**
  188. * @var \Closure[]
  189. */
  190. protected $savingCallbacks = [];
  191. /**
  192. * Field constructor.
  193. *
  194. * @param string|array $column
  195. * @param array $arguments
  196. */
  197. public function __construct($column, $arguments = [])
  198. {
  199. $this->column = $column;
  200. $this->label = $this->formatLabel($arguments);
  201. $this->callResolving();
  202. }
  203. /**
  204. * @param array $options
  205. *
  206. * @return $this
  207. */
  208. public function setRelation(array $options = [])
  209. {
  210. return $this;
  211. }
  212. /**
  213. * Format the label value.
  214. *
  215. * @param array $arguments
  216. *
  217. * @return string
  218. */
  219. protected function formatLabel($arguments = [])
  220. {
  221. if (isset($arguments[0])) {
  222. return $arguments[0];
  223. }
  224. $column = is_array($this->column) ? current($this->column) : $this->column;
  225. return str_replace('_', ' ', admin_trans_field($column));
  226. }
  227. /**
  228. * Format the name of the field.
  229. *
  230. * @param string $column
  231. *
  232. * @return array|mixed|string
  233. */
  234. protected function formatName($column)
  235. {
  236. return Helper::formatElementName($column);
  237. }
  238. /**
  239. * Set form element name.
  240. *
  241. * @param string|array $name
  242. *
  243. * @return $this
  244. *
  245. * @author Edwin Hui
  246. */
  247. public function setElementName($name)
  248. {
  249. $this->elementName = $name;
  250. return $this;
  251. }
  252. /**
  253. * Get form element name.
  254. *
  255. * @return array|mixed|string
  256. */
  257. public function getElementName()
  258. {
  259. return $this->elementName ?: $this->formatName($this->column);
  260. }
  261. /**
  262. * Fill data to the field.
  263. *
  264. * @param array $data
  265. *
  266. * @return void
  267. */
  268. final public function fill($data)
  269. {
  270. $data = Helper::array($data);
  271. $this->data($data);
  272. $this->value = $this->formatFieldData($data);
  273. $this->callCustomFormatter();
  274. }
  275. /**
  276. * Format field data.
  277. *
  278. * @param array $data
  279. *
  280. * @return mixed
  281. */
  282. protected function formatFieldData($data)
  283. {
  284. if (is_array($this->column)) {
  285. $value = [];
  286. foreach ($this->column as $key => $column) {
  287. $column = $this->normalizeColumn($column);
  288. if (Arr::has($data, $column)) {
  289. $value[$key] = Arr::get($data, $column);
  290. } else {
  291. $value[$key] = Arr::get($data, Str::snake($column));
  292. }
  293. }
  294. return $value;
  295. }
  296. return Arr::get($data, $this->normalizeColumn(), $this->value);
  297. }
  298. protected function normalizeColumn(?string $column = null)
  299. {
  300. return str_replace('->', '.', $column ?: $this->column);
  301. }
  302. /**
  303. * custom format form column data when edit.
  304. *
  305. * @param \Closure $call
  306. *
  307. * @return $this
  308. */
  309. public function customFormat(\Closure $call)
  310. {
  311. $this->customFormat = $call;
  312. return $this;
  313. }
  314. /**
  315. * Set original value to the field.
  316. *
  317. * @param array $data
  318. *
  319. * @return void
  320. */
  321. final public function setOriginal($data)
  322. {
  323. $data = Helper::array($data);
  324. $this->original = $this->formatFieldData($data);
  325. $this->callCustomFormatter('original', new Fluent($data));
  326. }
  327. /**
  328. * @param string $key
  329. * @param Fluent|null $dataremoveField
  330. */
  331. protected function callCustomFormatter($key = 'value', Fluent $data = null)
  332. {
  333. if ($this->customFormat) {
  334. $this->{$key} = $this->customFormat
  335. ->call(
  336. $data ?: $this->data(),
  337. $this->{$key},
  338. $this->column,
  339. $this
  340. );
  341. }
  342. }
  343. /**
  344. * @param Form|WidgetForm $form
  345. *
  346. * @return $this
  347. */
  348. public function setForm($form = null)
  349. {
  350. $this->form = $form;
  351. return $this;
  352. }
  353. /**
  354. * @param WidgetForm $form
  355. *
  356. * @return $this
  357. */
  358. public function setParent($form = null)
  359. {
  360. $this->parent = $form;
  361. return $this;
  362. }
  363. /**
  364. * @return Fluent|\Illuminate\Database\Eloquent\Model
  365. */
  366. public function values()
  367. {
  368. return $this->form ? $this->form->model() : new Fluent();
  369. }
  370. /**
  371. * Set width for field and label.
  372. *
  373. * @param int $field
  374. * @param int $label
  375. *
  376. * @return $this
  377. */
  378. public function width($field = 8, $label = 2)
  379. {
  380. $this->width = [
  381. 'label' => $label,
  382. 'field' => $field,
  383. ];
  384. return $this;
  385. }
  386. /**
  387. * Set the field options.
  388. *
  389. * @param array $options
  390. *
  391. * @return $this
  392. */
  393. public function options($options = [])
  394. {
  395. if ($options instanceof \Closure) {
  396. $options = $options->call($this->data(), $this->value());
  397. }
  398. $this->options = array_merge($this->options, Helper::array($options));
  399. return $this;
  400. }
  401. /**
  402. * @param array $options
  403. *
  404. * @return $this
  405. */
  406. public function replaceOptions($options)
  407. {
  408. if ($options instanceof \Closure) {
  409. $options = $options->call($this->data(), $this->value());
  410. }
  411. $this->options = $options;
  412. return $this;
  413. }
  414. /**
  415. * @param array|Arrayable $options
  416. *
  417. * @return $this
  418. */
  419. public function mergeOptions($options)
  420. {
  421. return $this->options($options);
  422. }
  423. /**
  424. * Set the field option checked.
  425. *
  426. * @param array $checked
  427. *
  428. * @return $this
  429. */
  430. public function checked($checked = [])
  431. {
  432. if ($checked instanceof Arrayable) {
  433. $checked = $checked->toArray();
  434. }
  435. $this->checked = array_merge($this->checked, (array) $checked);
  436. return $this;
  437. }
  438. /**
  439. * Set key for error message.
  440. *
  441. * @param string|array $key
  442. *
  443. * @return $this
  444. */
  445. public function setErrorKey($key)
  446. {
  447. $this->errorKey = $key;
  448. return $this;
  449. }
  450. /**
  451. * Get key for error message.
  452. *
  453. * @return string
  454. */
  455. public function getErrorKey()
  456. {
  457. return $this->errorKey ?: $this->column;
  458. }
  459. /**
  460. * Set or get value of the field.
  461. *
  462. * @param null $value
  463. *
  464. * @return mixed|$this
  465. */
  466. public function value($value = null)
  467. {
  468. if (is_null($value)) {
  469. if (
  470. $this->value === null
  471. || (is_array($this->value) && empty($this->value))
  472. ) {
  473. return $this->default();
  474. }
  475. return $this->value;
  476. }
  477. $this->value = value($value);
  478. return $this;
  479. }
  480. /**
  481. * Set or get data.
  482. *
  483. * @param array $data
  484. *
  485. * @return $this|Fluent
  486. */
  487. public function data(array $data = null)
  488. {
  489. if (is_null($data)) {
  490. if (! $this->data || is_array($this->data)) {
  491. $this->data = new Fluent((array) $this->data);
  492. }
  493. return $this->data;
  494. }
  495. $this->data = new Fluent($data);
  496. return $this;
  497. }
  498. /**
  499. * Get or set default value for field.
  500. *
  501. * @param mixed $default
  502. * @param bool $edit
  503. *
  504. * @return $this|mixed
  505. */
  506. public function default($default = null, bool $edit = false)
  507. {
  508. if ($default === null) {
  509. if (
  510. $this->form
  511. && method_exists($this->form, 'isCreating')
  512. && ! $this->form->isCreating()
  513. && ! $this->allowDefaultValueInEditPage
  514. ) {
  515. return;
  516. }
  517. if ($this->default instanceof \Closure) {
  518. $this->default->bindTo($this->data());
  519. return call_user_func($this->default, $this->form);
  520. }
  521. return $this->default;
  522. }
  523. $this->default = value($default);
  524. $this->allowDefaultValueInEditPage = $edit;
  525. return $this;
  526. }
  527. /**
  528. * Set help block for current field.
  529. *
  530. * @param string $text
  531. * @param string $icon
  532. *
  533. * @return $this
  534. */
  535. public function help($text = '', $icon = 'feather icon-help-circle')
  536. {
  537. $this->help = compact('text', 'icon');
  538. return $this;
  539. }
  540. /**
  541. * Get column of the field.
  542. *
  543. * @return string|array
  544. */
  545. public function column()
  546. {
  547. return $this->column;
  548. }
  549. /**
  550. * Get or set label of the field.
  551. *
  552. * @param null $label
  553. *
  554. * @return $this|string
  555. */
  556. public function label($label = null)
  557. {
  558. if ($label == null) {
  559. return $this->label;
  560. }
  561. if ($label instanceof \Closure) {
  562. $label = $label($this->label);
  563. }
  564. $this->label = $label;
  565. return $this;
  566. }
  567. /**
  568. * Get original value of the field.
  569. *
  570. * @return mixed
  571. */
  572. public function original()
  573. {
  574. return $this->original;
  575. }
  576. /**
  577. * Sanitize input data.
  578. *
  579. * @param array $input
  580. * @param string $column
  581. *
  582. * @return array
  583. */
  584. protected function sanitizeInput($input, $column)
  585. {
  586. if ($this instanceof Field\MultipleSelect) {
  587. $value = Arr::get($input, $column);
  588. Arr::set($input, $column, array_filter($value));
  589. }
  590. return $input;
  591. }
  592. /**
  593. * Add html attributes to elements.
  594. *
  595. * @param array|string $attribute
  596. * @param mixed $value
  597. *
  598. * @return $this
  599. */
  600. public function attribute($attribute, $value = null)
  601. {
  602. if (is_array($attribute)) {
  603. $this->attributes = array_merge($this->attributes, $attribute);
  604. } else {
  605. $this->attributes[$attribute] = (string) $value;
  606. }
  607. return $this;
  608. }
  609. /**
  610. * @param string $key
  611. *
  612. * @return bool
  613. */
  614. public function hasAttribute(string $key)
  615. {
  616. return array_key_exists($key, $this->attributes);
  617. }
  618. /**
  619. * @param string $key
  620. *
  621. * @return mixed|null
  622. */
  623. public function getAttribute(string $key)
  624. {
  625. return $this->attributes[$key] ?? null;
  626. }
  627. /**
  628. * Specifies a regular expression against which to validate the value of the input.
  629. *
  630. * @param string $error
  631. * @param string $regexp
  632. *
  633. * @return $this
  634. */
  635. public function pattern($regexp, $error = null)
  636. {
  637. if ($error) {
  638. $this->attribute('data-pattern-error', $error);
  639. }
  640. return $this->attribute('pattern', $regexp);
  641. }
  642. /**
  643. * set the input filed required.
  644. *
  645. * @param bool $isLabelAsterisked
  646. *
  647. * @return $this
  648. */
  649. public function required($isLabelAsterisked = true)
  650. {
  651. if ($isLabelAsterisked) {
  652. $this->setLabelClass(['asterisk']);
  653. }
  654. $this->rules('required');
  655. return $this->attribute('required', true);
  656. }
  657. /**
  658. * Set the field automatically get focus.
  659. *
  660. * @param bool $value
  661. *
  662. * @return $this
  663. */
  664. public function autofocus(bool $value = true)
  665. {
  666. return $this->attribute('autofocus', $value);
  667. }
  668. /**
  669. * Set the field as readonly mode.
  670. *
  671. * @param bool $value
  672. *
  673. * @return $this
  674. */
  675. public function readOnly(bool $value = true)
  676. {
  677. if (! $value) {
  678. unset($this->attributes['readonly']);
  679. return $this;
  680. }
  681. return $this->attribute('readonly', $value);
  682. }
  683. /**
  684. * Set field as disabled.
  685. *
  686. * @param bool $value
  687. *
  688. * @return $this
  689. */
  690. public function disable(bool $value = true)
  691. {
  692. if (! $value) {
  693. unset($this->attributes['disabled']);
  694. return $this;
  695. }
  696. return $this->attribute('disabled', $value);
  697. }
  698. /**
  699. * Get or set field placeholder.
  700. *
  701. * @param string $placeholder
  702. *
  703. * @return $this|string
  704. */
  705. public function placeholder($placeholder = null)
  706. {
  707. if ($placeholder === null) {
  708. return $this->placeholder ?: $this->defaultPlaceholder();
  709. }
  710. $this->placeholder = $placeholder;
  711. return $this;
  712. }
  713. /**
  714. * @return string
  715. */
  716. protected function defaultPlaceholder()
  717. {
  718. return trans('admin.input').' '.$this->label;
  719. }
  720. /**
  721. * @param mixed $value
  722. *
  723. * @return mixed
  724. */
  725. protected function prepareInputValue($value)
  726. {
  727. return $value;
  728. }
  729. /**
  730. * @param \Closure $closure
  731. *
  732. * @return $this
  733. */
  734. public function saving(\Closure $closure)
  735. {
  736. $this->savingCallbacks[] = $closure;
  737. return $this;
  738. }
  739. /**
  740. * Prepare for a field value before update or insert.
  741. *
  742. * @param mixed $value
  743. *
  744. * @return mixed
  745. */
  746. final public function prepare($value)
  747. {
  748. $value = $this->prepareInputValue($value);
  749. if ($this->savingCallbacks) {
  750. foreach ($this->savingCallbacks as $callback) {
  751. $value = $callback->call($this->data(), $value);
  752. }
  753. }
  754. return $value;
  755. }
  756. /**
  757. * Format the field attributes.
  758. *
  759. * @return string
  760. */
  761. protected function formatAttributes()
  762. {
  763. $html = [];
  764. foreach ($this->attributes as $name => $value) {
  765. $html[] = $name.'="'.e($value).'"';
  766. }
  767. return implode(' ', $html);
  768. }
  769. /**
  770. * @param bool $value
  771. *
  772. * @return $this
  773. */
  774. public function horizontal(bool $value = true)
  775. {
  776. $this->horizontal = $value;
  777. return $this;
  778. }
  779. /**
  780. * @return array
  781. */
  782. public function getViewElementClasses()
  783. {
  784. if ($this->horizontal) {
  785. return [
  786. 'label' => "col-md-{$this->width['label']} {$this->getLabelClass()}",
  787. 'field' => "col-md-{$this->width['field']} {$this->getFieldClass()}",
  788. 'form-group' => "form-group row {$this->getFormGroupClass()}",
  789. ];
  790. }
  791. return [
  792. 'label' => $this->getLabelClass(),
  793. 'field' => $this->getFieldClass(),
  794. 'form-group' => $this->getFormGroupClass(),
  795. ];
  796. }
  797. /**
  798. * Set element class.
  799. *
  800. * @param string|array $class
  801. *
  802. * @return $this
  803. */
  804. public function setElementClass($class)
  805. {
  806. $this->elementClass = array_merge($this->elementClass, (array) $this->normalizeElementClass($class));
  807. return $this;
  808. }
  809. /**
  810. * Get element class.
  811. *
  812. * @return array
  813. */
  814. public function getElementClass()
  815. {
  816. if (! $this->elementClass) {
  817. $this->elementClass = $this->getDefaultElementClass();
  818. }
  819. return $this->elementClass;
  820. }
  821. /**
  822. * @return array
  823. */
  824. protected function getDefaultElementClass()
  825. {
  826. return array_merge($this->normalizeElementClass((array) $this->getElementName()), [static::NORMAL_CLASS]);
  827. }
  828. /**
  829. * @param string|array $class
  830. *
  831. * @return array|string
  832. */
  833. public function normalizeElementClass($class)
  834. {
  835. if (is_array($class)) {
  836. return array_map([$this, 'normalizeElementClass'], $class);
  837. }
  838. return static::FIELD_CLASS_PREFIX.str_replace(['[', ']', '->', '.'], '_', $class);
  839. }
  840. /**
  841. * Get element class selector.
  842. *
  843. * @return string|array
  844. */
  845. public function getElementClassSelector()
  846. {
  847. $elementClass = $this->getElementClass();
  848. $formId = $this->getFormElementId();
  849. $formId = $formId ? '#'.$formId : '';
  850. if (Arr::isAssoc($elementClass)) {
  851. $classes = [];
  852. foreach ($elementClass as $index => $class) {
  853. $classes[$index] = $formId.' .'.(is_array($class) ? implode('.', $class) : $class);
  854. }
  855. return $classes;
  856. }
  857. return $formId.' .'.implode('.', $elementClass);
  858. }
  859. /**
  860. * Get element class string.
  861. *
  862. * @return mixed
  863. */
  864. public function getElementClassString()
  865. {
  866. $elementClass = $this->getElementClass();
  867. if (Arr::isAssoc($elementClass)) {
  868. $classes = [];
  869. foreach ($elementClass as $index => $class) {
  870. $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
  871. }
  872. return $classes;
  873. }
  874. return implode(' ', $elementClass);
  875. }
  876. /**
  877. * @return $this
  878. */
  879. public function hideInDialog()
  880. {
  881. if (
  882. $this->form instanceof Form
  883. && $this->form->inDialog()
  884. ) {
  885. $this->display(false);
  886. }
  887. return $this;
  888. }
  889. /**
  890. * @return string|null
  891. */
  892. protected function getFormElementId()
  893. {
  894. return $this->form ? $this->form->getElementId() : null;
  895. }
  896. /**
  897. * Add the element class.
  898. *
  899. * @param $class
  900. *
  901. * @return $this
  902. */
  903. public function addElementClass($class)
  904. {
  905. $this->elementClass = array_unique(
  906. array_merge($this->elementClass, (array) $class)
  907. );
  908. return $this;
  909. }
  910. /**
  911. * Remove element class.
  912. *
  913. * @param $class
  914. *
  915. * @return $this
  916. */
  917. public function removeElementClass($class)
  918. {
  919. Helper::deleteByValue($this->elementClass, $class);
  920. return $this;
  921. }
  922. /**
  923. * @param array|string $labelClass
  924. * @param bool $append
  925. *
  926. * @return $this|string
  927. */
  928. public function setLabelClass($labelClass, bool $append = true)
  929. {
  930. $this->labelClass = $append
  931. ? array_unique(array_merge($this->labelClass, (array) $labelClass))
  932. : (array) $labelClass;
  933. return $this;
  934. }
  935. /**
  936. * @return string
  937. */
  938. public function getLabelClass()
  939. {
  940. return implode(' ', $this->labelClass);
  941. }
  942. /**
  943. * @param mixed $value
  944. * @param callable $callback
  945. *
  946. * @return $this|mixed
  947. */
  948. public function when($value, $callback)
  949. {
  950. if ($value) {
  951. return $callback($this, $value) ?: $this;
  952. }
  953. return $this;
  954. }
  955. /**
  956. * @param string|array $class
  957. * @param bool $append
  958. *
  959. * @return $this
  960. */
  961. public function setFormGroupClass($class, bool $append = true)
  962. {
  963. $this->formGroupClass = $append
  964. ? array_unique(array_merge($this->formGroupClass, (array) $class))
  965. : (array) $class;
  966. return $this;
  967. }
  968. /**
  969. * @return string
  970. */
  971. public function getFormGroupClass()
  972. {
  973. return implode(' ', $this->formGroupClass);
  974. }
  975. /**
  976. * @param string|array $class
  977. * @param bool $append
  978. *
  979. * @return $this
  980. */
  981. public function setFieldClass($class, bool $append = true)
  982. {
  983. $this->fieldClass = $append
  984. ? array_unique(array_merge($this->fieldClass, (array) $class))
  985. : (array) $class;
  986. return $this;
  987. }
  988. public function getFieldClass()
  989. {
  990. return implode(' ', $this->fieldClass);
  991. }
  992. /**
  993. * Get the view variables of this field.
  994. *
  995. * @return array
  996. */
  997. public function defaultVariables()
  998. {
  999. return [
  1000. 'name' => $this->getElementName(),
  1001. 'help' => $this->help,
  1002. 'class' => $this->getElementClassString(),
  1003. 'value' => $this->value(),
  1004. 'label' => $this->label,
  1005. 'viewClass' => $this->getViewElementClasses(),
  1006. 'column' => $this->column,
  1007. 'errorKey' => $this->getErrorKey(),
  1008. 'attributes' => $this->formatAttributes(),
  1009. 'placeholder' => $this->placeholder(),
  1010. 'disabled' => $this->attributes['disabled'] ?? false,
  1011. 'formId' => $this->getFormElementId(),
  1012. 'selector' => $this->getElementClassSelector(),
  1013. 'options' => $this->options,
  1014. ];
  1015. }
  1016. protected function isCreating()
  1017. {
  1018. return request()->isMethod('POST');
  1019. }
  1020. protected function isEditing()
  1021. {
  1022. return request()->isMethod('PUT');
  1023. }
  1024. /**
  1025. * Get view of this field.
  1026. *
  1027. * @return string
  1028. */
  1029. public function view()
  1030. {
  1031. return $this->view ?: 'admin::form.'.strtolower(class_basename(static::class));
  1032. }
  1033. /**
  1034. * Set view of current field.
  1035. *
  1036. * @return string
  1037. */
  1038. public function setView($view)
  1039. {
  1040. $this->view = $view;
  1041. return $this;
  1042. }
  1043. /**
  1044. * Get script of current field.
  1045. *
  1046. * @return string
  1047. */
  1048. public function getScript()
  1049. {
  1050. return $this->script;
  1051. }
  1052. /**
  1053. * Set script of current field.
  1054. *
  1055. * @return self
  1056. */
  1057. public function script($script)
  1058. {
  1059. $this->script = $script;
  1060. return $this;
  1061. }
  1062. /**
  1063. * To set this field should render or not.
  1064. *
  1065. * @return self
  1066. */
  1067. public function display(bool $display)
  1068. {
  1069. $this->display = $display;
  1070. return $this;
  1071. }
  1072. /**
  1073. * 设置默认属性.
  1074. *
  1075. * @param string $attribute
  1076. * @param mixed $value
  1077. *
  1078. * @return $this
  1079. */
  1080. public function defaultAttribute(string $attribute, $value)
  1081. {
  1082. if (! array_key_exists($attribute, $this->attributes)) {
  1083. $this->attribute($attribute, $value);
  1084. }
  1085. return $this;
  1086. }
  1087. /**
  1088. * If this field should render.
  1089. *
  1090. * @return bool
  1091. */
  1092. protected function shouldRender()
  1093. {
  1094. return $this->display;
  1095. }
  1096. /**
  1097. * 保存数据为json格式.
  1098. *
  1099. * @param int $option
  1100. *
  1101. * @return $this
  1102. */
  1103. public function saveAsJson($option = 0)
  1104. {
  1105. return $this->saving(function ($value) use ($option) {
  1106. if ($value === null || is_scalar($value)) {
  1107. return $value;
  1108. }
  1109. return json_encode($value, $option);
  1110. });
  1111. }
  1112. /**
  1113. * 保存数据为字符串格式.
  1114. *
  1115. * @return $this
  1116. */
  1117. public function saveAsString()
  1118. {
  1119. return $this->saving(function ($value) {
  1120. if (is_object($value) || is_array($value)) {
  1121. return json_encode($value);
  1122. }
  1123. return (string) $value;
  1124. });
  1125. }
  1126. /**
  1127. * Collect assets required by this field.
  1128. */
  1129. public static function requireAssets()
  1130. {
  1131. static::$js && Admin::js(static::$js);
  1132. static::$css && Admin::css(static::$css);
  1133. }
  1134. /**
  1135. * 设置默认class.
  1136. */
  1137. protected function setDefaultClass()
  1138. {
  1139. if (is_string($class = $this->getElementClassString())) {
  1140. $this->defaultAttribute('class', $class);
  1141. }
  1142. }
  1143. /**
  1144. * Render this filed.
  1145. *
  1146. * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
  1147. */
  1148. public function render()
  1149. {
  1150. if (! $this->shouldRender()) {
  1151. return '';
  1152. }
  1153. $this->setDefaultClass();
  1154. $this->callComposing();
  1155. $this->withScript();
  1156. return Admin::view($this->view(), $this->variables());
  1157. }
  1158. protected function withScript()
  1159. {
  1160. if ($this->script) {
  1161. Admin::script($this->script);
  1162. }
  1163. }
  1164. /**
  1165. * @return string
  1166. */
  1167. public function __toString()
  1168. {
  1169. $view = $this->render();
  1170. return $view instanceof Renderable ? $view->render() : (string) $view;
  1171. }
  1172. }