PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/form/instance.php

https://bitbucket.org/codeyash/bootstrap
PHP | 777 lines | 436 code | 94 blank | 247 comment | 51 complexity | 872156a224aa9c9b39d952ada0dd7424 MD5 | raw file
Possible License(s): MIT, Apache-2.0
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * Form Class
  15. *
  16. * Helper for creating forms with support for creating dynamic form objects.
  17. *
  18. * @package Fuel
  19. * @category Core
  20. */
  21. class Form_Instance
  22. {
  23. /**
  24. * Valid types for input tags (including HTML5)
  25. */
  26. protected static $_valid_inputs = array(
  27. 'button', 'checkbox', 'color', 'date', 'datetime',
  28. 'datetime-local', 'email', 'file', 'hidden', 'image',
  29. 'month', 'number', 'password', 'radio', 'range',
  30. 'reset', 'search', 'submit', 'tel', 'text', 'time',
  31. 'url', 'week'
  32. );
  33. /**
  34. * @var Fieldset
  35. */
  36. protected $fieldset;
  37. public function __construct($fieldset, array $config = array())
  38. {
  39. if ($fieldset instanceof Fieldset)
  40. {
  41. $fieldset->form($this);
  42. $this->fieldset = $fieldset;
  43. }
  44. else
  45. {
  46. $this->fieldset = \Fieldset::forge($fieldset, array('form_instance' => $this));
  47. }
  48. foreach ($config as $key => $val)
  49. {
  50. $this->set_config($key, $val);
  51. }
  52. }
  53. /**
  54. * Set form attribute
  55. *
  56. * @param string
  57. * @param mixed
  58. */
  59. public function set_attribute($key, $value)
  60. {
  61. $attributes = $this->get_config('form_attributes', array());
  62. $attributes[$key] = $value;
  63. $this->set_config('form_attributes', $attributes);
  64. return $this;
  65. }
  66. /**
  67. * Get form attribute
  68. *
  69. * @param string
  70. * @param mixed
  71. */
  72. public function get_attribute($key, $default = null)
  73. {
  74. $attributes = $this->get_config('form_attributes', array());
  75. return array_key_exists($key, $attributes) ? $attributes[$key] : $default;
  76. }
  77. /**
  78. * Magic method toString that will build this as a form
  79. *
  80. * @return string
  81. */
  82. public function __toString()
  83. {
  84. return $this->build();
  85. }
  86. /**
  87. * Create a form open tag
  88. *
  89. * @param string|array action string or array with more tag attribute settings
  90. * @return string
  91. */
  92. public function open($attributes = array(), array $hidden = array())
  93. {
  94. $attributes = ! is_array($attributes) ? array('action' => $attributes) : $attributes;
  95. // If there is still no action set, Form-post
  96. if( ! array_key_exists('action', $attributes) or $attributes['action'] === null)
  97. {
  98. $attributes['action'] = \Uri::main();
  99. }
  100. // If not a full URL, create one
  101. elseif ( ! strpos($attributes['action'], '://'))
  102. {
  103. $attributes['action'] = \Uri::create($attributes['action']);
  104. }
  105. if (empty($attributes['accept-charset']))
  106. {
  107. $attributes['accept-charset'] = strtolower(\Fuel::$encoding);
  108. }
  109. // If method is empty, use POST
  110. ! empty($attributes['method']) || $attributes['method'] = $this->get_config('form_method', 'post');
  111. $form = '<form';
  112. foreach ($attributes as $prop => $value)
  113. {
  114. $form .= ' '.$prop.'="'.$value.'"';
  115. }
  116. $form .= '>';
  117. // Add hidden fields when given
  118. foreach ($hidden as $field => $value)
  119. {
  120. $form .= PHP_EOL.$this->hidden($field, $value);
  121. }
  122. return $form;
  123. }
  124. /**
  125. * Create a form close tag
  126. *
  127. * @return string
  128. */
  129. public function close()
  130. {
  131. return '</form>';
  132. }
  133. /**
  134. * Create a fieldset open tag
  135. *
  136. * @param array array with tag attribute settings
  137. * @param string string for the fieldset legend
  138. * @return string
  139. */
  140. public function fieldset_open($attributes = array(), $legend = null)
  141. {
  142. $fieldset_open = '<fieldset ' . array_to_attr($attributes) . ' >';
  143. ! is_null($legend) and $attributes['legend'] = $legend;
  144. if ( ! empty($attributes['legend']))
  145. {
  146. $fieldset_open.= "\n<legend>".$attributes['legend']."</legend>";
  147. }
  148. return $fieldset_open;
  149. }
  150. /**
  151. * Create a fieldset close tag
  152. *
  153. * @return string
  154. */
  155. public function fieldset_close()
  156. {
  157. return '</fieldset>';
  158. }
  159. /**
  160. * Create a form input
  161. *
  162. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  163. * @param string
  164. * @param array
  165. * @return string
  166. */
  167. public function input($field, $value = null, array $attributes = array())
  168. {
  169. if (is_array($field))
  170. {
  171. $attributes = $field;
  172. ! array_key_exists('value', $attributes) and $attributes['value'] = '';
  173. }
  174. else
  175. {
  176. $attributes['name'] = (string) $field;
  177. $attributes['value'] = (string) $value;
  178. }
  179. $attributes['type'] = empty($attributes['type']) ? 'text' : $attributes['type'];
  180. if ( ! in_array($attributes['type'], static::$_valid_inputs))
  181. {
  182. throw new \InvalidArgumentException(sprintf('"%s" is not a valid input type.', $attributes['type']));
  183. }
  184. if ($this->get_config('prep_value', true) && empty($attributes['dont_prep']))
  185. {
  186. $attributes['value'] = $this->prep_value($attributes['value']);
  187. }
  188. unset($attributes['dont_prep']);
  189. if (empty($attributes['id']) && $this->get_config('auto_id', false) == true)
  190. {
  191. $attributes['id'] = $this->get_config('auto_id_prefix', 'form_').$attributes['name'];
  192. }
  193. $tag = ! empty($attributes['tag']) ? $attributes['tag'] : 'input';
  194. unset($attributes['tag']);
  195. return html_tag($tag, $this->attr_to_string($attributes));
  196. }
  197. /**
  198. * Create a hidden field
  199. *
  200. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  201. * @param string
  202. * @param array
  203. * @return string
  204. */
  205. public function hidden($field, $value = null, array $attributes = array())
  206. {
  207. if (is_array($field))
  208. {
  209. $attributes = $field;
  210. }
  211. else
  212. {
  213. $attributes['name'] = (string) $field;
  214. $attributes['value'] = (string) $value;
  215. }
  216. $attributes['type'] = 'hidden';
  217. return $this->input($attributes);
  218. }
  219. /**
  220. * Create a password input field
  221. *
  222. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  223. * @param string
  224. * @param array
  225. * @return string
  226. */
  227. public function password($field, $value = null, array $attributes = array())
  228. {
  229. if (is_array($field))
  230. {
  231. $attributes = $field;
  232. }
  233. else
  234. {
  235. $attributes['name'] = (string) $field;
  236. $attributes['value'] = (string) $value;
  237. }
  238. $attributes['type'] = 'password';
  239. return $this->input($attributes);
  240. }
  241. /**
  242. * Create a radio button
  243. *
  244. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  245. * @param string
  246. * @param mixed either attributes (array) or bool/string to set checked status
  247. * @param array
  248. * @return string
  249. */
  250. public function radio($field, $value = null, $checked = null, array $attributes = array())
  251. {
  252. if (is_array($field))
  253. {
  254. $attributes = $field;
  255. }
  256. else
  257. {
  258. is_array($checked) and $attributes = $checked;
  259. $attributes['name'] = (string) $field;
  260. $attributes['value'] = (string) $value;
  261. # Added for 1.2 to allow checked true/false. in 3rd argument, used to be attributes
  262. if ( ! is_array($checked))
  263. {
  264. // If it's true, then go for it
  265. if (is_bool($checked) and $checked === true)
  266. {
  267. $attributes['checked'] = 'checked';
  268. }
  269. // Otherwise, if the string/number/whatever matches then do it
  270. elseif (is_scalar($checked) and $checked == $value)
  271. {
  272. $attributes['checked'] = 'checked';
  273. }
  274. }
  275. }
  276. $attributes['type'] = 'radio';
  277. return $this->input($attributes);
  278. }
  279. /**
  280. * Create a checkbox
  281. *
  282. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  283. * @param string
  284. * @param mixed either attributes (array) or bool/string to set checked status
  285. * @param array
  286. * @return string
  287. */
  288. public function checkbox($field, $value = null, $checked = null, array $attributes = array())
  289. {
  290. if (is_array($field))
  291. {
  292. $attributes = $field;
  293. }
  294. else
  295. {
  296. is_array($checked) and $attributes = $checked;
  297. $attributes['name'] = (string) $field;
  298. $attributes['value'] = (string) $value;
  299. # Added for 1.2 to allow checked true/false. in 3rd argument, used to be attributes
  300. if ( ! is_array($checked))
  301. {
  302. // If it's true, then go for it
  303. if (is_bool($checked) and $checked === true)
  304. {
  305. $attributes['checked'] = 'checked';
  306. }
  307. // Otherwise, if the string/number/whatever matches then do it
  308. elseif (is_scalar($checked) and $checked == $value)
  309. {
  310. $attributes['checked'] = 'checked';
  311. }
  312. }
  313. }
  314. $attributes['type'] = 'checkbox';
  315. return $this->input($attributes);
  316. }
  317. /**
  318. * Create a file upload input field
  319. *
  320. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  321. * @param array
  322. * @return string
  323. */
  324. public function file($field, array $attributes = array())
  325. {
  326. if (is_array($field))
  327. {
  328. $attributes = $field;
  329. }
  330. else
  331. {
  332. $attributes['name'] = (string) $field;
  333. }
  334. $attributes['type'] = 'file';
  335. return $this->input($attributes);
  336. }
  337. /**
  338. * Create a button
  339. *
  340. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  341. * @param string
  342. * @param array
  343. * @return string
  344. */
  345. public function button($field, $value = null, array $attributes = array())
  346. {
  347. if (is_array($field))
  348. {
  349. $attributes = $field;
  350. $value = isset($attributes['value']) ? $attributes['value'] : $value;
  351. }
  352. else
  353. {
  354. $attributes['name'] = (string) $field;
  355. $value = isset($value) ? $value : $attributes['name'];
  356. }
  357. return html_tag('button', $this->attr_to_string($attributes), $value);
  358. }
  359. /**
  360. * Create a reset button
  361. *
  362. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  363. * @param string
  364. * @param array
  365. * @return string
  366. */
  367. public function reset($field = 'reset', $value = 'Reset', array $attributes = array())
  368. {
  369. if (is_array($field))
  370. {
  371. $attributes = $field;
  372. }
  373. else
  374. {
  375. $attributes['name'] = (string) $field;
  376. $attributes['value'] = (string) $value;
  377. }
  378. $attributes['type'] = 'reset';
  379. return $this->input($attributes);
  380. }
  381. /**
  382. * Create a submit button
  383. *
  384. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  385. * @param string
  386. * @param array
  387. * @return string
  388. */
  389. public function submit($field = 'submit', $value = 'Submit', array $attributes = array())
  390. {
  391. if (is_array($field))
  392. {
  393. $attributes = $field;
  394. }
  395. else
  396. {
  397. $attributes['name'] = (string) $field;
  398. $attributes['value'] = (string) $value;
  399. }
  400. $attributes['type'] = 'submit';
  401. return $this->input($attributes);
  402. }
  403. /**
  404. * Create a textarea field
  405. *
  406. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  407. * @param string
  408. * @param array
  409. * @return string
  410. */
  411. public function textarea($field, $value = null, array $attributes = array())
  412. {
  413. if (is_array($field))
  414. {
  415. $attributes = $field;
  416. }
  417. else
  418. {
  419. $attributes['name'] = (string) $field;
  420. $attributes['value'] = (string) $value;
  421. }
  422. $value = empty($attributes['value']) ? '' : $attributes['value'];
  423. unset($attributes['value']);
  424. if ($this->get_config('prep_value', true) && empty($attributes['dont_prep']))
  425. {
  426. $value = $this->prep_value($value);
  427. }
  428. unset($attributes['dont_prep']);
  429. if (empty($attributes['id']) && $this->get_config('auto_id', false) == true)
  430. {
  431. $attributes['id'] = $this->get_config('auto_id_prefix', '').$attributes['name'];
  432. }
  433. return html_tag('textarea', $this->attr_to_string($attributes), $value);
  434. }
  435. /**
  436. * Select
  437. *
  438. * Generates a html select element based on the given parameters
  439. *
  440. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  441. * @param string selected value(s)
  442. * @param array array of options and option groups
  443. * @param array
  444. * @return string
  445. */
  446. public function select($field, $values = null, array $options = array(), array $attributes = array())
  447. {
  448. if (is_array($field))
  449. {
  450. $attributes = $field;
  451. if ( ! isset($attributes['selected']))
  452. {
  453. $attributes['selected'] = ! isset($attributes['value']) ? null : $attributes['value'];
  454. }
  455. }
  456. else
  457. {
  458. $attributes['name'] = (string) $field;
  459. $attributes['selected'] = $values;
  460. $attributes['options'] = $options;
  461. }
  462. unset($attributes['value']);
  463. if ( ! isset($attributes['options']) || ! is_array($attributes['options']))
  464. {
  465. throw new \InvalidArgumentException(sprintf('Select element "%s" is either missing the "options" or "options" is not array.', $attributes['name']));
  466. }
  467. // Get the options then unset them from the array
  468. $options = $attributes['options'];
  469. unset($attributes['options']);
  470. // Get the selected options then unset it from the array
  471. // and make sure they're all strings to avoid type conversions
  472. $selected = ! isset($attributes['selected']) ? array() : array_map(function($a) { return (string) $a; }, array_values((array) $attributes['selected']));
  473. unset($attributes['selected']);
  474. // workaround to access the current object context in the closure
  475. $current_obj =& $this;
  476. // closure to recusively process the options array
  477. $listoptions = function (array $options, $selected, $level = 1) use (&$listoptions, &$current_obj, &$attributes)
  478. {
  479. $input = PHP_EOL;
  480. foreach ($options as $key => $val)
  481. {
  482. if (is_array($val))
  483. {
  484. $optgroup = $listoptions($val, $selected, $level + 1);
  485. $optgroup .= str_repeat("\t", $level);
  486. $input .= str_repeat("\t", $level).html_tag('optgroup', array('label' => $key , 'style' => 'text-indent: '.(10*($level-1)).'px;'), $optgroup).PHP_EOL;
  487. }
  488. else
  489. {
  490. $opt_attr = array('value' => $key, 'style' => 'text-indent: '.(10*($level-1)).'px;');
  491. (in_array((string)$key, $selected, true)) && $opt_attr[] = 'selected';
  492. $input .= str_repeat("\t", $level);
  493. $opt_attr['value'] = ($current_obj->get_config('prep_value', true) && empty($attributes['dont_prep'])) ?
  494. $current_obj->prep_value($opt_attr['value']) : $opt_attr['value'];
  495. $val = ($current_obj->get_config('prep_value', true) && empty($attributes['dont_prep'])) ?
  496. $current_obj->prep_value($val) : $val;
  497. $input .= html_tag('option', $opt_attr, $val).PHP_EOL;
  498. }
  499. }
  500. unset($attributes['dont_prep']);
  501. return $input;
  502. };
  503. // generate the select options list
  504. $input = $listoptions($options, $selected).str_repeat("\t", 0);
  505. if (empty($attributes['id']) && $this->get_config('auto_id', false) == true)
  506. {
  507. $attributes['id'] = $this->get_config('auto_id_prefix', '').$attributes['name'];
  508. }
  509. // if it's a multiselect, make sure the name is an array
  510. if (isset($attributes['multiple']) and substr($attributes['name'],-2) != '[]')
  511. {
  512. $attributes['name'] .= '[]';
  513. }
  514. return html_tag('select', $this->attr_to_string($attributes), $input);
  515. }
  516. /**
  517. * Create a label field
  518. *
  519. * @param string|array either fieldname or full attributes array (when array other params are ignored)
  520. * @param string
  521. * @param array
  522. * @return string
  523. */
  524. public function label($label, $id = null, array $attributes = array())
  525. {
  526. if (is_array($label))
  527. {
  528. $attributes = $label;
  529. $label = $attributes['label'];
  530. isset($attributes['id']) and $id = $attributes['id'];
  531. }
  532. if (empty($attributes['for']) and $this->get_config('auto_id', false) == true)
  533. {
  534. $attributes['for'] = $this->get_config('auto_id_prefix', 'form_').$id;
  535. }
  536. unset($attributes['label']);
  537. return html_tag('label', $attributes, \Lang::get($label, array(), false) ?: $label);
  538. }
  539. /**
  540. * Prep Value
  541. *
  542. * Prepares the value for display in the form
  543. *
  544. * @param string
  545. * @return string
  546. */
  547. public function prep_value($value)
  548. {
  549. $value = \Security::htmlentities($value, ENT_QUOTES);
  550. return $value;
  551. }
  552. /**
  553. * Attr to String
  554. *
  555. * Wraps the global attributes function and does some form specific work
  556. *
  557. * @param array $attr
  558. * @return string
  559. */
  560. protected function attr_to_string($attr)
  561. {
  562. unset($attr['label']);
  563. return array_to_attr($attr);
  564. }
  565. // fieldset related methods
  566. /**
  567. * Returns the related fieldset
  568. *
  569. * @return Fieldset
  570. */
  571. public function fieldset()
  572. {
  573. return $this->fieldset;
  574. }
  575. /**
  576. * Build & template individual field
  577. *
  578. * @param string|Fieldset_Field field instance or name of a field in this form's fieldset
  579. * @return string
  580. * @depricated until v1.2
  581. */
  582. public function build_field($field)
  583. {
  584. ! $field instanceof Fieldset_Field && $field = $this->field($field);
  585. return $field->build();
  586. }
  587. /**
  588. * Add a CSRF token and a validation rule to check it
  589. */
  590. public function add_csrf()
  591. {
  592. $this->add(\Config::get('security.csrf_token_key', 'fuel_csrf_token'), 'CSRF Token')
  593. ->set_type('hidden')
  594. ->set_value(\Security::fetch_token())
  595. ->add_rule(array('Security', 'check_token'));
  596. return $this;
  597. }
  598. /**
  599. * Sets a config value on the fieldset
  600. *
  601. * @param string
  602. * @param mixed
  603. * @return Fieldset this, to allow chaining
  604. */
  605. public function set_config($config, $value = null)
  606. {
  607. $this->fieldset->set_config($config, $value);
  608. return $this;
  609. }
  610. /**
  611. * Get a single or multiple config values by key
  612. *
  613. * @param string|array a single key or multiple in an array, empty to fetch all
  614. * @param mixed default output when config wasn't set
  615. * @return mixed|array a single config value or multiple in an array when $key input was an array
  616. */
  617. public function get_config($key = null, $default = null)
  618. {
  619. if ($key === null)
  620. {
  621. return $this->fieldset->get_config();
  622. }
  623. if (is_array($key))
  624. {
  625. $output = array();
  626. foreach ($key as $k)
  627. {
  628. $output[$k] = $this->fieldset->get_config($k, null) !== null
  629. ? $this->fieldset->get_config($k, $default)
  630. : \Config::get('form.'.$k, $default);
  631. }
  632. return $output;
  633. }
  634. return $this->fieldset->get_config($key, null) !== null
  635. ? $this->fieldset->get_config($key, $default)
  636. : \Config::get('form.'.$key, $default);
  637. }
  638. /**
  639. * Alias for $this->fieldset->build()
  640. */
  641. public function build($action = null)
  642. {
  643. return $this->fieldset()->build($action);
  644. }
  645. /**
  646. * Alias for $this->fieldset->add()
  647. */
  648. public function add($name, $label = '', array $attributes = array(), array $rules = array())
  649. {
  650. return $this->fieldset->add($name, $label, $attributes, $rules);
  651. }
  652. /**
  653. * Alias for $this->fieldset->add_model()
  654. *
  655. * @return Validation this, to allow chaining
  656. */
  657. public function add_model($class, $instance = null, $method = 'set_form_fields')
  658. {
  659. $this->fieldset->add_model($class, $instance, $method);
  660. return $this;
  661. }
  662. /**
  663. * Alias for $this->fieldset->field()
  664. */
  665. public function field($name = null, $flatten = false)
  666. {
  667. return $this->fieldset->field($name, $flatten);
  668. }
  669. /**
  670. * Alias for $this->fieldset->populate() for this fieldset
  671. */
  672. public function populate($input, $repopulate = false)
  673. {
  674. $this->fieldset->populate($input, $repopulate);
  675. }
  676. /**
  677. * Alias for $this->fieldset->repopulate() for this fieldset
  678. */
  679. public function repopulate()
  680. {
  681. $this->fieldset->repopulate();
  682. }
  683. }