select.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Adam Daniel <adaniel1@eesus.jnj.com> |
  17. // | Bertrand Mansion <bmansion@mamasam.com> |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: select.php 12243 2007-05-02 21:00:52Z yannoo $
  21. require_once('HTML/QuickForm/element.php');
  22. /**
  23. * Class to dynamically create an HTML SELECT
  24. *
  25. * @author Adam Daniel <adaniel1@eesus.jnj.com>
  26. * @author Bertrand Mansion <bmansion@mamasam.com>
  27. * @version 1.0
  28. * @since PHP4.04pl1
  29. * @access public
  30. */
  31. class HTML_QuickForm_select extends HTML_QuickForm_element {
  32. // {{{ properties
  33. /**
  34. * Contains the select options
  35. *
  36. * @var array
  37. * @since 1.0
  38. * @access private
  39. */
  40. var $_options = array();
  41. /**
  42. * Default values of the SELECT
  43. *
  44. * @var string
  45. * @since 1.0
  46. * @access private
  47. */
  48. var $_values = null;
  49. // }}}
  50. // {{{ constructor
  51. /**
  52. * Class constructor
  53. *
  54. * @param string Select name attribute
  55. * @param mixed Label(s) for the select
  56. * @param mixed Data to be used to populate options
  57. * @param mixed Either a typical HTML attribute string or an associative array
  58. * @since 1.0
  59. * @access public
  60. * @return void
  61. */
  62. function HTML_QuickForm_select($elementName=null, $elementLabel=null, $options=null, $attributes=null)
  63. {
  64. HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
  65. $this->_persistantFreeze = true;
  66. $this->_type = 'select';
  67. if (isset($options)) {
  68. $this->load($options);
  69. }
  70. } //end constructor
  71. // }}}
  72. // {{{ apiVersion()
  73. /**
  74. * Returns the current API version
  75. *
  76. * @since 1.0
  77. * @access public
  78. * @return double
  79. */
  80. function apiVersion()
  81. {
  82. return 2.3;
  83. } //end func apiVersion
  84. // }}}
  85. // {{{ setSelected()
  86. /**
  87. * Sets the default values of the select box
  88. *
  89. * @param mixed $values Array or comma delimited string of selected values
  90. * @since 1.0
  91. * @access public
  92. * @return void
  93. */
  94. function setSelected($values)
  95. {
  96. if (is_string($values) && $this->getMultiple()) {
  97. $values = split("[ ]?,[ ]?", $values);
  98. }
  99. if (is_array($values)) {
  100. $this->_values = array_values($values);
  101. } else {
  102. $this->_values = array($values);
  103. }
  104. } //end func setSelected
  105. // }}}
  106. // {{{ getSelected()
  107. /**
  108. * Returns an array of the selected values
  109. *
  110. * @since 1.0
  111. * @access public
  112. * @return array of selected values
  113. */
  114. function getSelected()
  115. {
  116. return $this->_values;
  117. } // end func getSelected
  118. // }}}
  119. // {{{ setName()
  120. /**
  121. * Sets the input field name
  122. *
  123. * @param string $name Input field name attribute
  124. * @since 1.0
  125. * @access public
  126. * @return void
  127. */
  128. function setName($name)
  129. {
  130. $this->updateAttributes(array('name' => $name));
  131. } //end func setName
  132. // }}}
  133. // {{{ getName()
  134. /**
  135. * Returns the element name
  136. *
  137. * @since 1.0
  138. * @access public
  139. * @return string
  140. */
  141. function getName()
  142. {
  143. return $this->getAttribute('name');
  144. } //end func getName
  145. // }}}
  146. // {{{ getPrivateName()
  147. /**
  148. * Returns the element name (possibly with brackets appended)
  149. *
  150. * @since 1.0
  151. * @access public
  152. * @return string
  153. */
  154. function getPrivateName()
  155. {
  156. if ($this->getAttribute('multiple')) {
  157. return $this->getName() . '[]';
  158. } else {
  159. return $this->getName();
  160. }
  161. } //end func getPrivateName
  162. // }}}
  163. // {{{ setValue()
  164. /**
  165. * Sets the value of the form element
  166. *
  167. * @param mixed $values Array or comma delimited string of selected values
  168. * @since 1.0
  169. * @access public
  170. * @return void
  171. */
  172. function setValue($value)
  173. {
  174. $this->setSelected($value);
  175. } // end func setValue
  176. // }}}
  177. // {{{ getValue()
  178. /**
  179. * Returns an array of the selected values
  180. *
  181. * @since 1.0
  182. * @access public
  183. * @return array of selected values
  184. */
  185. function getValue()
  186. {
  187. return $this->_values;
  188. } // end func getValue
  189. // }}}
  190. // {{{ setSize()
  191. /**
  192. * Sets the select field size, only applies to 'multiple' selects
  193. *
  194. * @param int $size Size of select field
  195. * @since 1.0
  196. * @access public
  197. * @return void
  198. */
  199. function setSize($size)
  200. {
  201. $this->updateAttributes(array('size' => $size));
  202. } //end func setSize
  203. // }}}
  204. // {{{ getSize()
  205. /**
  206. * Returns the select field size
  207. *
  208. * @since 1.0
  209. * @access public
  210. * @return int
  211. */
  212. function getSize()
  213. {
  214. return $this->getAttribute('size');
  215. } //end func getSize
  216. // }}}
  217. // {{{ setMultiple()
  218. /**
  219. * Sets the select mutiple attribute
  220. *
  221. * @param bool $multiple Whether the select supports multi-selections
  222. * @since 1.2
  223. * @access public
  224. * @return void
  225. */
  226. function setMultiple($multiple)
  227. {
  228. if ($multiple) {
  229. $this->updateAttributes(array('multiple' => 'multiple'));
  230. } else {
  231. $this->removeAttribute('multiple');
  232. }
  233. } //end func setMultiple
  234. // }}}
  235. // {{{ getMultiple()
  236. /**
  237. * Returns the select mutiple attribute
  238. *
  239. * @since 1.2
  240. * @access public
  241. * @return bool true if multiple select, false otherwise
  242. */
  243. function getMultiple()
  244. {
  245. return (bool)$this->getAttribute('multiple');
  246. } //end func getMultiple
  247. // }}}
  248. // {{{ addOption()
  249. /**
  250. * Adds a new OPTION to the SELECT
  251. *
  252. * @param string $text Display text for the OPTION
  253. * @param string $value Value for the OPTION
  254. * @param mixed $attributes Either a typical HTML attribute string
  255. * or an associative array
  256. * @since 1.0
  257. * @access public
  258. * @return void
  259. */
  260. function addOption($text, $value, $attributes=null)
  261. {
  262. if (null === $attributes) {
  263. $attributes = array('value' => $value);
  264. } else {
  265. $attributes = $this->_parseAttributes($attributes);
  266. if (isset($attributes['selected'])) {
  267. // the 'selected' attribute will be set in toHtml()
  268. $this->_removeAttr('selected', $attributes);
  269. if (is_null($this->_values)) {
  270. $this->_values = array($value);
  271. } elseif (!in_array($value, $this->_values)) {
  272. $this->_values[] = $value;
  273. }
  274. }
  275. $this->_updateAttrArray($attributes, array('value' => $value));
  276. }
  277. $this->_options[] = array('text' => $text, 'attr' => $attributes);
  278. } // end func addOption
  279. // }}}
  280. // {{{ loadArray()
  281. /**
  282. * Loads the options from an associative array
  283. *
  284. * @param array $arr Associative array of options
  285. * @param mixed $values (optional) Array or comma delimited string of selected values
  286. * @since 1.0
  287. * @access public
  288. * @return PEAR_Error on error or true
  289. * @throws PEAR_Error
  290. */
  291. function loadArray($arr, $values=null)
  292. {
  293. if (!is_array($arr)) {
  294. return PEAR::raiseError('Argument 1 of HTML_Select::loadArray is not a valid array');
  295. }
  296. if (isset($values)) {
  297. $this->setSelected($values);
  298. }
  299. foreach ($arr as $key => $val) {
  300. // Warning: new API since release 2.3
  301. $this->addOption($val, $key);
  302. }
  303. return true;
  304. } // end func loadArray
  305. // }}}
  306. // {{{ loadDbResult()
  307. /**
  308. * Loads the options from DB_result object
  309. *
  310. * If no column names are specified the first two columns of the result are
  311. * used as the text and value columns respectively
  312. * @param object $result DB_result object
  313. * @param string $textCol (optional) Name of column to display as the OPTION text
  314. * @param string $valueCol (optional) Name of column to use as the OPTION value
  315. * @param mixed $values (optional) Array or comma delimited string of selected values
  316. * @since 1.0
  317. * @access public
  318. * @return PEAR_Error on error or true
  319. * @throws PEAR_Error
  320. */
  321. function loadDbResult(&$result, $textCol=null, $valueCol=null, $values=null)
  322. {
  323. if (!is_object($result) || !is_a($result, 'db_result')) {
  324. return PEAR::raiseError('Argument 1 of HTML_Select::loadDbResult is not a valid DB_result');
  325. }
  326. if (isset($values)) {
  327. $this->setValue($values);
  328. }
  329. $fetchMode = ($textCol && $valueCol) ? DB_FETCHMODE_ASSOC : DB_FETCHMODE_ORDERED;
  330. while (is_array($row = $result->fetchRow($fetchMode)) ) {
  331. if ($fetchMode == DB_FETCHMODE_ASSOC) {
  332. $this->addOption($row[$textCol], $row[$valueCol]);
  333. } else {
  334. $this->addOption($row[0], $row[1]);
  335. }
  336. }
  337. return true;
  338. } // end func loadDbResult
  339. // }}}
  340. // {{{ loadQuery()
  341. /**
  342. * Queries a database and loads the options from the results
  343. *
  344. * @param mixed $conn Either an existing DB connection or a valid dsn
  345. * @param string $sql SQL query string
  346. * @param string $textCol (optional) Name of column to display as the OPTION text
  347. * @param string $valueCol (optional) Name of column to use as the OPTION value
  348. * @param mixed $values (optional) Array or comma delimited string of selected values
  349. * @since 1.1
  350. * @access public
  351. * @return void
  352. * @throws PEAR_Error
  353. */
  354. function loadQuery(&$conn, $sql, $textCol=null, $valueCol=null, $values=null)
  355. {
  356. if (is_string($conn)) {
  357. require_once('DB.php');
  358. $dbConn = &DB::connect($conn, true);
  359. if (DB::isError($dbConn)) {
  360. return $dbConn;
  361. }
  362. } elseif (is_subclass_of($conn, "db_common")) {
  363. $dbConn = &$conn;
  364. } else {
  365. return PEAR::raiseError('Argument 1 of HTML_Select::loadQuery is not a valid type');
  366. }
  367. $result = $dbConn->query($sql);
  368. if (DB::isError($result)) {
  369. return $result;
  370. }
  371. $this->loadDbResult($result, $textCol, $valueCol, $values);
  372. $result->free();
  373. if (is_string($conn)) {
  374. $dbConn->disconnect();
  375. }
  376. return true;
  377. } // end func loadQuery
  378. // }}}
  379. // {{{ load()
  380. /**
  381. * Loads options from different types of data sources
  382. *
  383. * This method is a simulated overloaded method. The arguments, other than the
  384. * first are optional and only mean something depending on the type of the first argument.
  385. * If the first argument is an array then all arguments are passed in order to loadArray.
  386. * If the first argument is a db_result then all arguments are passed in order to loadDbResult.
  387. * If the first argument is a string or a DB connection then all arguments are
  388. * passed in order to loadQuery.
  389. * @param mixed $options Options source currently supports assoc array or DB_result
  390. * @param mixed $param1 (optional) See function detail
  391. * @param mixed $param2 (optional) See function detail
  392. * @param mixed $param3 (optional) See function detail
  393. * @param mixed $param4 (optional) See function detail
  394. * @since 1.1
  395. * @access public
  396. * @return PEAR_Error on error or true
  397. * @throws PEAR_Error
  398. */
  399. function load(&$options, $param1=null, $param2=null, $param3=null, $param4=null)
  400. {
  401. switch (true) {
  402. case is_array($options):
  403. return $this->loadArray($options, $param1);
  404. break;
  405. case (is_a($options, 'db_result')):
  406. return $this->loadDbResult($options, $param1, $param2, $param3);
  407. break;
  408. //case (is_string($options) && !empty($options) || is_subclass_of($options, "db_common")):
  409. // return $this->loadQuery($options, $param1, $param2, $param3, $param4);
  410. // break;
  411. }
  412. } // end func load
  413. // }}}
  414. // {{{ toHtml()
  415. /**
  416. * Returns the SELECT in HTML
  417. *
  418. * @since 1.0
  419. * @access public
  420. * @return string
  421. */
  422. function toHtml()
  423. {
  424. if ($this->_flagFrozen) {
  425. return $this->getFrozenHtml();
  426. } else {
  427. $tabs = $this->_getTabs();
  428. $strHtml = '';
  429. if ($this->getComment() != '') {
  430. $strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->\n";
  431. }
  432. if (!$this->getMultiple()) {
  433. $attrString = $this->_getAttrString($this->_attributes);
  434. } else {
  435. $myName = $this->getName();
  436. $this->setName($myName . '[]');
  437. $attrString = $this->_getAttrString($this->_attributes);
  438. $this->setName($myName);
  439. }
  440. $strHtml .= $tabs . '<select' . $attrString . ">\n";
  441. foreach ($this->_options as $option) {
  442. if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
  443. $this->_updateAttrArray($option['attr'], array('selected' => 'selected'));
  444. }
  445. $strHtml .= $tabs . "\t<option" . $this->_getAttrString($option['attr']) . '>' .
  446. $option['text'] . "</option>\n";
  447. }
  448. return $strHtml . $tabs . '</select>';
  449. }
  450. } //end func toHtml
  451. // }}}
  452. // {{{ getFrozenHtml()
  453. /**
  454. * Returns the value of field without HTML tags
  455. *
  456. * @since 1.0
  457. * @access public
  458. * @return string
  459. */
  460. function getFrozenHtml()
  461. {
  462. $value = array();
  463. if (is_array($this->_values)) {
  464. foreach ($this->_values as $key => $val) {
  465. for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
  466. if ((string)$val == (string)$this->_options[$i]['attr']['value']) {
  467. $value[$key] = $this->_options[$i]['text'];
  468. break;
  469. }
  470. }
  471. }
  472. }
  473. $html = empty($value)? '&nbsp;': join('<br />', $value);
  474. if ($this->_persistantFreeze) {
  475. $name = $this->getPrivateName();
  476. // Only use id attribute if doing single hidden input
  477. if (1 == count($value)) {
  478. $id = $this->getAttribute('id');
  479. $idAttr = isset($id)? array('id' => $id): array();
  480. } else {
  481. $idAttr = array();
  482. }
  483. foreach ($value as $key => $item) {
  484. $html .= '<input' . $this->_getAttrString(array(
  485. 'type' => 'hidden',
  486. 'name' => $name,
  487. 'value' => $this->_values[$key]
  488. ) + $idAttr) . ' />';
  489. }
  490. }
  491. return $html;
  492. } //end func getFrozenHtml
  493. // }}}
  494. // {{{ exportValue()
  495. /**
  496. * We check the options and return only the values that _could_ have been
  497. * selected. We also return a scalar value if select is not "multiple"
  498. */
  499. function exportValue(&$submitValues, $assoc = false)
  500. {
  501. $value = $this->_findValue($submitValues);
  502. if (is_null($value)) {
  503. $value = $this->getValue();
  504. } elseif(!is_array($value)) {
  505. $value = array($value);
  506. }
  507. if (is_array($value) && !empty($this->_options)) {
  508. $cleanValue = null;
  509. foreach ($value as $v) {
  510. for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
  511. if ($v == $this->_options[$i]['attr']['value']) {
  512. $cleanValue[] = $v;
  513. break;
  514. }
  515. }
  516. }
  517. } else {
  518. $cleanValue = $value;
  519. }
  520. if (is_array($cleanValue) && !$this->getMultiple()) {
  521. return $this->_prepareValue($cleanValue[0], $assoc);
  522. } else {
  523. return $this->_prepareValue($cleanValue, $assoc);
  524. }
  525. }
  526. // }}}
  527. // {{{ onQuickFormEvent()
  528. function onQuickFormEvent($event, $arg, &$caller)
  529. {
  530. if ('updateValue' == $event) {
  531. $value = $this->_findValue($caller->_constantValues);
  532. if (null === $value) {
  533. $value = $this->_findValue($caller->_submitValues);
  534. // Fix for bug #4465 & #5269
  535. // XXX: should we push this to element::onQuickFormEvent()?
  536. if (null === $value && (!$caller->isSubmitted() || !$this->getMultiple())) {
  537. $value = $this->_findValue($caller->_defaultValues);
  538. }
  539. }
  540. if (null !== $value) {
  541. $this->setValue($value);
  542. }
  543. return true;
  544. } else {
  545. return parent::onQuickFormEvent($event, $arg, $caller);
  546. }
  547. }
  548. // }}}
  549. } //end class HTML_QuickForm_select
  550. ?>