PageRenderTime 61ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/library/spoon/form/dropdown.php

https://github.com/JonckheereM/Public
PHP | 679 lines | 275 code | 118 blank | 286 comment | 78 complexity | 3a0ba2a1f7e8070eda6ce511df033dcb MD5 | raw file
  1. <?php
  2. /**
  3. * Spoon Library
  4. *
  5. * This source file is part of the Spoon Library. More information,
  6. * documentation and tutorials can be found @ http://www.spoon-library.com
  7. *
  8. * @package spoon
  9. * @subpackage form
  10. *
  11. *
  12. * @author Davy Hellemans <davy@spoon-library.com>
  13. * @author Tijs Verkoyen <tijs@spoon-library.com>
  14. * @author Dave Lens <dave@spoon-library.com>
  15. * @since 0.1.1
  16. */
  17. /**
  18. * Generates a single or multiple dropdown menu.
  19. *
  20. * @package spoon
  21. * @subpackage form
  22. *
  23. *
  24. * @author Davy Hellemans <davy@spoon-library.com>
  25. * @since 0.1.1
  26. */
  27. class SpoonFormDropdown extends SpoonFormAttributes
  28. {
  29. /**
  30. * Should we allow external data
  31. *
  32. * @var bool
  33. */
  34. private $allowExternalData = false;
  35. /**
  36. * Class attribute on error
  37. *
  38. * @var string
  39. */
  40. protected $classError;
  41. /**
  42. * Default element on top of the dropdown (value, label)
  43. *
  44. * @var array
  45. */
  46. private $defaultElement = array();
  47. /**
  48. * Errors stack
  49. *
  50. * @var string
  51. */
  52. protected $errors;
  53. /**
  54. * List of option specific attributes
  55. *
  56. * @var array
  57. */
  58. private $optionAttributes = array();
  59. /**
  60. * Contains optgroups
  61. *
  62. * @var bool
  63. */
  64. private $optionGroups = false;
  65. /**
  66. * Default selected item(s)
  67. *
  68. * @var mixed
  69. */
  70. private $selected;
  71. /**
  72. * Whether you can select multiple elements
  73. *
  74. * @var bool
  75. */
  76. private $single = true;
  77. /**
  78. * Initial values
  79. *
  80. * @var array
  81. */
  82. protected $values = array();
  83. /**
  84. * Class constructor.
  85. *
  86. * @return void
  87. * @param string $name
  88. * @param array $values
  89. * @param mixed[optional] $selected
  90. * @param bool[optional] $multipleSelection
  91. * @param string[optional] $class
  92. * @param string[optional] $classError
  93. */
  94. public function __construct($name, array $values, $selected = null, $multipleSelection = false, $class = 'inputDropdown', $classError = 'inputDropdownError')
  95. {
  96. // obligates fields
  97. $this->attributes['id'] = SpoonFilter::toCamelCase($name, '_', true);
  98. $this->attributes['name'] = (string) $name;
  99. $this->setValues($values);
  100. // update reserved attributes
  101. $this->reservedAttributes[] = 'multiple';
  102. // custom optional fields
  103. $this->single = !(bool) $multipleSelection;
  104. if($selected !== null) $this->setSelected($selected);
  105. $this->attributes['class'] = (string) $class;
  106. $this->classError = (string) $classError;
  107. $this->attributes['size'] = 1;
  108. }
  109. /**
  110. * Adds an error to the error stack.
  111. *
  112. * @return void
  113. * @param string $error
  114. */
  115. public function addError($error)
  116. {
  117. $this->errors .= (string) $error;
  118. }
  119. /**
  120. * Retrieves the custom attributes as HTML.
  121. *
  122. * @return string
  123. * @param array $variables
  124. */
  125. protected function getAttributesHTML(array $variables)
  126. {
  127. // init var
  128. $html = '';
  129. // multiple
  130. if(!$this->single) $this->attributes['multiple'] = 'multiple';
  131. // loop attributes
  132. foreach($this->attributes as $key => $value)
  133. {
  134. // class?
  135. if($key == 'class') $html .= $this->getClassHTML();
  136. // name
  137. elseif($key == 'name' && !$this->single) $html .= ' name[]="'. $value .'"';
  138. // other elements
  139. else $html .= ' '. $key .'="'. str_replace(array_keys($variables), array_values($variables), $value) .'"';
  140. }
  141. return $html;
  142. }
  143. /**
  144. * Retrieve the class HTML.
  145. *
  146. * @return string
  147. */
  148. protected function getClassHTML()
  149. {
  150. // default value
  151. $value = '';
  152. // has errors
  153. if($this->errors != '')
  154. {
  155. // class & classOnError defined
  156. if($this->attributes['class'] != '' && $this->classError != '') $value = ' class="'. $this->attributes['class'] .' '. $this->classError .'"';
  157. // only class defined
  158. elseif($this->attributes['class'] != '') $value = ' class="'. $this->attributes['class'] .'"';
  159. // only error defined
  160. elseif($this->classError != '') $value = ' class="'. $this->classError .'"';
  161. }
  162. // no errors
  163. else
  164. {
  165. // class defined
  166. if($this->attributes['class'] != '') $value = ' class="'. $this->attributes['class'] .'"';
  167. }
  168. return $value;
  169. }
  170. /**
  171. * Retrieve the initial value.
  172. *
  173. * @return string
  174. */
  175. public function getDefaultValue($key = null)
  176. {
  177. // custom key
  178. if($key !== null)
  179. {
  180. // does this key exist?
  181. if(array_key_exists((string) $key, $this->values)) return $this->values[$key];
  182. // something went wrong
  183. throw new SpoonFormException('You can\'t fetch the value ('. $key .') from the dropdown values based on its key if it doesn\'t exist.');
  184. }
  185. // everything by default
  186. return $this->values;
  187. }
  188. /**
  189. * Retrieve the errors.
  190. *
  191. * @return string
  192. */
  193. public function getErrors()
  194. {
  195. return $this->errors;
  196. }
  197. /**
  198. * Retrieve the list of option specific attributes by its' value.
  199. *
  200. * @return array
  201. * @param string $value
  202. */
  203. public function getOptionAttributes($value)
  204. {
  205. return (isset($this->optionAttributes[(string) $value])) ? $this->optionAttributes[(string) $value] : array();
  206. }
  207. /**
  208. * Retrieves the selected item(s).
  209. *
  210. * @return mixed
  211. */
  212. public function getSelected()
  213. {
  214. /**
  215. * If we want to know what elements are selected, we first need
  216. * to make sure that the $_POST/$_GET array is taken into consideration.
  217. */
  218. // form submitted
  219. if($this->isSubmitted())
  220. {
  221. // post/get data
  222. $data = $this->getMethod(true);
  223. // multiple
  224. if(!$this->single)
  225. {
  226. // field has been submitted
  227. if(isset($data[$this->attributes['name']]) && is_array($data[$this->attributes['name']]) && count($data[$this->attributes['name']]) != 0)
  228. {
  229. // reset selected
  230. $this->selected = array();
  231. // loop elements and add the value to the array
  232. foreach($data[$this->attributes['name']] as $label => $value) $this->selected[] = $value;
  233. }
  234. }
  235. // single (has been submitted)
  236. elseif(isset($data[$this->attributes['name']]) && $data[$this->attributes['name']] != '') $this->selected = (string) $data[$this->attributes['name']];
  237. }
  238. return $this->selected;
  239. }
  240. /**
  241. * Retrieve the value(s).
  242. *
  243. * @return mixed
  244. */
  245. public function getValue()
  246. {
  247. // post/get data
  248. $data = $this->getMethod(true);
  249. // default values
  250. $values = $this->values;
  251. // submitted field
  252. if($this->isSubmitted() && isset($data[$this->attributes['name']]))
  253. {
  254. // option groups
  255. if($this->optionGroups) $values = $data[$this->attributes['name']];
  256. // no option groups
  257. else
  258. {
  259. // multiple selection allowed
  260. if(!$this->single)
  261. {
  262. // reset
  263. $values = array();
  264. // loop choices
  265. foreach((array) $data[$this->attributes['name']] as $value)
  266. {
  267. // external data is allowed
  268. if($this->allowExternalData) $values[] = $value;
  269. // external data is not allowed
  270. else
  271. {
  272. if(isset($this->values[$value]) && !in_array($value, $values)) $values[] = $value;
  273. }
  274. }
  275. }
  276. // ony single selection
  277. else
  278. {
  279. // rest
  280. $values = null;
  281. // external data is allowed
  282. if($this->allowExternalData) $values = (string) $data[$this->attributes['name']];
  283. // external data is NOT allowed
  284. else
  285. {
  286. if(isset($this->values[(string) $data[$this->attributes['name']]])) $values = (string) $data[$this->attributes['name']];
  287. }
  288. }
  289. }
  290. }
  291. // form was submitted, but the field was not
  292. elseif($this->isSubmitted()) return null;
  293. // return calculated values
  294. return $values;
  295. }
  296. /**
  297. * Checks if this field was submitted & contains one more values.
  298. *
  299. * @return bool
  300. * @param string[optional] $error
  301. */
  302. public function isFilled($error = null)
  303. {
  304. // form submitted
  305. if($this->isSubmitted())
  306. {
  307. // something went wrong
  308. if($this->getValue() === null)
  309. {
  310. if($error !== null) $this->setError($error);
  311. return false;
  312. }
  313. // no problems
  314. return true;
  315. }
  316. // not submitted
  317. return false;
  318. }
  319. /**
  320. * Parses the html for this dropdown.
  321. *
  322. * @return string
  323. * @param SpoonTemplate[optional] $template
  324. */
  325. public function parse(SpoonTemplate $template = null)
  326. {
  327. // name is required
  328. if($this->attributes['name'] == '') throw new SpoonFormException('A name is required for a dropdown menu. Please provide a name.');
  329. // name?
  330. if(!$this->single) $this->attributes['name'] .= '[]';
  331. // init var
  332. $selected = $this->getSelected();
  333. // start html generation
  334. $output = "\r\n" . '<select';
  335. // add attributes
  336. $output .= $this->getAttributesHTML(array('[id]' => $this->attributes['id'], '[name]' => $this->attributes['name']));
  337. // end select tag
  338. $output .= ">\r\n";
  339. // default element?
  340. if(count($this->defaultElement) != 0)
  341. {
  342. // create option
  343. $output .= "\t". '<option value="'. $this->defaultElement[1] .'"';
  344. // multiple
  345. if(!$this->single)
  346. {
  347. // if the value is within the selected items array
  348. if(is_array($selected) && count($selected) != 0 && in_array($this->defaultElement[1], $selected)) $output .= ' selected="selected"';
  349. }
  350. // single
  351. else
  352. {
  353. // if the current value is equal to the submitted value
  354. if($this->defaultElement[1] == $selected && $selected !== null) $output .= ' selected="selected"';
  355. }
  356. // end option
  357. $output .= '>'. $this->defaultElement[0] ."</option>\r\n";
  358. }
  359. // has option groups
  360. if($this->optionGroups)
  361. {
  362. foreach($this->values as $groupName => $group)
  363. {
  364. // create optgroup
  365. $output .= "\t" .'<optgroup label="'. $groupName .'">'."\n";
  366. // loop valuesgoo
  367. foreach($group as $value => $label)
  368. {
  369. // create option
  370. $output .= "\t\t" . '<option value="'. $value .'"';
  371. // multiple
  372. if(!$this->single)
  373. {
  374. // if the value is within the selected items array
  375. if(is_array($selected) && count($selected) != 0 && in_array($value, $selected)) $output .= ' selected="selected"';
  376. }
  377. // single
  378. else
  379. {
  380. // if the current value is equal to the submitted value
  381. if($value == $selected) $output .= ' selected="selected"';
  382. }
  383. // add custom attributes
  384. if(isset($this->optionAttributes[(string) $value]))
  385. {
  386. // loop each attribute
  387. foreach($this->optionAttributes[(string) $value] as $attrKey => $attrValue)
  388. {
  389. // add to the output
  390. $output .= ' '. $attrKey .'="'. $attrValue .'"';
  391. }
  392. }
  393. // end option
  394. $output .= ">$label</option>\r\n";
  395. }
  396. // end optgroup
  397. $output .= "\t" .'</optgroup>'."\n";
  398. }
  399. }
  400. // regular dropdown
  401. else
  402. {
  403. // loop values
  404. foreach($this->values as $value => $label)
  405. {
  406. // create option
  407. $output .= "\t". '<option value="'. $value .'"';
  408. // multiple
  409. if(!$this->single)
  410. {
  411. // if the value is within the selected items array
  412. if(is_array($selected) && count($selected) != 0 && in_array($value, $selected)) $output .= ' selected="selected"';
  413. }
  414. // single
  415. else
  416. {
  417. // if the current value is equal to the submitted value
  418. if($this->getSelected() !== null && $value == $selected) $output .= ' selected="selected"';
  419. }
  420. // add custom attributes
  421. if(isset($this->optionAttributes[(string) $value]))
  422. {
  423. // loop each attribute
  424. foreach($this->optionAttributes[(string) $value] as $attrKey => $attrValue)
  425. {
  426. // add to the output
  427. $output .= ' '. $attrKey .'="'. $attrValue .'"';
  428. }
  429. }
  430. // end option
  431. $output .= ">$label</option>\r\n";
  432. }
  433. }
  434. // end html
  435. $output .= "</select>\r\n";
  436. // parse to template
  437. if($template !== null)
  438. {
  439. $template->assign('ddm'. SpoonFilter::toCamelCase($this->attributes['name']), $output);
  440. $template->assign('ddm'. SpoonFilter::toCamelCase($this->attributes['name']) .'Error', ($this->errors!= '') ? '<span class="formError">'. $this->errors .'</span>' : '');
  441. }
  442. return $output;
  443. }
  444. /**
  445. * Should we allow external data to be added.
  446. *
  447. * @return void
  448. * @param bool[optional] $on
  449. */
  450. public function setAllowExternalData($on = true)
  451. {
  452. $this->allowExternalData = (bool) $on;
  453. }
  454. /**
  455. * Sets the default element (top of the dropdown).
  456. *
  457. * @return void
  458. * @param string $label
  459. * @param string[optional] $value
  460. */
  461. public function setDefaultElement($label, $value = null)
  462. {
  463. $this->defaultElement = array((string) $label, (string) $value);
  464. }
  465. /**
  466. * Overwrites the error stack.
  467. *
  468. * @return void
  469. * @param string $error
  470. */
  471. public function setError($error)
  472. {
  473. $this->errors = (string) $error;
  474. }
  475. /**
  476. * Sets custom option attributes for a specific value.
  477. *
  478. * @return void
  479. * @param string $value
  480. * @param array $attributes
  481. */
  482. public function setOptionAttributes($value, array $attributes)
  483. {
  484. // set each attribute
  485. foreach($attributes as $attrKey => $attrValue)
  486. {
  487. $this->optionAttributes[(string) $value][(string) $attrKey] = (string) $attrValue;
  488. }
  489. }
  490. /**
  491. * Whether you can select one or more items.
  492. *
  493. * @return void
  494. * @param bool[optional] $single
  495. */
  496. public function setSingle($single = true)
  497. {
  498. $this->single = (bool) $single;
  499. }
  500. /**
  501. * Set the default selected item(s).
  502. *
  503. * @return void
  504. * @param mixed $selected
  505. */
  506. public function setSelected($selected)
  507. {
  508. // an array
  509. if(is_array($selected))
  510. {
  511. // may NOT be single
  512. if($this->single) throw new SpoonFormException('The "selected" argument must be a string, when you create a "single" dropdown');
  513. // arguments are fine
  514. foreach($selected as $item) $this->selected[] = (string) $item;
  515. }
  516. // other types
  517. else
  518. {
  519. // single type
  520. if($this->single) $this->selected = (string) $selected;
  521. // multiple selections
  522. else $this->selected[] = (string) $selected;
  523. }
  524. }
  525. /**
  526. * Sets the values for this dropdown menu.
  527. *
  528. * @return void
  529. * @param array $values
  530. */
  531. private function setValues(array $values)
  532. {
  533. // has not items
  534. if(count($values) == 0) throw new SpoonFormException('The array with values contains no items.');
  535. // check the first element
  536. foreach($values as $value)
  537. {
  538. // dropdownfield with optgroups?
  539. $this->optionGroups = (is_array($value)) ? true : false;
  540. // break the loop
  541. break;
  542. }
  543. // has option groups
  544. if($this->optionGroups)
  545. {
  546. // loop each group
  547. foreach($values as $groupName => $options)
  548. {
  549. // loop each option
  550. foreach($options as $key => $value) $this->values[$groupName][$key] = $value;
  551. }
  552. }
  553. // no option groups
  554. else
  555. {
  556. // has items
  557. foreach($values as $label => $value) $this->values[$label] = $value;
  558. }
  559. }
  560. }
  561. ?>