FormBuilder.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // |
  4. // +----------------------------------------------------------------------
  5. // |
  6. // +----------------------------------------------------------------------
  7. // |
  8. // +----------------------------------------------------------------------
  9. // |
  10. // +----------------------------------------------------------------------
  11. // +----------------------------------------------------------------------
  12. // | 表单生成类 https://github.com/LaravelCollective/html
  13. // +----------------------------------------------------------------------
  14. namespace form;
  15. use think\helper\Arr;
  16. class FormBuilder
  17. {
  18. /**
  19. * 我们创建的标签名称数组
  20. *
  21. * @var array
  22. */
  23. protected $labels = [];
  24. /**
  25. * 输入类型
  26. *
  27. * @var null
  28. */
  29. protected $type = null;
  30. /**
  31. * 默认情况下不填充value的输入类型
  32. *
  33. * @var array
  34. */
  35. protected $skipValueTypes = ['file', 'password', 'checkbox', 'radio'];
  36. /**
  37. * 创建一个表单标签元素。
  38. *
  39. * @param $name
  40. * @param null $value
  41. * @param array $options
  42. * @param bool $escape_html
  43. *
  44. * @return string
  45. */
  46. public function label($name, $value = null, $options = [], $escape_html = true)
  47. {
  48. $this->labels[] = $name;
  49. $options = $this->attributes($options);
  50. $value = $this->formatLabel($name, $value);
  51. if ($escape_html) {
  52. $value = $this->entities($value);
  53. }
  54. return '<label for="' . $name . '"' . $options . '>' . $value . '</label>';
  55. }
  56. /**
  57. * 创建一个表单输入字段
  58. *
  59. * @param $type
  60. * @param $name
  61. * @param null $value
  62. * @param array $options
  63. *
  64. * @return string
  65. */
  66. public function input($type, $name, $value = null, $options = [])
  67. {
  68. $this->type = $type;
  69. if (!isset($options['name'])) {
  70. $options['name'] = $name;
  71. }
  72. //我们将得到给定字段的适当值。我们将寻找
  73. //会话中的值查找旧输入数据中的值,然后我们将查找
  74. //在模型实例中(如果已设置)。否则我们只会使用空的
  75. $id = $this->getIdAttribute($name, $options);
  76. if (!in_array($type, $this->skipValueTypes)) {
  77. $value = $this->getValueAttribute($name, $value);
  78. $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'layui-input') !== false ? '' : ' layui-input') : 'layui-input';
  79. }
  80. //一旦我们有了类型、值和ID,我们就可以将它们合并到
  81. //属性数组,以便将它们转换为HTML属性格式
  82. //创建HTML元素时。然后,我们将返回整个输入。
  83. $merge = compact('type', 'value', 'id');
  84. $options = array_merge($options, $merge);
  85. return '<input' . $this->attributes($options) . '>';
  86. }
  87. /**
  88. * 创建一个文本输入字段
  89. *
  90. * @param string $name
  91. * @param null $value
  92. * @param array $options
  93. *
  94. * @return string
  95. */
  96. public function text($name, $value = null, $options = [])
  97. {
  98. return $this->input('text', $name, $value, $options);
  99. }
  100. /**
  101. * 创建一个密码输入字段
  102. *
  103. * @param string $name
  104. * @param array $options
  105. *
  106. * @return string
  107. */
  108. public function password(string $name, array $options = [])
  109. {
  110. return $this->input('password', $name, '', $options);
  111. }
  112. /**
  113. * 创建一个范围输入选择器
  114. *
  115. * @param string $name
  116. * @param null $value
  117. * @param array $options
  118. *
  119. * @return string
  120. */
  121. public function range($name, $value = null, $options = [])
  122. {
  123. return $this->input('range', $name, $value, $options);
  124. }
  125. /**
  126. * 创建一个隐藏的输入字段
  127. *
  128. * @param string $name
  129. * @param null $value
  130. * @param array $options
  131. *
  132. * @return string
  133. */
  134. public function hidden($name, $value = null, $options = [])
  135. {
  136. return $this->input('hidden', $name, $value, $options);
  137. }
  138. /**
  139. * 创建一个电子邮件输入字段
  140. *
  141. * @param string $name
  142. * @param null $value
  143. * @param array $options
  144. *
  145. * @return string
  146. */
  147. public function email($name, $value = null, $options = [])
  148. {
  149. return $this->input('email', $name, $value, $options);
  150. }
  151. /**
  152. * 创建一个tel输入字段
  153. *
  154. * @param string $name
  155. * @param null $value
  156. * @param array $options
  157. *
  158. * @return string
  159. */
  160. public function tel($name, $value = null, $options = [])
  161. {
  162. return $this->input('tel', $name, $value, $options);
  163. }
  164. /**
  165. * 创建一个数字输入字段
  166. *
  167. * @param string $name
  168. * @param null $value
  169. * @param array $options
  170. *
  171. * @return string
  172. */
  173. public function number($name, $value = null, $options = [])
  174. {
  175. return $this->input('number', $name, $value, $options);
  176. }
  177. /**
  178. * 创建一个url输入字段
  179. *
  180. * @param string $name
  181. * @param null $value
  182. * @param array $options
  183. *
  184. * @return string
  185. */
  186. public function url($name, $value = null, $options = [])
  187. {
  188. return $this->input('url', $name, $value, $options);
  189. }
  190. /**
  191. * 创建一个textarea输入字段
  192. *
  193. * @param string $name
  194. * @param null $value
  195. * @param array $options
  196. *
  197. * @return string
  198. */
  199. public function textarea($name, $value = null, $options = [])
  200. {
  201. $this->type = 'textarea';
  202. if (!isset($options['name'])) {
  203. $options['name'] = $name;
  204. }
  205. //接下来,我们将查找rows和cols属性,因为每个属性都是
  206. //在textarea元素定义上。如果他们不在场,我们就
  207. //为开发人员的这些属性假设一些合理的默认值。
  208. $options = $this->setTextAreaSize($options);
  209. $options['id'] = $this->getIdAttribute($name, $options);
  210. $value = (string) $this->getValueAttribute($name, $value);
  211. unset($options['size']);
  212. //接下来,我们将把属性转换成字符串形式。我们还移除了
  213. //“大小”属性,因为它只是一条通往行和列的捷径
  214. //元素。然后我们将为我们创建最终的textarea元素HTML。
  215. $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'layui-textarea') !== false ? '' : ' layui-textarea') : 'layui-textarea';
  216. $options = $this->attributes($options);
  217. return '<textarea' . $options . '>' . $value . '</textarea>';
  218. }
  219. /**
  220. * 创建一个选择框字段
  221. *
  222. * @param $name
  223. * @param array $list
  224. * @param null $selected
  225. * @param array $selectAttributes
  226. * @param array $optionsAttributes
  227. * @param array $optgroupsAttributes
  228. *
  229. * @return string
  230. */
  231. public function select(
  232. $name,
  233. $list = [],
  234. $selected = null,
  235. array $selectAttributes = [],
  236. array $optionsAttributes = [],
  237. array $optgroupsAttributes = []
  238. ) {
  239. $this->type = 'select';
  240. //在构建选择框时,“值”属性实际上就是所选的
  241. //因此,我们将在检查模型或会话时使用该值
  242. //应该提供一种方便的方法来重新填充post上的表格。
  243. $selected = $this->getValueAttribute($name, $selected);
  244. $selectAttributes['id'] = $this->getIdAttribute($name, $selectAttributes);
  245. if (!isset($selectAttributes['name'])) {
  246. $selectAttributes['name'] = $name;
  247. }
  248. //我们将简单地遍历这些选项,并为每个选项构建一个HTML值
  249. //直到我们有一个HTML声明数组。然后我们会加入他们
  250. //所有这些都整合到一个可以放在表单上的HTML元素中。
  251. $html = [];
  252. if (isset($selectAttributes['placeholder'])) {
  253. $html[] = $this->placeholderOption($selectAttributes['placeholder'], $selected);
  254. unset($selectAttributes['placeholder']);
  255. }
  256. foreach ($list as $value => $display) {
  257. $optionAttributes = $optionsAttributes[$value] ?? [];
  258. $optgroupAttributes = $optgroupsAttributes[$value] ?? [];
  259. $html[] = $this->getSelectOption($display, $value, $selected, $optionAttributes, $optgroupAttributes);
  260. }
  261. //一旦我们拥有了所有这些HTML,我们就可以在之后将其加入到单个元素中
  262. //将属性格式化为HTML“attributes”字符串,然后
  263. //构建一个最终的select语句,它将包含所有的值。
  264. $selectAttributes = $this->attributes($selectAttributes);
  265. $list = implode('', $html);
  266. return "<select{$selectAttributes}>{$list}</select>";
  267. }
  268. /**
  269. * 创建一个按钮字段
  270. *
  271. * @param string $value
  272. * @param array $options
  273. *
  274. * @return string
  275. */
  276. public function button($value = null, $options = [])
  277. {
  278. if (!array_key_exists('type', $options)) {
  279. $options['type'] = 'button';
  280. }
  281. return '<button' . $this->attributes($options) . '>' . $value . '</button>';
  282. }
  283. /**
  284. * 创建单选按钮输入字段
  285. *
  286. * @param string $name
  287. * @param mixed $value
  288. * @param bool $checked
  289. * @param array $options
  290. *
  291. * @return string
  292. */
  293. public function radio($name, $value = null, $checked = null, $options = [])
  294. {
  295. if (is_null($value)) {
  296. $value = $name;
  297. }
  298. if ($checked) {
  299. $options['checked'] = 'checked';
  300. }
  301. return $this->input('radio', $name, $value, $options);
  302. }
  303. /**
  304. * 创建一组单选框字段
  305. *
  306. * @param string $name
  307. * @param array $list
  308. * @param mixed $checked
  309. * @param array $title
  310. * @param array $options
  311. *
  312. * @return string
  313. */
  314. public function radios($name, $list, $checked = null, $title = [], $options = [])
  315. {
  316. if (is_array($list)) {
  317. $html = [];
  318. $checked = is_null($checked) ? key($list) : $checked;
  319. $checked = is_array($checked) ? $checked : explode(',', $checked);
  320. foreach ($list as $k => $v) {
  321. $options['id'] = "{$name}-{$k}";
  322. $options['title'] = $title[$k] ?? $v;
  323. $html[] = Form::radio($name, $k, in_array($k, $checked), $options);
  324. }
  325. return '<div class="radio-group">' . implode(' ', $html) . '</div>';
  326. }
  327. return '';
  328. }
  329. /**
  330. * 创建复选按钮字段
  331. *
  332. * @param string $name
  333. * @param mixed $value
  334. * @param bool $checked
  335. * @param array $options
  336. *
  337. * @return string
  338. */
  339. public function checkbox($name, $value = 1, $checked = null, $options = [])
  340. {
  341. if ($checked) {
  342. $options['checked'] = 'checked';
  343. }
  344. return $this->input('checkbox', $name, $value, $options);
  345. }
  346. /**
  347. * 创建一组复选按钮框字段
  348. *
  349. * @param string $name
  350. * @param array $list
  351. * @param mixed $checked
  352. * @param array $title
  353. * @param array $options
  354. *
  355. * @return string
  356. */
  357. public function checkboxs($name, $list, $checked, $title = [], $options = [])
  358. {
  359. if (is_array($list)) {
  360. $html = [];
  361. $checked = is_null($checked) ? [] : $checked;
  362. $checked = is_array($checked) ? $checked : explode(',', $checked);
  363. foreach ($list as $k => $v) {
  364. $options['id'] = "{$name}-{$k}";
  365. $options['title'] = $title[$k] ?? $v;
  366. $html[] = Form::checkbox("{$name}[{$k}]", $k, in_array($k, $checked), $options);
  367. }
  368. return '<div class="checkbox">' . implode(' ', $html) . '</div>';
  369. }
  370. return '';
  371. }
  372. /**
  373. * 创建一个上传图片组件(单图)字段
  374. *
  375. * @param string $name
  376. * @param string $value
  377. * @param array $inputAttr
  378. * @param array $uploadAttr
  379. * @param array $chooseAttr
  380. * @param array $previewAttr
  381. *
  382. * @return string
  383. */
  384. public function image($name = null, $value = null, $inputAttr = [], $uploadAttr = [], $chooseAttr = [], $previewAttr = [])
  385. {
  386. $default = [
  387. 'data-type' => "image",
  388. 'data-mimetype' => 'image/gif,image/jpeg,image/png,image/jpg,image/bmp',
  389. ];
  390. $uploadAttr = is_array($uploadAttr) ? array_merge($default, $uploadAttr) : $uploadAttr;
  391. $chooseAttr = is_array($chooseAttr) ? array_merge($default, $chooseAttr) : $chooseAttr;
  392. return $this->uploader($name, $value, $inputAttr, $uploadAttr, $chooseAttr, $previewAttr);
  393. }
  394. /**
  395. * 创建一个上传图片组件(多图)字段
  396. *
  397. * @param string $name
  398. * @param string $value
  399. * @param array $inputAttr
  400. * @param array $uploadAttr
  401. * @param array $chooseAttr
  402. * @param array $previewAttr
  403. *
  404. * @return string
  405. */
  406. public function images($name = null, $value = null, $inputAttr = [], $uploadAttr = [], $chooseAttr = [], $previewAttr = [])
  407. {
  408. $default = [
  409. 'data-type' => "image",
  410. 'data-multiple' => 'true',
  411. 'data-mimetype' => 'image/gif,image/jpeg,image/png,image/jpg,image/bmp',
  412. ];
  413. $uploadAttr = is_array($uploadAttr) ? array_merge($default, $uploadAttr) : $uploadAttr;
  414. $chooseAttr = is_array($chooseAttr) ? array_merge($default, $chooseAttr) : $chooseAttr;
  415. return $this->uploader($name, $value, $inputAttr, $uploadAttr, $chooseAttr, $previewAttr);
  416. }
  417. /**
  418. * 创建上传文件组件(单文件)字段
  419. *
  420. * @param string $name
  421. * @param string $value
  422. * @param array $inputAttr
  423. * @param array $uploadAttr
  424. * @param array $chooseAttr
  425. * @param array $previewAttr
  426. *
  427. * @return string
  428. */
  429. public function upload($name = null, $value = null, $inputAttr = [], $uploadAttr = [], $chooseAttr = [], $previewAttr = [])
  430. {
  431. $default = [
  432. 'data-type' => "file",
  433. ];
  434. $uploadAttr = is_array($uploadAttr) ? array_merge($default, $uploadAttr) : $uploadAttr;
  435. $chooseAttr = is_array($chooseAttr) ? array_merge($default, $chooseAttr) : $chooseAttr;
  436. return $this->uploader($name, $value, $inputAttr, $uploadAttr, $chooseAttr, $previewAttr);
  437. }
  438. /**
  439. * 创建上传文件组件(多文件)字段
  440. *
  441. * @param string $name
  442. * @param string $value
  443. * @param array $inputAttr
  444. * @param array $uploadAttr
  445. * @param array $chooseAttr
  446. * @param array $previewAttr
  447. *
  448. * @return string
  449. */
  450. public function uploads($name = null, $value = null, $inputAttr = [], $uploadAttr = [], $chooseAttr = [], $previewAttr = [])
  451. {
  452. $default = [
  453. 'data-type' => "file",
  454. 'data-multiple' => 'true',
  455. ];
  456. $uploadAttr = is_array($uploadAttr) ? array_merge($default, $uploadAttr) : $uploadAttr;
  457. $chooseAttr = is_array($chooseAttr) ? array_merge($default, $chooseAttr) : $chooseAttr;
  458. return $this->uploader($name, $value, $inputAttr, $uploadAttr, $chooseAttr, $previewAttr);
  459. }
  460. /**
  461. * 创建颜色选择字段
  462. *
  463. * @param string $name
  464. * @param string $value
  465. * @param array $options
  466. *
  467. * @return string
  468. */
  469. public function color($name = null, $value = null, $options = [])
  470. {
  471. $domname = str_replace(['[', ']', '.'], '', $name);
  472. $input = $this->text($name, $value, array_merge(['id' => "c-{$domname}", 'placeholder' => '请选择颜色'], $options));
  473. $html = <<<EOD
  474. <div class="layui-input-inline" style="width: 120px;">
  475. {$input}
  476. </div>
  477. <div class="layui-inline" style="left: -11px;">
  478. <div class="colorpicker" data-input-id="c-{$domname}"></div>
  479. </div>
  480. EOD;
  481. return $html;
  482. }
  483. /**
  484. * 创建日期时间选择器字段
  485. *
  486. * @param string $name
  487. * @param string $value
  488. * @param array $options
  489. *
  490. * @return string
  491. */
  492. public function datetime($name = null, $value = null, $options = [])
  493. {
  494. $value = is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
  495. return $this->datetimepicker($name, $value, $options);
  496. }
  497. /**
  498. * 日期时间选择器
  499. *
  500. * @param string $name
  501. * @param mixed $value
  502. * @param array $options
  503. * @return string
  504. */
  505. public function datetimepicker($name, $value, $options = [])
  506. {
  507. $value = is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
  508. $options['class'] = isset($options['class']) ? $options['class'] . ' datetime' : 'datetime';
  509. return $this->text($name, $value, $options);
  510. }
  511. /**
  512. * 创建动态下拉列表字段
  513. *
  514. * @param string $name 名称
  515. * @param mixed $value
  516. * @param string $url 数据源地址
  517. * @param string $field 显示的字段名称,默认为name
  518. * @param string $primaryKey 主键,数据库中保存的值,默认为id
  519. * @param array $options
  520. *
  521. * @return string
  522. */
  523. public function selectpage($name, $value, $url, $field = null, $primaryKey = null, $options = [])
  524. {
  525. $options = array_merge($options, ['data-source' => $url, 'data-field' => $field ? $field : 'name', 'data-primary-key' => $primaryKey ? $primaryKey : 'id']);
  526. if (isset($options['class'])) {
  527. $options['class'][] = 'selectpage';
  528. } else {
  529. $options['class'] = 'selectpage';
  530. }
  531. return $this->text($name, $value, $options);
  532. }
  533. /**
  534. * 创建动态下拉列表(复选)字段
  535. *
  536. * @param string $name 名称
  537. * @param mixed $value
  538. * @param string $url 数据源地址
  539. * @param string $field 显示的字段名称,默认为name
  540. * @param string $primaryKey 主键,数据库中保存的值,默认为id
  541. * @param array $options
  542. *
  543. * @return string
  544. */
  545. public function selectpages($name, $value, $url, $field = null, $primaryKey = null, $options = [])
  546. {
  547. $options['data-multiple'] = "true";
  548. return $this->selectpage($name, $value, $url, $field, $primaryKey, $options);
  549. }
  550. protected function uploader($name = null, $value = null, $inputAttr = [], $uploadAttr = [], $chooseAttr = [], $previewAttr = [])
  551. {
  552. $domname = str_replace(['[', ']', '.'], '', $name);
  553. $upload = $uploadAttr === false ? false : true;
  554. $choose = $chooseAttr === false ? false : true;
  555. $preview = $previewAttr === false ? false : true;
  556. $options = [
  557. 'id' => "faupload_{$domname}",
  558. 'class' => "layui-btn faupload",
  559. 'data-input-id' => "c-{$domname}",
  560. ];
  561. if ($preview) {
  562. $options['data-preview-id'] = "p-{$domname}";
  563. }
  564. $uploadBtn = $upload ? $this->button('<i class="iconfont icon-upload-line"></i> ' . '上传', array_merge($options, $uploadAttr)) : '';
  565. $options = [
  566. 'id' => "fachoose-{$domname}",
  567. 'class' => "layui-btn fachoose",
  568. 'data-input-id' => "c-{$domname}",
  569. ];
  570. if ($preview) {
  571. $options['data-preview-id'] = "p-{$domname}";
  572. }
  573. $chooseBtn = $choose ? $this->button('<i class="iconfont icon-list-unordered"></i> ' . '选择', array_merge($options, $chooseAttr)) : '';
  574. $previewAttrHtml = $this->attributes($previewAttr);
  575. $previewArea = $preview ? '<ul class="layui-row list-inline plupload-preview" id="p-' . $domname . '" ' . $previewAttrHtml . '></ul>' : '';
  576. $input = $this->text($name, $value, array_merge(['id' => "c-{$domname}", 'class' => 'layui-input'], $inputAttr));
  577. $html = <<<EOD
  578. <div class="layui-col-xs6">{$input}</div>
  579. {$uploadBtn}{$chooseBtn}
  580. {$previewArea}
  581. EOD;
  582. return $html;
  583. }
  584. /**
  585. * 获取给定值的选择选项
  586. *
  587. * @param string $display
  588. * @param string $value
  589. * @param string $selected
  590. * @param array $attributes
  591. * @param array $optgroupAttributes
  592. *
  593. * @return mixed
  594. */
  595. protected function getSelectOption($display, $value, $selected, array $attributes = [], array $optgroupAttributes = [])
  596. {
  597. if (is_array($display)) {
  598. //if (is_iterable($display)) {
  599. return $this->optionGroup($display, $value, $selected, $optgroupAttributes, $attributes);
  600. }
  601. return $this->option($display, $value, $selected, $attributes);
  602. }
  603. /**
  604. * 创建选项组表单元素
  605. *
  606. * @param array $list
  607. * @param string $label
  608. * @param string $selected
  609. * @param array $attributes
  610. * @param array $optionsAttributes
  611. * @param integer $level
  612. *
  613. * @return string
  614. */
  615. protected function optionGroup($list, $label, $selected, array $attributes = [], array $optionsAttributes = [], $level = 0)
  616. {
  617. $html = [];
  618. $space = str_repeat("&nbsp;", $level);
  619. foreach ($list as $value => $display) {
  620. $optionAttributes = $optionsAttributes[$value] ?? [];
  621. if (is_array($display)) {
  622. //if (is_iterable($display)) {
  623. $html[] = $this->optionGroup($display, $value, $selected, $attributes, $optionAttributes, $level + 5);
  624. } else {
  625. $html[] = $this->option($space . $display, $value, $selected, $optionAttributes);
  626. }
  627. }
  628. return '<optgroup label="' . e($space . $label, false) . '"' . $this->attributes($attributes) . '>' . implode('', $html) . '</optgroup>';
  629. }
  630. /**
  631. * 创建一个选择元素选项
  632. *
  633. * @param string $display
  634. * @param string $value
  635. * @param string $selected
  636. * @param array $attributes
  637. *
  638. * @return mixed
  639. */
  640. protected function option($display, $value, $selected, array $attributes = [])
  641. {
  642. $selected = $this->getSelectedValue($value, $selected);
  643. $options = array_merge(['value' => $value, 'selected' => $selected], $attributes);
  644. $string = '<option' . $this->attributes($options) . '>';
  645. if ($display !== null) {
  646. $string .= e($display, false) . '</option>';
  647. }
  648. return $string;
  649. }
  650. /**
  651. * 创建占位符选择元素选项
  652. *
  653. * @param $display
  654. * @param $selected
  655. *
  656. * @return mixed
  657. */
  658. protected function placeholderOption($display, $selected)
  659. {
  660. $selected = $this->getSelectedValue(null, $selected);
  661. $options = [
  662. 'selected' => $selected,
  663. 'value' => '',
  664. ];
  665. return '<option' . $this->attributes($options) . '>' . e($display, false) . '</option>';
  666. }
  667. /**
  668. * 确定是否选择了该值
  669. *
  670. * @param string $value
  671. * @param string $selected
  672. *
  673. * @return null|string
  674. */
  675. protected function getSelectedValue($value, $selected)
  676. {
  677. if (is_array($selected)) {
  678. return in_array($value, $selected, true) || in_array((string) $value, $selected, true) ? 'selected' : null;
  679. }
  680. if (is_int($value) && is_bool($selected)) {
  681. return (bool) $value === $selected;
  682. }
  683. return ((string) $value === (string) $selected) ? 'selected' : null;
  684. }
  685. /**
  686. * 在属性上设置文本区域大小
  687. *
  688. * @param array $options
  689. *
  690. * @return array
  691. */
  692. protected function setTextAreaSize($options)
  693. {
  694. if (isset($options['size'])) {
  695. return $this->setQuickTextAreaSize($options);
  696. }
  697. //如果没有指定“size”属性,我们将只查找常规
  698. //列和行属性,如果这些属性在
  699. //属性数组。然后我们将返回整个选项数组。
  700. $cols = Arr::get($options, 'cols', 50);
  701. $rows = Arr::get($options, 'rows', 10);
  702. return array_merge($options, compact('cols', 'rows'));
  703. }
  704. /**
  705. * 使用快速“大小”属性设置文本区域大小
  706. *
  707. * @param array $options
  708. *
  709. * @return array
  710. */
  711. protected function setQuickTextAreaSize($options)
  712. {
  713. $segments = explode('x', $options['size']);
  714. return array_merge($options, ['cols' => $segments[0], 'rows' => $segments[1]]);
  715. }
  716. /**
  717. * 获取应分配给字段的值
  718. *
  719. * @param string $name
  720. * @param string $value
  721. *
  722. * @return mixed
  723. */
  724. protected function getValueAttribute($name, $value = null)
  725. {
  726. if (is_null($name)) {
  727. return $value;
  728. }
  729. if (!is_null($value)) {
  730. return $value;
  731. }
  732. }
  733. /**
  734. * 将HTML字符串转换为实体
  735. *
  736. * @param string $value
  737. *
  738. * @return string
  739. */
  740. protected function entities($value)
  741. {
  742. return htmlentities($value, ENT_QUOTES, 'UTF-8', false);
  743. }
  744. /**
  745. * 获取字段名的ID属性
  746. *
  747. * @param string $name
  748. * @param array $attributes
  749. *
  750. * @return string
  751. */
  752. public function getIdAttribute($name, $attributes)
  753. {
  754. if (array_key_exists('id', $attributes)) {
  755. return $attributes['id'];
  756. }
  757. if (in_array($name, $this->labels)) {
  758. return $name;
  759. }
  760. }
  761. /**
  762. * 设置标签值的格式。
  763. *
  764. * @param string $name
  765. * @param string|null $value
  766. *
  767. * @return string
  768. */
  769. protected function formatLabel($name, $value)
  770. {
  771. return $value ?: ucwords(str_replace('_', ' ', $name));
  772. }
  773. /**
  774. * 从数组生成HTML属性字符串
  775. *
  776. * @param array $attributes
  777. *
  778. * @return string
  779. */
  780. public function attributes($attributes)
  781. {
  782. $html = [];
  783. foreach ((array) $attributes as $key => $value) {
  784. $element = $this->attributeElement($key, $value);
  785. if (!is_null($element)) {
  786. $html[] = $element;
  787. }
  788. }
  789. return count($html) > 0 ? ' ' . implode(' ', $html) : '';
  790. }
  791. /**
  792. * 构建单个属性元素
  793. *
  794. * @param string $key
  795. * @param string $value
  796. *
  797. * @return string
  798. */
  799. protected function attributeElement($key, $value)
  800. {
  801. //[required]之类的HTML属性转换为正确的形式,而不是使用错误的数字。
  802. if (is_numeric($key)) {
  803. return $value;
  804. }
  805. // 将布尔属性视为HTML属性
  806. if (is_bool($value) && $key !== 'value') {
  807. return $value ? $key : '';
  808. }
  809. //多个class属性
  810. if (is_array($value) && $key === 'class') {
  811. return 'class="' . implode(' ', $value) . '"';
  812. }
  813. if (!is_null($value)) {
  814. if (is_array($value) || stripos($value, '"') !== false) {
  815. $value = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
  816. return $key . "='" . $value . "'";
  817. } else {
  818. return $key . '="' . $value . '"';
  819. }
  820. }
  821. }
  822. }
  823. if (!function_exists('e')) {
  824. /**
  825. * 将HTML特殊字符编码为字符串
  826. *
  827. * @param string $value
  828. * @param bool $doubleEncode
  829. *
  830. * @return string
  831. */
  832. function e($value, $doubleEncode = true)
  833. {
  834. if (is_array($value)) {
  835. $value = json_encode($value, JSON_UNESCAPED_UNICODE);
  836. }
  837. return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', $doubleEncode);
  838. }
  839. }