Form.php 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234
  1. <?php
  2. namespace fast;
  3. use ArrayAccess;
  4. /**
  5. * @class Form
  6. * @package fast
  7. * @method mixed token() static token
  8. * @method mixed close() static 关闭一个HTML表单
  9. * @method mixed setModel(mixed $model) static 设置HTML表单模型
  10. * @method mixed open(array $options) static 打开一个新的HTML表单
  11. * @method mixed file(string $name, array $options = array()) static 表单file
  12. * @method mixed reset(string $name, array $options = array()) static 表单reset
  13. * @method mixed password(string $name, array $options = array()) static 表单password
  14. * @method mixed button(string $value = null, array $options = array()) static 表单button
  15. * @method mixed model(mixed $model ,array $options = array()) static 打开一个新的HTML表单模型
  16. * @method mixed submit(string $value = null, array $options = array()) static 表单submit提交
  17. * @method mixed text(string $name, string $value = null, array $options = []) static 表单text
  18. * @method mixed label(string $name, string $value = null, array $options = []) static label标签
  19. * @method mixed url(string $name, string $value = null, array $options = array()) static 表单url
  20. * @method mixed email(string $name, string $value = null, array $options = array()) static 表单email
  21. * @method mixed hidden(string $name, string $value = null, array $options = array()) static 表单hidden
  22. * @method mixed image(string $url, string $name = null, array $attributes = array()) static 表单image提交
  23. * @method mixed textarea(string $name, string $value = null, array $options = array()) static 表单textarea
  24. * @method mixed checkbox(string $name, string $value = 1, string $checked = null, array $options = array()) static 表单checkbox
  25. * @method mixed radio(string $name, string $value = null, string $checked = null, array $options = array())) static 表单radio
  26. * @method mixed select(string $name, array $list = array(), string $selected = null, array $options = array()) static 表单textarea
  27. * @method mixed selectYear(string $name ,string $begin,string $end, string $selected = null ,array $options = array()) static select年
  28. * @method mixed selectMonth(string $name ,string $selected = null ,array $options = array() ,string $format = '%m') static select月
  29. */
  30. class Form
  31. {
  32. public function __construct()
  33. {
  34. }
  35. public static function __callStatic($name, $arguments)
  36. {
  37. return call_user_func_array([FormBuilder::instance(), $name], $arguments);
  38. }
  39. }
  40. class FormBuilder
  41. {
  42. /**
  43. * The CSRF token used by the form builder.
  44. *
  45. * @var string
  46. */
  47. protected $csrfToken = array('name' => '__token__');
  48. /**
  49. * The current model instance for the form.
  50. *
  51. * @var mixed
  52. */
  53. protected $model;
  54. /**
  55. * An array of label names we've created.
  56. *
  57. * @var array
  58. */
  59. protected $labels = array();
  60. /**
  61. * The reserved form open attributes.
  62. *
  63. * @var array
  64. */
  65. protected $reserved = array('method', 'url', 'route', 'action', 'files');
  66. /**
  67. * The form methods that should be spoofed, in uppercase.
  68. *
  69. * @var array
  70. */
  71. protected $spoofedMethods = array('DELETE', 'PATCH', 'PUT');
  72. /**
  73. * The types of inputs to not fill values on by default.
  74. *
  75. * @var array
  76. */
  77. protected $skipValueTypes = array('file', 'password', 'checkbox', 'radio');
  78. /**
  79. * Escape html
  80. * @var boolean
  81. */
  82. protected $escapeHtml = true;
  83. protected static $instance;
  84. /**
  85. * Create a new form builder instance.
  86. *
  87. * @return void
  88. */
  89. public function __construct()
  90. {
  91. }
  92. public static function instance($options = [])
  93. {
  94. if (is_null(self::$instance))
  95. {
  96. self::$instance = new static($options);
  97. }
  98. return self::$instance;
  99. }
  100. /**
  101. * Open up a new HTML form.
  102. *
  103. * @param array $options
  104. * @return string
  105. */
  106. public function open(array $options = array())
  107. {
  108. $method = array_get($options, 'method', 'post');
  109. // We need to extract the proper method from the attributes. If the method is
  110. // something other than GET or POST we'll use POST since we will spoof the
  111. // actual method since forms don't support the reserved methods in HTML.
  112. $attributes['method'] = $this->getMethod($method);
  113. $attributes['action'] = array_get($options, 'action', '');
  114. $attributes['accept-charset'] = 'UTF-8';
  115. // If the method is PUT, PATCH or DELETE we will need to add a spoofer hidden
  116. // field that will instruct the Symfony request to pretend the method is a
  117. // different method than it actually is, for convenience from the forms.
  118. $append = $this->getAppendage($method);
  119. if (isset($options['files']) && $options['files'])
  120. {
  121. $options['enctype'] = 'multipart/form-data';
  122. }
  123. // Finally we're ready to create the final form HTML field. We will attribute
  124. // format the array of attributes. We will also add on the appendage which
  125. // is used to spoof requests for this PUT, PATCH, etc. methods on forms.
  126. $attributes = array_merge(
  127. $attributes, array_except($options, $this->reserved)
  128. );
  129. // Finally, we will concatenate all of the attributes into a single string so
  130. // we can build out the final form open statement. We'll also append on an
  131. // extra value for the hidden _method field if it's needed for the form.
  132. $attributes = $this->attributes($attributes);
  133. return '<form' . $attributes . '>' . $append;
  134. }
  135. /**
  136. * Create a new model based form builder.
  137. *
  138. * @param mixed $model
  139. * @param array $options
  140. * @return string
  141. */
  142. public function model($model, array $options = array())
  143. {
  144. $this->model = $model;
  145. return $this->open($options);
  146. }
  147. /**
  148. * Set the model instance on the form builder.
  149. *
  150. * @param mixed $model
  151. * @return void
  152. */
  153. public function setModel($model)
  154. {
  155. $this->model = $model;
  156. }
  157. /**
  158. * Set the escape html mode
  159. * @param boolean $escape
  160. */
  161. public function setEscapeHtml($escape)
  162. {
  163. $this->escapeHtml = $escape;
  164. }
  165. /**
  166. * Escape HTML special characters in a string.
  167. * @return string
  168. */
  169. public function escape($value)
  170. {
  171. if (!$this->escapeHtml)
  172. {
  173. return $value;
  174. }
  175. if (is_array($value))
  176. {
  177. $value = json_encode($value, JSON_UNESCAPED_UNICODE);
  178. }
  179. return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false);
  180. }
  181. /**
  182. * Close the current form.
  183. *
  184. * @return string
  185. */
  186. public function close()
  187. {
  188. $this->labels = array();
  189. $this->model = null;
  190. return '</form>';
  191. }
  192. /**
  193. * Generate a hidden field with the current CSRF token.
  194. *
  195. * @return string
  196. */
  197. public function token($name = '__token__', $type = 'md5')
  198. {
  199. if (function_exists('token'))
  200. {
  201. return token($name, $type);
  202. }
  203. return '';
  204. }
  205. /**
  206. * Create a form label element.
  207. *
  208. * @param string $name
  209. * @param string $value
  210. * @param array $options
  211. * @return string
  212. */
  213. public function label($name, $value = null, $options = array())
  214. {
  215. $this->labels[] = $name;
  216. $options = $this->attributes($options);
  217. $value = $this->escape($this->formatLabel($name, $value));
  218. return '<label for="' . $name . '"' . $options . '>' . $value . '</label>';
  219. }
  220. /**
  221. * Format the label value.
  222. *
  223. * @param string $name
  224. * @param string|null $value
  225. * @return string
  226. */
  227. protected function formatLabel($name, $value)
  228. {
  229. return $value ? : ucwords(str_replace('_', ' ', $name));
  230. }
  231. /**
  232. * Create a form input field.
  233. *
  234. * @param string $type
  235. * @param string $name
  236. * @param string $value
  237. * @param array $options
  238. * @return string
  239. */
  240. public function input($type, $name, $value = null, $options = array())
  241. {
  242. if (!isset($options['name']))
  243. $options['name'] = $name;
  244. // We will get the appropriate value for the given field. We will look for the
  245. // value in the session for the value in the old input data then we'll look
  246. // in the model instance if one is set. Otherwise we will just use empty.
  247. $id = $this->getIdAttribute($name, $options);
  248. if (!in_array($type, $this->skipValueTypes))
  249. {
  250. $value = $this->getValueAttribute($name, $value);
  251. }
  252. // Once we have the type, value, and ID we can merge them into the rest of the
  253. // attributes array so we can convert them into their HTML attribute format
  254. // when creating the HTML element. Then, we will return the entire input.
  255. $merge = compact('type', 'value', 'id');
  256. $options = array_merge($options, $merge);
  257. return '<input' . $this->attributes($options) . '>';
  258. }
  259. /**
  260. * Create a text input field.
  261. *
  262. * @param string $name
  263. * @param string $value
  264. * @param array $options
  265. * @return string
  266. */
  267. public function text($name, $value = null, $options = array())
  268. {
  269. return $this->input('text', $name, $value, $options);
  270. }
  271. /**
  272. * Create a password input field.
  273. *
  274. * @param string $name
  275. * @param array $options
  276. * @return string
  277. */
  278. public function password($name, $options = array())
  279. {
  280. return $this->input('password', $name, '', $options);
  281. }
  282. /**
  283. * Create a hidden input field.
  284. *
  285. * @param string $name
  286. * @param string $value
  287. * @param array $options
  288. * @return string
  289. */
  290. public function hidden($name, $value = null, $options = array())
  291. {
  292. return $this->input('hidden', $name, $value, $options);
  293. }
  294. /**
  295. * Create an e-mail input field.
  296. *
  297. * @param string $name
  298. * @param string $value
  299. * @param array $options
  300. * @return string
  301. */
  302. public function email($name, $value = null, $options = array())
  303. {
  304. return $this->input('email', $name, $value, $options);
  305. }
  306. /**
  307. * Create a url input field.
  308. *
  309. * @param string $name
  310. * @param string $value
  311. * @param array $options
  312. * @return string
  313. */
  314. public function url($name, $value = null, $options = array())
  315. {
  316. return $this->input('url', $name, $value, $options);
  317. }
  318. /**
  319. * Create a file input field.
  320. *
  321. * @param string $name
  322. * @param array $options
  323. * @return string
  324. */
  325. public function file($name, $options = array())
  326. {
  327. return $this->input('file', $name, null, $options);
  328. }
  329. /**
  330. * Create a textarea input field.
  331. *
  332. * @param string $name
  333. * @param string $value
  334. * @param array $options
  335. * @return string
  336. */
  337. public function textarea($name, $value = null, $options = array())
  338. {
  339. if (!isset($options['name']))
  340. $options['name'] = $name;
  341. // Next we will look for the rows and cols attributes, as each of these are put
  342. // on the textarea element definition. If they are not present, we will just
  343. // assume some sane default values for these attributes for the developer.
  344. $options = $this->setTextAreaSize($options);
  345. $options['id'] = $this->getIdAttribute($name, $options);
  346. $value = (string) $this->getValueAttribute($name, $value);
  347. unset($options['size']);
  348. // Next we will convert the attributes into a string form. Also we have removed
  349. // the size attribute, as it was merely a short-cut for the rows and cols on
  350. // the element. Then we'll create the final textarea elements HTML for us.
  351. $options = $this->attributes($options);
  352. return '<textarea' . $options . '>' . $this->escape($value) . '</textarea>';
  353. }
  354. /**
  355. * Set the text area size on the attributes.
  356. *
  357. * @param array $options
  358. * @return array
  359. */
  360. protected function setTextAreaSize($options)
  361. {
  362. if (isset($options['size']))
  363. {
  364. return $this->setQuickTextAreaSize($options);
  365. }
  366. // If the "size" attribute was not specified, we will just look for the regular
  367. // columns and rows attributes, using sane defaults if these do not exist on
  368. // the attributes array. We'll then return this entire options array back.
  369. $cols = array_get($options, 'cols', 50);
  370. $rows = array_get($options, 'rows', 10);
  371. return array_merge($options, compact('cols', 'rows'));
  372. }
  373. /**
  374. * Set the text area size using the quick "size" attribute.
  375. *
  376. * @param array $options
  377. * @return array
  378. */
  379. protected function setQuickTextAreaSize($options)
  380. {
  381. $segments = explode('x', $options['size']);
  382. return array_merge($options, array('cols' => $segments[0], 'rows' => $segments[1]));
  383. }
  384. /**
  385. * Create a select box field.
  386. *
  387. * @param string $name
  388. * @param array $list
  389. * @param string $selected
  390. * @param array $options
  391. * @return string
  392. */
  393. public function select($name, $list = array(), $selected = null, $options = array())
  394. {
  395. // When building a select box the "value" attribute is really the selected one
  396. // so we will use that when checking the model or session for a value which
  397. // should provide a convenient method of re-populating the forms on post.
  398. $selected = $this->getValueAttribute($name, $selected);
  399. $options['id'] = $this->getIdAttribute($name, $options);
  400. if (!isset($options['name']))
  401. $options['name'] = $name;
  402. // We will simply loop through the options and build an HTML value for each of
  403. // them until we have an array of HTML declarations. Then we will join them
  404. // all together into one single HTML element that can be put on the form.
  405. $html = array();
  406. foreach ($list as $value => $display)
  407. {
  408. $html[] = $this->getSelectOption($display, $value, $selected);
  409. }
  410. // Once we have all of this HTML, we can join this into a single element after
  411. // formatting the attributes into an HTML "attributes" string, then we will
  412. // build out a final select statement, which will contain all the values.
  413. $options = $this->attributes($options);
  414. $list = implode('', $html);
  415. return "<select{$options}>{$list}</select>";
  416. }
  417. /**
  418. * Create a select range field.
  419. *
  420. * @param string $name
  421. * @param string $begin
  422. * @param string $end
  423. * @param string $selected
  424. * @param array $options
  425. * @return string
  426. */
  427. public function selectRange($name, $begin, $end, $selected = null, $options = array())
  428. {
  429. $range = array_combine($range = range($begin, $end), $range);
  430. return $this->select($name, $range, $selected, $options);
  431. }
  432. /**
  433. * Create a select year field.
  434. *
  435. * @param string $name
  436. * @param string $begin
  437. * @param string $end
  438. * @param string $selected
  439. * @param array $options
  440. * @return string
  441. */
  442. public function selectYear()
  443. {
  444. return call_user_func_array(array($this, 'selectRange'), func_get_args());
  445. }
  446. /**
  447. * Create a select month field.
  448. *
  449. * @param string $name
  450. * @param string $selected
  451. * @param array $options
  452. * @param string $format
  453. * @return string
  454. */
  455. public function selectMonth($name, $selected = null, $options = array(), $format = '%m')
  456. {
  457. $months = array();
  458. foreach (range(1, 12) as $month)
  459. {
  460. $months[$month] = strftime($format, mktime(0, 0, 0, $month, 1));
  461. }
  462. return $this->select($name, $months, $selected, $options);
  463. }
  464. /**
  465. * Get the select option for the given value.
  466. *
  467. * @param string $display
  468. * @param string $value
  469. * @param string $selected
  470. * @return string
  471. */
  472. public function getSelectOption($display, $value, $selected)
  473. {
  474. if (is_array($display))
  475. {
  476. return $this->optionGroup($display, $value, $selected);
  477. }
  478. return $this->option($display, $value, $selected);
  479. }
  480. /**
  481. * Create an option group form element.
  482. *
  483. * @param array $list
  484. * @param string $label
  485. * @param string $selected
  486. * @return string
  487. */
  488. protected function optionGroup($list, $label, $selected)
  489. {
  490. $html = array();
  491. foreach ($list as $value => $display)
  492. {
  493. $html[] = $this->option($display, $value, $selected);
  494. }
  495. return '<optgroup label="' . $this->escape($label) . '">' . implode('', $html) . '</optgroup>';
  496. }
  497. /**
  498. * Create a select element option.
  499. *
  500. * @param string $display
  501. * @param string $value
  502. * @param string $selected
  503. * @return string
  504. */
  505. protected function option($display, $value, $selected)
  506. {
  507. $selected = $this->getSelectedValue($value, $selected);
  508. $options = array('value' => $this->escape($value), 'selected' => $selected);
  509. return '<option' . $this->attributes($options) . '>' . $this->escape($display) . '</option>';
  510. }
  511. /**
  512. * Determine if the value is selected.
  513. *
  514. * @param string $value
  515. * @param string $selected
  516. * @return string
  517. */
  518. protected function getSelectedValue($value, $selected)
  519. {
  520. if (is_array($selected))
  521. {
  522. return in_array($value, $selected) ? 'selected' : null;
  523. }
  524. return ((string) $value == (string) $selected) ? 'selected' : null;
  525. }
  526. /**
  527. * Create a checkbox input field.
  528. *
  529. * @param string $name
  530. * @param mixed $value
  531. * @param bool $checked
  532. * @param array $options
  533. * @return string
  534. */
  535. public function checkbox($name, $value = 1, $checked = null, $options = array())
  536. {
  537. return $this->checkable('checkbox', $name, $value, $checked, $options);
  538. }
  539. /**
  540. * Create a radio button input field.
  541. *
  542. * @param string $name
  543. * @param mixed $value
  544. * @param bool $checked
  545. * @param array $options
  546. * @return string
  547. */
  548. public function radio($name, $value = null, $checked = null, $options = array())
  549. {
  550. if (is_null($value))
  551. $value = $name;
  552. return $this->checkable('radio', $name, $value, $checked, $options);
  553. }
  554. /**
  555. * Create a checkable input field.
  556. *
  557. * @param string $type
  558. * @param string $name
  559. * @param mixed $value
  560. * @param bool $checked
  561. * @param array $options
  562. * @return string
  563. */
  564. protected function checkable($type, $name, $value, $checked, $options)
  565. {
  566. $checked = $this->getCheckedState($type, $name, $value, $checked);
  567. if ($checked)
  568. $options['checked'] = 'checked';
  569. return $this->input($type, $name, $value, $options);
  570. }
  571. /**
  572. * Get the check state for a checkable input.
  573. *
  574. * @param string $type
  575. * @param string $name
  576. * @param mixed $value
  577. * @param bool $checked
  578. * @return bool
  579. */
  580. protected function getCheckedState($type, $name, $value, $checked)
  581. {
  582. switch ($type)
  583. {
  584. case 'checkbox':
  585. return $this->getCheckboxCheckedState($name, $value, $checked);
  586. case 'radio':
  587. return $this->getRadioCheckedState($name, $value, $checked);
  588. default:
  589. return $this->getValueAttribute($name) == $value;
  590. }
  591. }
  592. /**
  593. * Get the check state for a checkbox input.
  594. *
  595. * @param string $name
  596. * @param mixed $value
  597. * @param bool $checked
  598. * @return bool
  599. */
  600. protected function getCheckboxCheckedState($name, $value, $checked)
  601. {
  602. if (isset($this->session) && !$this->oldInputIsEmpty() && is_null($this->old($name)))
  603. return false;
  604. if ($this->missingOldAndModel($name))
  605. return $checked;
  606. $posted = $this->getValueAttribute($name);
  607. return is_array($posted) ? in_array($value, $posted) : (bool) $posted;
  608. }
  609. /**
  610. * Get the check state for a radio input.
  611. *
  612. * @param string $name
  613. * @param mixed $value
  614. * @param bool $checked
  615. * @return bool
  616. */
  617. protected function getRadioCheckedState($name, $value, $checked)
  618. {
  619. if ($this->missingOldAndModel($name))
  620. return $checked;
  621. return $this->getValueAttribute($name) == $value;
  622. }
  623. /**
  624. * Determine if old input or model input exists for a key.
  625. *
  626. * @param string $name
  627. * @return bool
  628. */
  629. protected function missingOldAndModel($name)
  630. {
  631. return (is_null($this->old($name)) && is_null($this->getModelValueAttribute($name)));
  632. }
  633. /**
  634. * Create a HTML reset input element.
  635. *
  636. * @param string $value
  637. * @param array $attributes
  638. * @return string
  639. */
  640. public function reset($value, $attributes = array())
  641. {
  642. return $this->input('reset', null, $value, $attributes);
  643. }
  644. /**
  645. * Create a HTML image input element.
  646. *
  647. * @param string $url
  648. * @param string $name
  649. * @param array $attributes
  650. * @return string
  651. */
  652. public function image($url, $name = null, $attributes = array())
  653. {
  654. $attributes['src'] = $url;
  655. return $this->input('image', $name, null, $attributes);
  656. }
  657. /**
  658. * Create a submit button element.
  659. *
  660. * @param string $value
  661. * @param array $options
  662. * @return string
  663. */
  664. public function submit($value = null, $options = array())
  665. {
  666. return $this->input('submit', null, $value, $options);
  667. }
  668. /**
  669. * Create a button element.
  670. *
  671. * @param string $value
  672. * @param array $options
  673. * @return string
  674. */
  675. public function button($value = null, $options = array())
  676. {
  677. if (!array_key_exists('type', $options))
  678. {
  679. $options['type'] = 'button';
  680. }
  681. return '<button' . $this->attributes($options) . '>' . $value . '</button>';
  682. }
  683. /**
  684. * Parse the form action method.
  685. *
  686. * @param string $method
  687. * @return string
  688. */
  689. protected function getMethod($method)
  690. {
  691. $method = strtoupper($method);
  692. return $method != 'GET' ? 'POST' : $method;
  693. }
  694. /**
  695. * Get the form action from the options.
  696. *
  697. * @param array $options
  698. * @return string
  699. */
  700. /* protected function getAction(array $options)
  701. {
  702. // We will also check for a "route" or "action" parameter on the array so that
  703. // developers can easily specify a route or controller action when creating
  704. // a form providing a convenient interface for creating the form actions.
  705. if (isset($options['url']))
  706. {
  707. return $this->getUrlAction($options['url']);
  708. }
  709. if (isset($options['route']))
  710. {
  711. return $this->getRouteAction($options['route']);
  712. }
  713. // If an action is available, we are attempting to open a form to a controller
  714. // action route. So, we will use the URL generator to get the path to these
  715. // actions and return them from the method. Otherwise, we'll use current.
  716. elseif (isset($options['action']))
  717. {
  718. return $this->getControllerAction($options['action']);
  719. }
  720. return $this->url->current();
  721. } */
  722. /**
  723. * Get the action for a "url" option.
  724. *
  725. * @param array|string $options
  726. * @return string
  727. */
  728. /* protected function getUrlAction($options)
  729. {
  730. if (is_array($options))
  731. {
  732. return $this->url->to($options[0], array_slice($options, 1));
  733. }
  734. return $this->url->to($options);
  735. } */
  736. /**
  737. * Get the action for a "route" option.
  738. *
  739. * @param array|string $options
  740. * @return string
  741. */
  742. /* protected function getRouteAction($options)
  743. {
  744. if (is_array($options))
  745. {
  746. return $this->url->route($options[0], array_slice($options, 1));
  747. }
  748. return $this->url->route($options);
  749. } */
  750. /**
  751. * Get the action for an "action" option.
  752. *
  753. * @param array|string $options
  754. * @return string
  755. */
  756. /* protected function getControllerAction($options)
  757. {
  758. if (is_array($options))
  759. {
  760. return $this->url->action($options[0], array_slice($options, 1));
  761. }
  762. return $this->url->action($options);
  763. } */
  764. /**
  765. * Get the form appendage for the given method.
  766. *
  767. * @param string $method
  768. * @return string
  769. */
  770. protected function getAppendage($method)
  771. {
  772. list($method, $appendage) = array(strtoupper($method), '');
  773. // If the HTTP method is in this list of spoofed methods, we will attach the
  774. // method spoofer hidden input to the form. This allows us to use regular
  775. // form to initiate PUT and DELETE requests in addition to the typical.
  776. if (in_array($method, $this->spoofedMethods))
  777. {
  778. $appendage .= $this->hidden('_method', $method);
  779. }
  780. // If the method is something other than GET we will go ahead and attach the
  781. // CSRF token to the form, as this can't hurt and is convenient to simply
  782. // always have available on every form the developers creates for them.
  783. if ($method != 'GET')
  784. {
  785. $appendage .= $this->token(array_get($this->csrfToken, 'name'), array_get($this->csrfToken, 'type'));
  786. }
  787. return $appendage;
  788. }
  789. /**
  790. * Get the ID attribute for a field name.
  791. *
  792. * @param string $name
  793. * @param array $attributes
  794. * @return string
  795. */
  796. public function getIdAttribute($name, $attributes)
  797. {
  798. if (array_key_exists('id', $attributes))
  799. {
  800. return $attributes['id'];
  801. }
  802. if (in_array($name, $this->labels))
  803. {
  804. return $name;
  805. }
  806. }
  807. /**
  808. * Get the value that should be assigned to the field.
  809. *
  810. * @param string $name
  811. * @param string $value
  812. * @return string
  813. */
  814. public function getValueAttribute($name, $value = null)
  815. {
  816. if (is_null($name))
  817. return $value;
  818. if (!is_null($this->old($name)))
  819. {
  820. return $this->old($name);
  821. }
  822. if (!is_null($value))
  823. return $value;
  824. if (isset($this->model))
  825. {
  826. return $this->getModelValueAttribute($name);
  827. }
  828. }
  829. /**
  830. * Get the model value that should be assigned to the field.
  831. *
  832. * @param string $name
  833. * @return string
  834. */
  835. protected function getModelValueAttribute($name)
  836. {
  837. if (is_object($this->model))
  838. {
  839. return object_get($this->model, $this->transformKey($name));
  840. }
  841. elseif (is_array($this->model))
  842. {
  843. return array_get($this->model, $this->transformKey($name));
  844. }
  845. }
  846. /**
  847. * Get a value from the session's old input.
  848. *
  849. * @param string $name
  850. * @return string
  851. */
  852. public function old($name)
  853. {
  854. if (isset($this->session))
  855. {
  856. return $this->session->getOldInput($this->transformKey($name));
  857. }
  858. }
  859. /**
  860. * Determine if the old input is empty.
  861. *
  862. * @return bool
  863. */
  864. public function oldInputIsEmpty()
  865. {
  866. return (isset($this->session) && count($this->session->getOldInput()) == 0);
  867. }
  868. /**
  869. * Transform key from array to dot syntax.
  870. *
  871. * @param string $key
  872. * @return string
  873. */
  874. protected function transformKey($key)
  875. {
  876. return str_replace(array('.', '[]', '[', ']'), array('_', '', '.', ''), $key);
  877. }
  878. /**
  879. * 数组转换成一个HTML属性字符串。
  880. *
  881. * @param array $attributes
  882. * @return string
  883. */
  884. public function attributes($attributes)
  885. {
  886. $html = array();
  887. // 假设我们的keys 和 value 是相同的,
  888. // 拿HTML“required”属性来说,假设是['required']数组,
  889. // 会已 required="required" 拼接起来,而不是用数字keys去拼接
  890. foreach ((array) $attributes as $key => $value)
  891. {
  892. $element = $this->attributeElement($key, $value);
  893. if (!is_null($element))
  894. $html[] = $element;
  895. }
  896. return count($html) > 0 ? ' ' . implode(' ', $html) : '';
  897. }
  898. /**
  899. * 拼接成一个属性。
  900. *
  901. * @param string $key
  902. * @param string $value
  903. * @return string
  904. */
  905. protected function attributeElement($key, $value)
  906. {
  907. if (is_numeric($key))
  908. $key = $value;
  909. if (!is_null($value))
  910. return $key . '="' . $value . '"';
  911. }
  912. }
  913. class Arr
  914. {
  915. /**
  916. * Determine whether the given value is array accessible.
  917. *
  918. * @param mixed $value
  919. * @return bool
  920. */
  921. public static function accessible($value)
  922. {
  923. return is_array($value) || $value instanceof ArrayAccess;
  924. }
  925. /**
  926. * Determine if the given key exists in the provided array.
  927. *
  928. * @param \ArrayAccess|array $array
  929. * @param string|int $key
  930. * @return bool
  931. */
  932. public static function exists($array, $key)
  933. {
  934. if ($array instanceof ArrayAccess)
  935. {
  936. return $array->offsetExists($key);
  937. }
  938. return array_key_exists($key, $array);
  939. }
  940. /**
  941. * Get an item from an array using "dot" notation.
  942. *
  943. * @param \ArrayAccess|array $array
  944. * @param string $key
  945. * @param mixed $default
  946. * @return mixed
  947. */
  948. public static function get($array, $key, $default = null)
  949. {
  950. if (!static::accessible($array))
  951. {
  952. return $default;
  953. }
  954. if (is_null($key))
  955. {
  956. return $array;
  957. }
  958. if (static::exists($array, $key))
  959. {
  960. return $array[$key];
  961. }
  962. foreach (explode('.', $key) as $segment)
  963. {
  964. if (static::accessible($array) && static::exists($array, $segment))
  965. {
  966. $array = $array[$segment];
  967. }
  968. else
  969. {
  970. return $default;
  971. }
  972. }
  973. return $array;
  974. }
  975. /**
  976. * Get all of the given array except for a specified array of items.
  977. *
  978. * @param array $array
  979. * @param array|string $keys
  980. * @return array
  981. */
  982. public static function except($array, $keys)
  983. {
  984. static::forget($array, $keys);
  985. return $array;
  986. }
  987. /**
  988. * Remove one or many array items from a given array using "dot" notation.
  989. *
  990. * @param array $array
  991. * @param array|string $keys
  992. * @return void
  993. */
  994. public static function forget(&$array, $keys)
  995. {
  996. $original = &$array;
  997. $keys = (array) $keys;
  998. if (count($keys) === 0)
  999. {
  1000. return;
  1001. }
  1002. foreach ($keys as $key)
  1003. {
  1004. // if the exact key exists in the top-level, remove it
  1005. if (static::exists($array, $key))
  1006. {
  1007. unset($array[$key]);
  1008. continue;
  1009. }
  1010. $parts = explode('.', $key);
  1011. // clean up before each pass
  1012. $array = &$original;
  1013. while (count($parts) > 1)
  1014. {
  1015. $part = array_shift($parts);
  1016. if (isset($array[$part]) && is_array($array[$part]))
  1017. {
  1018. $array = &$array[$part];
  1019. }
  1020. else
  1021. {
  1022. continue 2;
  1023. }
  1024. }
  1025. unset($array[array_shift($parts)]);
  1026. }
  1027. }
  1028. }
  1029. if (!function_exists('array_get'))
  1030. {
  1031. /**
  1032. * Get an item from an array using "dot" notation.
  1033. *
  1034. * @param \ArrayAccess|array $array
  1035. * @param string $key
  1036. * @param mixed $default
  1037. * @return mixed
  1038. */
  1039. function array_get($array, $key, $default = null)
  1040. {
  1041. return Arr::get($array, $key, $default);
  1042. }
  1043. }
  1044. if (!function_exists('e'))
  1045. {
  1046. /**
  1047. * Escape HTML special characters in a string.
  1048. *
  1049. *
  1050. * @return string
  1051. */
  1052. function e($value)
  1053. {
  1054. if (is_array($value))
  1055. {
  1056. $value = json_encode($value, JSON_UNESCAPED_UNICODE);
  1057. }
  1058. return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false);
  1059. }
  1060. }
  1061. if (!function_exists('array_except'))
  1062. {
  1063. /**
  1064. * Get all of the given array except for a specified array of items.
  1065. *
  1066. * @param array $array
  1067. * @param array|string $keys
  1068. * @return array
  1069. */
  1070. function array_except($array, $keys)
  1071. {
  1072. return Arr::except($array, $keys);
  1073. }
  1074. }