Field.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  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. $value[$key] = $this->getValueFromData($data, $this->normalizeColumn($column));
  288. }
  289. return $value;
  290. }
  291. return $this->getValueFromData($data, null, $this->value);
  292. }
  293. /**
  294. * @param array $data
  295. * @param string $column
  296. * @param mixed $default
  297. *
  298. * @return mixed
  299. */
  300. protected function getValueFromData($data, $column = null, $default = null)
  301. {
  302. $column = $column ?: $this->normalizeColumn();
  303. if (Arr::has($data, $column)) {
  304. return Arr::get($data, $column, $default);
  305. }
  306. return Arr::get($data, Str::snake($column), $default);
  307. }
  308. protected function normalizeColumn(?string $column = null)
  309. {
  310. return str_replace('->', '.', $column ?: $this->column);
  311. }
  312. /**
  313. * custom format form column data when edit.
  314. *
  315. * @param \Closure $call
  316. *
  317. * @return $this
  318. */
  319. public function customFormat(\Closure $call)
  320. {
  321. $this->customFormat = $call;
  322. return $this;
  323. }
  324. /**
  325. * Set original value to the field.
  326. *
  327. * @param array $data
  328. *
  329. * @return void
  330. */
  331. final public function setOriginal($data)
  332. {
  333. $data = Helper::array($data);
  334. $this->original = $this->formatFieldData($data);
  335. $this->callCustomFormatter('original', new Fluent($data));
  336. }
  337. /**
  338. * @param string $key
  339. * @param Fluent|null $dataremoveField
  340. */
  341. protected function callCustomFormatter($key = 'value', Fluent $data = null)
  342. {
  343. if ($this->customFormat) {
  344. $this->{$key} = $this->customFormat
  345. ->call(
  346. $data ?: $this->data(),
  347. $this->{$key},
  348. $this->column,
  349. $this
  350. );
  351. }
  352. }
  353. /**
  354. * @param Form|WidgetForm $form
  355. *
  356. * @return $this
  357. */
  358. public function setForm($form = null)
  359. {
  360. $this->form = $form;
  361. return $this;
  362. }
  363. /**
  364. * @param WidgetForm $form
  365. *
  366. * @return $this
  367. */
  368. public function setParent($form = null)
  369. {
  370. $this->parent = $form;
  371. return $this;
  372. }
  373. /**
  374. * @return Fluent|\Illuminate\Database\Eloquent\Model
  375. */
  376. public function values()
  377. {
  378. return $this->form ? $this->form->model() : new Fluent();
  379. }
  380. /**
  381. * Set width for field and label.
  382. *
  383. * @param int $field
  384. * @param int $label
  385. *
  386. * @return $this
  387. */
  388. public function width($field = 8, $label = 2)
  389. {
  390. $this->width = [
  391. 'label' => $label,
  392. 'field' => $field,
  393. ];
  394. return $this;
  395. }
  396. /**
  397. * Set the field options.
  398. *
  399. * @param array $options
  400. *
  401. * @return $this
  402. */
  403. public function options($options = [])
  404. {
  405. if ($options instanceof \Closure) {
  406. $options = $options->call($this->data(), $this->value());
  407. }
  408. $this->options = array_merge($this->options, Helper::array($options));
  409. return $this;
  410. }
  411. /**
  412. * @param array $options
  413. *
  414. * @return $this
  415. */
  416. public function replaceOptions($options)
  417. {
  418. if ($options instanceof \Closure) {
  419. $options = $options->call($this->data(), $this->value());
  420. }
  421. $this->options = $options;
  422. return $this;
  423. }
  424. /**
  425. * @param array|Arrayable $options
  426. *
  427. * @return $this
  428. */
  429. public function mergeOptions($options)
  430. {
  431. return $this->options($options);
  432. }
  433. /**
  434. * Set the field option checked.
  435. *
  436. * @param array $checked
  437. *
  438. * @return $this
  439. */
  440. public function checked($checked = [])
  441. {
  442. if ($checked instanceof Arrayable) {
  443. $checked = $checked->toArray();
  444. }
  445. $this->checked = array_merge($this->checked, (array) $checked);
  446. return $this;
  447. }
  448. /**
  449. * Set key for error message.
  450. *
  451. * @param string|array $key
  452. *
  453. * @return $this
  454. */
  455. public function setErrorKey($key)
  456. {
  457. $this->errorKey = $key;
  458. return $this;
  459. }
  460. /**
  461. * Get key for error message.
  462. *
  463. * @return string
  464. */
  465. public function getErrorKey()
  466. {
  467. return $this->errorKey ?: $this->column;
  468. }
  469. /**
  470. * Set or get value of the field.
  471. *
  472. * @param null $value
  473. *
  474. * @return mixed|$this
  475. */
  476. public function value($value = null)
  477. {
  478. if (is_null($value)) {
  479. if (
  480. $this->value === null
  481. || (is_array($this->value) && empty($this->value))
  482. ) {
  483. return $this->default();
  484. }
  485. return $this->value;
  486. }
  487. $this->value = value($value);
  488. return $this;
  489. }
  490. /**
  491. * Set or get data.
  492. *
  493. * @param array $data
  494. *
  495. * @return $this|Fluent
  496. */
  497. public function data(array $data = null)
  498. {
  499. if (is_null($data)) {
  500. if (! $this->data || is_array($this->data)) {
  501. $this->data = new Fluent((array) $this->data);
  502. }
  503. return $this->data;
  504. }
  505. $this->data = new Fluent($data);
  506. return $this;
  507. }
  508. /**
  509. * Get or set default value for field.
  510. *
  511. * @param mixed $default
  512. * @param bool $edit
  513. *
  514. * @return $this|mixed
  515. */
  516. public function default($default = null, bool $edit = false)
  517. {
  518. if ($default === null) {
  519. if (
  520. $this->form
  521. && method_exists($this->form, 'isCreating')
  522. && ! $this->form->isCreating()
  523. && ! $this->allowDefaultValueInEditPage
  524. ) {
  525. return;
  526. }
  527. if ($this->default instanceof \Closure) {
  528. $this->default->bindTo($this->data());
  529. return call_user_func($this->default, $this->form);
  530. }
  531. return $this->default;
  532. }
  533. $this->default = value($default);
  534. $this->allowDefaultValueInEditPage = $edit;
  535. return $this;
  536. }
  537. /**
  538. * Set help block for current field.
  539. *
  540. * @param string $text
  541. * @param string $icon
  542. *
  543. * @return $this
  544. */
  545. public function help($text = '', $icon = 'feather icon-help-circle')
  546. {
  547. $this->help = compact('text', 'icon');
  548. return $this;
  549. }
  550. /**
  551. * Get column of the field.
  552. *
  553. * @return string|array
  554. */
  555. public function column()
  556. {
  557. return $this->column;
  558. }
  559. /**
  560. * Get or set label of the field.
  561. *
  562. * @param null $label
  563. *
  564. * @return $this|string
  565. */
  566. public function label($label = null)
  567. {
  568. if ($label == null) {
  569. return $this->label;
  570. }
  571. if ($label instanceof \Closure) {
  572. $label = $label($this->label);
  573. }
  574. $this->label = $label;
  575. return $this;
  576. }
  577. /**
  578. * Get original value of the field.
  579. *
  580. * @return mixed
  581. */
  582. public function original()
  583. {
  584. return $this->original;
  585. }
  586. /**
  587. * Sanitize input data.
  588. *
  589. * @param array $input
  590. * @param string $column
  591. *
  592. * @return array
  593. */
  594. protected function sanitizeInput($input, $column)
  595. {
  596. if ($this instanceof Field\MultipleSelect) {
  597. $value = Arr::get($input, $column);
  598. Arr::set($input, $column, array_filter($value));
  599. }
  600. return $input;
  601. }
  602. /**
  603. * Add html attributes to elements.
  604. *
  605. * @param array|string $attribute
  606. * @param mixed $value
  607. *
  608. * @return $this
  609. */
  610. public function attribute($attribute, $value = null)
  611. {
  612. if (is_array($attribute)) {
  613. $this->attributes = array_merge($this->attributes, $attribute);
  614. } else {
  615. $this->attributes[$attribute] = (string) $value;
  616. }
  617. return $this;
  618. }
  619. /**
  620. * @param string $key
  621. *
  622. * @return bool
  623. */
  624. public function hasAttribute(string $key)
  625. {
  626. return array_key_exists($key, $this->attributes);
  627. }
  628. /**
  629. * @param string $key
  630. *
  631. * @return mixed|null
  632. */
  633. public function getAttribute(string $key)
  634. {
  635. return $this->attributes[$key] ?? null;
  636. }
  637. /**
  638. * Specifies a regular expression against which to validate the value of the input.
  639. *
  640. * @param string $error
  641. * @param string $regexp
  642. *
  643. * @return $this
  644. */
  645. public function pattern($regexp, $error = null)
  646. {
  647. if ($error) {
  648. $this->attribute('data-pattern-error', $error);
  649. }
  650. return $this->attribute('pattern', $regexp);
  651. }
  652. /**
  653. * set the input filed required.
  654. *
  655. * @param bool $isLabelAsterisked
  656. *
  657. * @return $this
  658. */
  659. public function required($isLabelAsterisked = true)
  660. {
  661. if ($isLabelAsterisked) {
  662. $this->setLabelClass(['asterisk']);
  663. }
  664. $this->rules('required');
  665. return $this->attribute('required', true);
  666. }
  667. /**
  668. * Set the field automatically get focus.
  669. *
  670. * @param bool $value
  671. *
  672. * @return $this
  673. */
  674. public function autofocus(bool $value = true)
  675. {
  676. return $this->attribute('autofocus', $value);
  677. }
  678. /**
  679. * Set the field as readonly mode.
  680. *
  681. * @param bool $value
  682. *
  683. * @return $this
  684. */
  685. public function readOnly(bool $value = true)
  686. {
  687. if (! $value) {
  688. unset($this->attributes['readonly']);
  689. return $this;
  690. }
  691. return $this->attribute('readonly', $value);
  692. }
  693. /**
  694. * Set field as disabled.
  695. *
  696. * @param bool $value
  697. *
  698. * @return $this
  699. */
  700. public function disable(bool $value = true)
  701. {
  702. if (! $value) {
  703. unset($this->attributes['disabled']);
  704. return $this;
  705. }
  706. return $this->attribute('disabled', $value);
  707. }
  708. /**
  709. * Get or set field placeholder.
  710. *
  711. * @param string $placeholder
  712. *
  713. * @return $this|string
  714. */
  715. public function placeholder($placeholder = null)
  716. {
  717. if ($placeholder === null) {
  718. return $this->placeholder ?: $this->defaultPlaceholder();
  719. }
  720. $this->placeholder = $placeholder;
  721. return $this;
  722. }
  723. /**
  724. * @return string
  725. */
  726. protected function defaultPlaceholder()
  727. {
  728. return trans('admin.input').' '.$this->label;
  729. }
  730. /**
  731. * @param mixed $value
  732. *
  733. * @return mixed
  734. */
  735. protected function prepareInputValue($value)
  736. {
  737. return $value;
  738. }
  739. /**
  740. * @param \Closure $closure
  741. *
  742. * @return $this
  743. */
  744. public function saving(\Closure $closure)
  745. {
  746. $this->savingCallbacks[] = $closure;
  747. return $this;
  748. }
  749. /**
  750. * Prepare for a field value before update or insert.
  751. *
  752. * @param mixed $value
  753. *
  754. * @return mixed
  755. */
  756. final public function prepare($value)
  757. {
  758. $value = $this->prepareInputValue($value);
  759. if ($this->savingCallbacks) {
  760. foreach ($this->savingCallbacks as $callback) {
  761. $value = $callback->call($this->data(), $value);
  762. }
  763. }
  764. return $value;
  765. }
  766. /**
  767. * Format the field attributes.
  768. *
  769. * @return string
  770. */
  771. protected function formatAttributes()
  772. {
  773. $html = [];
  774. foreach ($this->attributes as $name => $value) {
  775. $html[] = $name.'="'.e($value).'"';
  776. }
  777. return implode(' ', $html);
  778. }
  779. /**
  780. * @param bool $value
  781. *
  782. * @return $this
  783. */
  784. public function horizontal(bool $value = true)
  785. {
  786. $this->horizontal = $value;
  787. return $this;
  788. }
  789. /**
  790. * @return array
  791. */
  792. public function getViewElementClasses()
  793. {
  794. if ($this->horizontal) {
  795. return [
  796. 'label' => "col-md-{$this->width['label']} {$this->getLabelClass()}",
  797. 'field' => "col-md-{$this->width['field']} {$this->getFieldClass()}",
  798. 'form-group' => "form-group row {$this->getFormGroupClass()}",
  799. ];
  800. }
  801. return [
  802. 'label' => $this->getLabelClass(),
  803. 'field' => $this->getFieldClass(),
  804. 'form-group' => $this->getFormGroupClass(),
  805. ];
  806. }
  807. /**
  808. * Set element class.
  809. *
  810. * @param string|array $class
  811. *
  812. * @return $this
  813. */
  814. public function setElementClass($class)
  815. {
  816. $this->elementClass = array_merge($this->elementClass, (array) $this->normalizeElementClass($class));
  817. return $this;
  818. }
  819. /**
  820. * Get element class.
  821. *
  822. * @return array
  823. */
  824. public function getElementClass()
  825. {
  826. if (! $this->elementClass) {
  827. $this->elementClass = $this->getDefaultElementClass();
  828. }
  829. return $this->elementClass;
  830. }
  831. /**
  832. * @return array
  833. */
  834. protected function getDefaultElementClass()
  835. {
  836. return array_merge($this->normalizeElementClass((array) $this->getElementName()), [static::NORMAL_CLASS]);
  837. }
  838. /**
  839. * @param string|array $class
  840. *
  841. * @return array|string
  842. */
  843. public function normalizeElementClass($class)
  844. {
  845. if (is_array($class)) {
  846. return array_map([$this, 'normalizeElementClass'], $class);
  847. }
  848. return static::FIELD_CLASS_PREFIX.str_replace(['[', ']', '->', '.'], '_', $class);
  849. }
  850. /**
  851. * Get element class selector.
  852. *
  853. * @return string|array
  854. */
  855. public function getElementClassSelector()
  856. {
  857. $elementClass = $this->getElementClass();
  858. $formId = $this->getFormElementId();
  859. $formId = $formId ? '#'.$formId : '';
  860. if (Arr::isAssoc($elementClass)) {
  861. $classes = [];
  862. foreach ($elementClass as $index => $class) {
  863. $classes[$index] = $formId.' .'.(is_array($class) ? implode('.', $class) : $class);
  864. }
  865. return $classes;
  866. }
  867. return $formId.' .'.implode('.', $elementClass);
  868. }
  869. /**
  870. * Get element class string.
  871. *
  872. * @return mixed
  873. */
  874. public function getElementClassString()
  875. {
  876. $elementClass = $this->getElementClass();
  877. if (Arr::isAssoc($elementClass)) {
  878. $classes = [];
  879. foreach ($elementClass as $index => $class) {
  880. $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
  881. }
  882. return $classes;
  883. }
  884. return implode(' ', $elementClass);
  885. }
  886. /**
  887. * @return $this
  888. */
  889. public function hideInDialog()
  890. {
  891. if (
  892. $this->form instanceof Form
  893. && $this->form->inDialog()
  894. ) {
  895. $this->display(false);
  896. }
  897. return $this;
  898. }
  899. /**
  900. * @return string|null
  901. */
  902. protected function getFormElementId()
  903. {
  904. return $this->form ? $this->form->getElementId() : null;
  905. }
  906. /**
  907. * Add the element class.
  908. *
  909. * @param $class
  910. *
  911. * @return $this
  912. */
  913. public function addElementClass($class)
  914. {
  915. $this->elementClass = array_unique(
  916. array_merge($this->elementClass, (array) $class)
  917. );
  918. return $this;
  919. }
  920. /**
  921. * Remove element class.
  922. *
  923. * @param $class
  924. *
  925. * @return $this
  926. */
  927. public function removeElementClass($class)
  928. {
  929. Helper::deleteByValue($this->elementClass, $class);
  930. return $this;
  931. }
  932. /**
  933. * @param array|string $labelClass
  934. * @param bool $append
  935. *
  936. * @return $this|string
  937. */
  938. public function setLabelClass($labelClass, bool $append = true)
  939. {
  940. $this->labelClass = $append
  941. ? array_unique(array_merge($this->labelClass, (array) $labelClass))
  942. : (array) $labelClass;
  943. return $this;
  944. }
  945. /**
  946. * @return string
  947. */
  948. public function getLabelClass()
  949. {
  950. return implode(' ', $this->labelClass);
  951. }
  952. /**
  953. * @param mixed $value
  954. * @param callable $callback
  955. *
  956. * @return $this|mixed
  957. */
  958. public function when($value, $callback)
  959. {
  960. if ($value) {
  961. return $callback($this, $value) ?: $this;
  962. }
  963. return $this;
  964. }
  965. /**
  966. * @param string|array $class
  967. * @param bool $append
  968. *
  969. * @return $this
  970. */
  971. public function setFormGroupClass($class, bool $append = true)
  972. {
  973. $this->formGroupClass = $append
  974. ? array_unique(array_merge($this->formGroupClass, (array) $class))
  975. : (array) $class;
  976. return $this;
  977. }
  978. /**
  979. * @return string
  980. */
  981. public function getFormGroupClass()
  982. {
  983. return implode(' ', $this->formGroupClass);
  984. }
  985. /**
  986. * @param string|array $class
  987. * @param bool $append
  988. *
  989. * @return $this
  990. */
  991. public function setFieldClass($class, bool $append = true)
  992. {
  993. $this->fieldClass = $append
  994. ? array_unique(array_merge($this->fieldClass, (array) $class))
  995. : (array) $class;
  996. return $this;
  997. }
  998. public function getFieldClass()
  999. {
  1000. return implode(' ', $this->fieldClass);
  1001. }
  1002. /**
  1003. * Get the view variables of this field.
  1004. *
  1005. * @return array
  1006. */
  1007. public function defaultVariables()
  1008. {
  1009. return [
  1010. 'name' => $this->getElementName(),
  1011. 'help' => $this->help,
  1012. 'class' => $this->getElementClassString(),
  1013. 'value' => $this->value(),
  1014. 'label' => $this->label,
  1015. 'viewClass' => $this->getViewElementClasses(),
  1016. 'column' => $this->column,
  1017. 'errorKey' => $this->getErrorKey(),
  1018. 'attributes' => $this->formatAttributes(),
  1019. 'placeholder' => $this->placeholder(),
  1020. 'disabled' => $this->attributes['disabled'] ?? false,
  1021. 'formId' => $this->getFormElementId(),
  1022. 'selector' => $this->getElementClassSelector(),
  1023. 'options' => $this->options,
  1024. ];
  1025. }
  1026. protected function isCreating()
  1027. {
  1028. return request()->isMethod('POST');
  1029. }
  1030. protected function isEditing()
  1031. {
  1032. return request()->isMethod('PUT');
  1033. }
  1034. /**
  1035. * Get view of this field.
  1036. *
  1037. * @return string
  1038. */
  1039. public function view()
  1040. {
  1041. return $this->view ?: 'admin::form.'.strtolower(class_basename(static::class));
  1042. }
  1043. /**
  1044. * Set view of current field.
  1045. *
  1046. * @return string
  1047. */
  1048. public function setView($view)
  1049. {
  1050. $this->view = $view;
  1051. return $this;
  1052. }
  1053. /**
  1054. * Get script of current field.
  1055. *
  1056. * @return string
  1057. */
  1058. public function getScript()
  1059. {
  1060. return $this->script;
  1061. }
  1062. /**
  1063. * Set script of current field.
  1064. *
  1065. * @return self
  1066. */
  1067. public function script($script)
  1068. {
  1069. $this->script = $script;
  1070. return $this;
  1071. }
  1072. /**
  1073. * To set this field should render or not.
  1074. *
  1075. * @return self
  1076. */
  1077. public function display(bool $display)
  1078. {
  1079. $this->display = $display;
  1080. return $this;
  1081. }
  1082. /**
  1083. * 设置默认属性.
  1084. *
  1085. * @param string $attribute
  1086. * @param mixed $value
  1087. *
  1088. * @return $this
  1089. */
  1090. public function defaultAttribute(string $attribute, $value)
  1091. {
  1092. if (! array_key_exists($attribute, $this->attributes)) {
  1093. $this->attribute($attribute, $value);
  1094. }
  1095. return $this;
  1096. }
  1097. /**
  1098. * If this field should render.
  1099. *
  1100. * @return bool
  1101. */
  1102. protected function shouldRender()
  1103. {
  1104. return $this->display;
  1105. }
  1106. /**
  1107. * 保存数据为json格式.
  1108. *
  1109. * @param int $option
  1110. *
  1111. * @return $this
  1112. */
  1113. public function saveAsJson($option = 0)
  1114. {
  1115. return $this->saving(function ($value) use ($option) {
  1116. if ($value === null || is_scalar($value)) {
  1117. return $value;
  1118. }
  1119. return json_encode($value, $option);
  1120. });
  1121. }
  1122. /**
  1123. * 保存数据为字符串格式.
  1124. *
  1125. * @return $this
  1126. */
  1127. public function saveAsString()
  1128. {
  1129. return $this->saving(function ($value) {
  1130. if (is_object($value) || is_array($value)) {
  1131. return json_encode($value);
  1132. }
  1133. return (string) $value;
  1134. });
  1135. }
  1136. /**
  1137. * Collect assets required by this field.
  1138. */
  1139. public static function requireAssets()
  1140. {
  1141. static::$js && Admin::js(static::$js);
  1142. static::$css && Admin::css(static::$css);
  1143. }
  1144. /**
  1145. * 设置默认class.
  1146. */
  1147. protected function setDefaultClass()
  1148. {
  1149. if (is_string($class = $this->getElementClassString())) {
  1150. $this->defaultAttribute('class', $class);
  1151. }
  1152. }
  1153. /**
  1154. * Render this filed.
  1155. *
  1156. * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
  1157. */
  1158. public function render()
  1159. {
  1160. if (! $this->shouldRender()) {
  1161. return '';
  1162. }
  1163. $this->setDefaultClass();
  1164. $this->callComposing();
  1165. $this->withScript();
  1166. return Admin::view($this->view(), $this->variables());
  1167. }
  1168. protected function withScript()
  1169. {
  1170. if ($this->script) {
  1171. Admin::script($this->script);
  1172. }
  1173. }
  1174. /**
  1175. * @return string
  1176. */
  1177. public function __toString()
  1178. {
  1179. $view = $this->render();
  1180. return $view instanceof Renderable ? $view->render() : (string) $view;
  1181. }
  1182. }