com.lokorin.lokorin.lib
[ class tree: com.lokorin.lokorin.lib ] [ index: com.lokorin.lokorin.lib ] [ all elements ]

Source for file lib_forms.php

Documentation is available at lib_forms.php

  1. <?php
  2. /*
  3. * Lokorin.com
  4. * Copyright 2004-2006
  5. * Licensed under the GNU LGPL. See COPYING for full terms.
  6. */
  7. /**
  8. * A library for creating and using forms.
  9. * @author Andreas Launila
  10. * @version $Revision: 1.16 $
  11. * @package com.lokorin.lokorin.lib
  12. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  13. */
  14.  
  15. /**
  16. * For access to common constants and functions.
  17. */
  18. require_once('common.php');
  19. CssHandler::getInstance()->includeCss('forms');
  20.  
  21. /**
  22. * Meant as an interface for validatable objects.
  23. * @author Andreas Launila
  24. * @package com.lokorin.lokorin.lib
  25. */
  26. interface Validatable {
  27. /**
  28. * Checks if the object's state is valid or not.
  29. * @return boolean True if the object's state is valid, false otherwise.
  30. */
  31. public function isValid();
  32.  
  33. /**
  34. * Returns the reason for an object is not in a valid state. This assumes
  35. * that the isValid() function returns false (so check that first).
  36. * @return string An error message.
  37. */
  38. public function getError();
  39. }
  40.  
  41. /**
  42. * Describes a field in a form.
  43. * @author Andreas Launila
  44. * @package com.lokorin.lokorin.lib
  45. */
  46. abstract class Field implements Validatable {
  47. /**
  48. * The name of the field.
  49. * @var string
  50. */
  51. private $name;
  52. /**
  53. * If the field has to be entered to be valid.
  54. * @var boolean
  55. */
  56. private $required;
  57. /**
  58. * The value of the field.
  59. * @var string
  60. */
  61. private $value;
  62. /**
  63. * The unique identifier for the field.
  64. * @var integer
  65. */
  66. private $id;
  67. /**
  68. * Any additional attributes where the key is the attribute name and the
  69. * value is the the attribute value.
  70. * @var array
  71. */
  72. private $attributes;
  73. /**
  74. * True if the current value was entered by a user, false otherwise.
  75. * @var boolean
  76. */
  77. private $hasUserValue;
  78.  
  79. /**
  80. * Constructor for Field.
  81. * @param string $name The name of the field.
  82. * @param boolean $required True if the field has to contain something to be valid,
  83. * false otherwise. False by default.
  84. */
  85. public function __construct($name, $required = false) {
  86. $this->name = $name;
  87. $this->required = $required;
  88. $this->attributes = array("name" => $name);
  89. $this->hasUserValue = false;
  90. //Check if there is a value for the field, if so then give the
  91. //field that value.
  92. if(isset($_REQUEST[$name])) {
  93. $this->setValue($_REQUEST[$name]);
  94. $this->hasUserValue = true;
  95. }
  96. }
  97.  
  98. /**
  99. * Gets the name of the field.
  100. * @return string A field name.
  101. */
  102. public function getName() {
  103. return $this->name;
  104. }
  105.  
  106. /**
  107. * Gets the value of the field.
  108. * @return string A field value.
  109. */
  110. public function getValue() {
  111. return $this->value;
  112. }
  113.  
  114. /**
  115. * Sets the value of the field.
  116. * @param mixed $newValue The new value for the field.
  117. */
  118. public function setValue($newValue) {
  119. $this->value = $newValue;
  120. $this->attributes["value"] = $this->value;
  121. $this->hasUserValue = false;
  122. }
  123.  
  124. /**
  125. * Returns the (X)HTML representation of the field. This function should
  126. * be concidered as an abstract function, any subclasses should override
  127. * this.
  128. * @return string An field in HTML.
  129. */
  130. public abstract function getAsHtml();
  131.  
  132. /**
  133. * Gets the field's id.
  134. * @return string An field id.
  135. */
  136. public function getId() {
  137. return $this->id;
  138. }
  139.  
  140. /**
  141. * Sets the field's id.
  142. * @param string $newId The id to be used by the field.
  143. */
  144. public function setId($newId) {
  145. $this->id = $newId;
  146. $this->attributes["id"] = $newId;
  147. }
  148.  
  149. /**
  150. * Gets the (X)HTML information containing all base information.
  151. * @return string A bunch of attributes.
  152. */
  153. protected function getAttributes() {
  154. $attributes = "";
  155. foreach($this->attributes as $name => $value) {
  156. $attributes .= htmlspecialchars($name).'="'.
  157. htmlspecialchars($value).'" ';
  158. }
  159. return $attributes;
  160. }
  161.  
  162. /**
  163. * @see Validatable.isValid()
  164. */
  165. public function isValid() {
  166. return ($this->required === false) || $this->hasValue();
  167. }
  168.  
  169. /**
  170. * @see Validatable.getError()
  171. */
  172. public function getError() {
  173. return 'This field requires a value to be entered.';
  174. }
  175. /**
  176. * Sets one of the firleds attributes. If the attribute does not exist
  177. * then it is created. The attributes 'id', 'name' and 'value' can not be
  178. * modified throught this function.
  179. * @param string $name The name of the attribute.
  180. * @param string $value The value that the attribute should have.
  181. */
  182. public function setAttribute($name, $value) {
  183. $this->attributes[$name] = $value;
  184. }
  185. /**
  186. * Checks if the field has a non empty value.
  187. * @return boolean True if the field has a non empty value, false
  188. * otherwise.
  189. */
  190. public function hasValue() {
  191. return $this->value != '';
  192. }
  193. /**
  194. * Checks if the field has a non empty value that has been supplied by
  195. * a user.
  196. * @return boolean True if the field has a non empty value supplied by
  197. * the user, false otherwise.
  198. */
  199. public function hasUserValue() {
  200. return $this->hasUserValue;
  201. }
  202. /**
  203. * Formats any additional data that should be appended to the field. Any
  204. * '%id' entities in the formatted string are replaced with the field's
  205. * id. Any '%name' entities in the formatted string are replaced with the
  206. * field's name.
  207. * @param $additionToFormat The addition that should be formatted.
  208. * @return mixed The formatted addition, the function may return it intact,
  209. * modified or fully removed if it wished. The only guarantee is that
  210. * there will be no '%id' or '%name' entities in the result.
  211. */
  212. public function formatAddition($additionToFormat) {
  213. return str_replace('%name', $this->name,
  214. str_replace('%id', $this->id, $additionToFormat));
  215. }
  216. /**
  217. * Clears the field, making it so that it appears to never have received a
  218. * value.
  219. */
  220. public function clear() {
  221. $this->value = '';
  222. unset($this->attributes["value"]);
  223. }
  224. }
  225.  
  226. /**
  227. * Describes a hidden field.
  228. * @author Andreas Launila
  229. * @package com.lokorin.lokorin.lib
  230. */
  231. class Hidden extends Field {
  232. /**
  233. * Constructor for Hidden.
  234. * @param string $name The name of the hidden field.
  235. * @param string $value The value of the hidden field (nothing by default).
  236. */
  237. public function __construct($name, $value = '') {
  238. parent::__construct($name, false);
  239. if(strlen($value) != 0) {
  240. $this->setValue($value);
  241. }
  242. }
  243.  
  244. /**
  245. * @see Field.getAsHtml()
  246. */
  247. public function getAsHtml() {
  248. return sprintf('<input type="hidden" class="hidden" %s/>',
  249. $this->getAttributes());
  250. }
  251. /**
  252. * @see Field.hasUserValue()
  253. */
  254. public function hasUserValue() {
  255. //This can not be set by users.
  256. return false;
  257. }
  258. }
  259.  
  260. /**
  261. * Describes a field that is read only. I.e. just prints the contents of it,
  262. * not really a field, but it's useful at times.
  263. * @author Andreas Launila
  264. * @package com.lokorin.lokorin.lib
  265. */
  266. class ReadOnly extends Field {
  267. /**
  268. * A callback that the value should be processed through before being
  269. * displayed. An empty string means that there is no callback.
  270. * @var callback
  271. */
  272. private $callback;
  273. /**
  274. * Constructor for ReadOnly.
  275. * @param string $name The name of the read only field.
  276. * @param string $value The value to display.
  277. * @param callback $formatCallback A callback that should be applied to
  278. * the value before displaying it. The callback should take one
  279. * argument, the value, and return the string that should be displayed
  280. * instead of the value.
  281. */
  282. public function __construct($name, $value = '', $formatCallback = '') {
  283. parent::__construct($name, false);
  284. $this->setValue($value);
  285. $this->callback = $formatCallback;
  286. }
  287.  
  288. /**
  289. * @see Field.getAsHtml()
  290. */
  291. public function getAsHtml() {
  292. $value = $this->getValue();
  293. if($this->callback != '') {
  294. $callback = $this->callback;
  295. $value = $callback($value);
  296. }
  297. return '<p>'.$value.'</p>';
  298. }
  299. }
  300.  
  301. /**
  302. * Describes a checkbox.
  303. * @author Andreas Launila
  304. * @package com.lokorin.lokorin.lib
  305. */
  306. class Checkbox extends Field {
  307. /**
  308. * Constructor for Checkbox.
  309. * @param string $name The name of the checkbox.
  310. */
  311. public function __construct($name) {
  312. parent::__construct($name, false);
  313. }
  314.  
  315. /**
  316. * @see Field.getAsHtml()
  317. */
  318. public function getAsHtml() {
  319. $filler = $this->getAttributes();
  320. if(strpos($filler, "value") !== false) {
  321. $filler = preg_replace("/value=\".*?\"/", $filler, 'checked="checked"');
  322. }
  323. return sprintf('<input type="checkbox" %s/>', $filler);
  324. }
  325. }
  326.  
  327. /**
  328. * Describes a button.
  329. * @author Andreas Launila
  330. * @package com.lokorin.lokorin.lib
  331. */
  332. class Button extends Field {
  333. /**
  334. * Constructor for Button.
  335. * @param string $name The name of the button.
  336. * @param string $value The value to displayed as the button's text.
  337. */
  338. public function __construct($name, $value = '') {
  339. parent::__construct($name, false);
  340. $this->setValue($value);
  341. }
  342.  
  343. /**
  344. * @see Field.getAsHtml()
  345. */
  346. public function getAsHtml() {
  347. return sprintf('<input type="button" %s/>', $this->getAttributes());
  348. }
  349. /**
  350. * @see Field.clear()
  351. */
  352. public function clear() {
  353. //A button can not be cleared.
  354. }
  355. }
  356.  
  357. /**
  358. * Describes a submit button.
  359. * @author Andreas Launila
  360. * @package com.lokorin.lokorin.lib
  361. */
  362. class SubmitButton extends Field {
  363. /**
  364. * Constructor for SubmitButton.
  365. * @param string $name The name of the button.
  366. * @param string $value The value to displayed as the button's text.
  367. */
  368. public function __construct($name, $value = '') {
  369. parent::__construct($name, false);
  370. $this->setValue($value);
  371. }
  372.  
  373. /**
  374. * @see Field.getAsHtml()
  375. */
  376. public function getAsHtml() {
  377. return sprintf('<input class="submitButton" type="submit" %s/>', $this->getAttributes());
  378. }
  379. /**
  380. * @see Field.hasUserValue()
  381. */
  382. public function hasUserValue() {
  383. //This never has any user value.
  384. return false;
  385. }
  386. /**
  387. * @see Field.clear()
  388. */
  389. public function clear() {
  390. //A button can not be cleared.
  391. }
  392. }
  393.  
  394. /**
  395. * Describes a reset button.
  396. * @author Andreas Launila
  397. * @package com.lokorin.lokorin.lib
  398. */
  399. class ResetButton extends Field {
  400. /**
  401. * Constructor for ResetButton.
  402. * @param string $name The name of the button.
  403. * @param string $value The value to displayed as the button's text.
  404. */
  405. public function __construct($name, $value = '') {
  406. parent::Field($name, false);
  407. $this->setValue($value);
  408. }
  409.  
  410. /**
  411. * @see field.getAsHtml()
  412. */
  413. public function getAsHtml() {
  414. return sprintf('<input type="reset" %s/>', $this->getAttributes());
  415. }
  416. /**
  417. * @see Field.clear()
  418. */
  419. public function clear() {
  420. //A button can not be cleared.
  421. }
  422. }
  423.  
  424. /**
  425. * Describes a field that can be sized.
  426. * @author Andreas Launila
  427. * @package com.lokorin.lokorin.lib
  428. */
  429. abstract class SizedField extends Field {
  430. /**
  431. * The height of the field, 0 means that no height has been set.
  432. * @var integer
  433. */
  434. private $height;
  435. /**
  436. * The width of the field, 0 means that no width has been set.
  437. * @var integer
  438. */
  439. private $width;
  440.  
  441. /**
  442. * Constructor for SizedField.
  443. * @param string $name The name of the SizedField.
  444. * @param boolean $required True if the field has to contain something to be valid,
  445. * false otherwise. False by default.
  446. */
  447. public function __construct($name, $required = false) {
  448. parent::__construct($name, $required);
  449. }
  450.  
  451. /**
  452. * Sets the height of the field.
  453. * @param integer $new_height The new height.
  454. */
  455. public function setHeight($new_height) {
  456. $this->height = $new_height;
  457. }
  458.  
  459. /**
  460. * Sets the width of the field.
  461. * @param integer $new_width The new width.
  462. */
  463. public function setWidth($new_width) {
  464. $this->width = $new_width;
  465. }
  466.  
  467. /**
  468. * Gets the height of the field.
  469. * @return integer A field height.
  470. */
  471. public function getHeight() {
  472. return $this->height;
  473. }
  474.  
  475. /**
  476. * Gets the width of the field.
  477. * @return integer A field width.
  478. */
  479. public function getWidth() {
  480. return $this->width;
  481. }
  482.  
  483. /**
  484. * @see field.getAttributes()
  485. */
  486. protected function getAttributes() {
  487. $filler = parent::getAttributes();
  488. if($this->width != 0) {
  489. $filler .= 'width="'.$this->width.'" ';
  490. }
  491. if($this->height != 0) {
  492. $filler .= 'height="'.$this->height.'" ';
  493. }
  494. return $filler;
  495. }
  496. }
  497.  
  498. /**
  499. * Describes a textfield.
  500. * @author Andreas Launila
  501. * @package com.lokorin.lokorin.lib
  502. */
  503. class TextField extends SizedField {
  504. /**
  505. * Constructor for TextField.
  506. * @param string $name The name of the SizedField.
  507. * @param boolean $required True if the field has to contain something to be valid,
  508. * false otherwise. False by default.
  509. */
  510. public function __construct($name, $required = false) {
  511. parent::__construct($name, $required);
  512. }
  513.  
  514. /**
  515. * @see field.getAsHtml()
  516. */
  517. public function getAsHtml() {
  518. //To fix a mistake.
  519. $this->setHeight(0);
  520. $attributes = preg_replace('/width="(.*?)"/', 'size="$1"', $this->getAttributes());
  521. return sprintf('<input type="text" %s/>', $attributes);
  522. }
  523. }
  524.  
  525. /**
  526. * Describes a password field.
  527. * @author Andreas Launila
  528. * @package com.lokorin.lokorin.lib
  529. */
  530. class PasswordField extends SizedField {
  531. /**
  532. * Constructor for PasswordField.
  533. * @param string $name The name of the SizedField.
  534. * @param boolean $required True if the field has to contain something to be valid,
  535. * false otherwise. False by default.
  536. */
  537. public function __construct($name, $required = false) {
  538. parent::__construct($name, $required);
  539. }
  540.  
  541. /**
  542. * @see field.getAsHtml()
  543. */
  544. public function getAsHtml() {
  545. return sprintf('<input type="password" %s/>', $this->getAttributes());
  546. }
  547. }
  548.  
  549. /**
  550. * Describes a textarea.
  551. * @author Andreas Launila
  552. * @package com.lokorin.lokorin.lib
  553. */
  554. class TextArea extends SizedField {
  555. /**
  556. * Constructor for TextArea.
  557. * @param string $name The name of the SizedField.
  558. * @param boolean $required True if the field has to contain something to
  559. * be valid, false otherwise. False by default.
  560. * @param integer $rows The number of rows that the textarea should have
  561. * (default is 20).
  562. * @param integer $cols The number of columns that the textarea should
  563. * have (default is 30).
  564. */
  565. public function __construct($name, $required = false, $rows = 10, $cols = 40) {
  566. parent::__construct($name, $required);
  567. $this->setHeight($rows);
  568. $this->setWidth($cols);
  569. }
  570.  
  571. /**
  572. * @see field.getAsHtml()
  573. */
  574. public function getAsHtml() {
  575. $filler = '';
  576. if($this->getWidth() != 0) {
  577. $filler .= 'cols="'.$this->getWidth().'" ';
  578. }
  579. if($this->getHeight() != 0) {
  580. $filler .= 'rows="'.$this->getHeight().'" ';
  581. }
  582. if(strlen($this->getId()) > 0) {
  583. $filler .= 'id="'.$this->getId().'" ';
  584. }
  585. return sprintf('<textarea name="%s" %s>%s</textarea>', $this->getName(),
  586. $filler, htmlspecialchars($this->getValue()));
  587. }
  588. }
  589.  
  590. /**
  591. * Describes a select field.
  592. * @author Andreas Launila
  593. * @package com.lokorin.lokorin.lib
  594. */
  595. class Select extends Field {
  596. /**
  597. * The options that should be displayed in the select element. The
  598. * value as key and the name of the option as value.
  599. * @var array
  600. */
  601. private $options;
  602.  
  603. /**
  604. * Constructor for Select.
  605. * @param string $name The name of the Select field.
  606. * @param array $options The options to be used. To be given as option value as key and
  607. * name as value.
  608. */
  609. public function __construct($name, $options) {
  610. parent::__construct($name, false);
  611. $this->options = $options;
  612. }
  613.  
  614. /**
  615. * @see field.getAsHtml()
  616. */
  617. public function getAsHtml() {
  618. //Build the options and select the current value.
  619. $options = '';
  620. foreach($this->options as $value => $name) {
  621. $options .= '<option value="'.$value.'">'.$name.'</option>'."\n";
  622. }
  623. if($this->getValue() != '') {
  624. $options = preg_replace('/(value="'.$this->getValue().'")/','$1 selected="selected"',$options);
  625. }
  626.  
  627. $attributes = preg_replace('/value="[^"]*"/', "", $this->getAttributes());
  628. return sprintf('<select %s>%s</select><br />', $attributes, $options);
  629. }
  630. }
  631.  
  632. /**
  633. * Describes a field (or rather group of fields) that allows the user to
  634. * select a specific date by selecting year, month and day.
  635. * @author Andreas Launila
  636. * @package com.lokorin.lokorin.lib
  637. */
  638. class DateField extends Field {
  639. /**
  640. * The year selection field.
  641. * @var Select
  642. */
  643. protected $year;
  644. /**
  645. * The month selection field.
  646. * @var Select
  647. */
  648. protected $month;
  649. /**
  650. * The date selection field.
  651. * @var TextField
  652. */
  653. protected $day;
  654. /**
  655. * The lowest unix timestamp that the user should allow to select.
  656. * @var integer
  657. */
  658. protected $timeMin;
  659. /**
  660. * The highest unix timestamp that the user should allow to select.
  661. * @var integer
  662. */
  663. protected $timeMax;
  664. /**
  665. * The value that should be displayed as legend for the fieldset.
  666. * @var string
  667. */
  668. protected $legend;
  669. /**
  670. * The initial value (unix timestamp) that should be used for the field.
  671. * $var integer
  672. */
  673. private $initialValue;
  674. /**
  675. * Constructor for DateField.
  676. * @param string $name The name identifier of the date field.
  677. * @param string $displayName The name that should be displayed to the
  678. * user.
  679. * @param integer $timeMin The lowest unix timestamp that the date field
  680. * should allow the user to select.
  681. * @param integer $timeMax The highest unix timestamp that the date field
  682. * should allow the user to select.
  683. * @param integer $initialValue The unix timestamp that should be
  684. * displayed initially.
  685. * @access public
  686. */
  687. public function __construct($name, $displayName, $timeMin = 0,
  688. $timeMax = 2000000000, $initialValue = 0) {
  689. parent::__construct($name, false);
  690. //Perform a basic sanity check.
  691. if($timeMin > $timeMax) {
  692. //Exchange the values, they are in the wrong order.
  693. $tmp = $timeMax;
  694. $timeMax = $timeMin;
  695. $timeMin = $timeMax;
  696. }
  697. $this->timeMin = $timeMin;
  698. $this->timeMax = $timeMax;
  699. $this->legend = $displayName;
  700. //Set up the fields.
  701. /*
  702. * Year
  703. */
  704. $yearMin = date('Y', $timeMin);
  705. $yearMax = date('Y', $timeMax);
  706. //Create and add the year selection.
  707. $years = array();
  708. for($i = $yearMin; $i<=$yearMax; $i++) {
  709. $years[$i] = $i;
  710. }
  711. $this->year = new Select($name.'_year', $years);
  712. /*
  713. * Month
  714. */
  715. $months = array(
  716. 1 => 'January',
  717. 2 => 'February',
  718. 3 => 'March',
  719. 4 => 'April',
  720. 5 => 'May',
  721. 6 => 'June',
  722. 7 => 'July',
  723. 8 => 'August',
  724. 9 => 'September',
  725. 10 => 'October',
  726. 11 => 'November',
  727. 12 => 'December'
  728. );
  729. $this->month = new Select($name.'_month', $months);
  730. /*
  731. * Day
  732. */
  733. $day = new TextField($name.'_day');
  734. $day->setWidth(5);
  735. $this->day = $day;
  736. $day = $this->day;
  737. $month = $this->month;
  738. $year = $this->year;
  739.  
  740. if($this->hasUserValue()) {
  741. //Dirty hack to make this compatible with lib_search.
  742. $_REQUEST[$name] = $this->getValue();
  743. } else {
  744. $this->setValue($initialValue);
  745. $this->initialValue = $this->getValue();
  746. }
  747. }
  748. /**
  749. * @see Field.getValue()
  750. */
  751. public function getValue() {
  752. //Retrieve the represented unix timestamp.
  753. $day = $this->day;
  754. $month = $this->month;
  755. $year = $this->year;
  756. $time = mktime(0, 0, 0, $month->getValue(), $day->getValue(),
  757. $year->getValue());
  758. //Make sure it's within the permitted interval.
  759. if($time < $this->timeMin) {
  760. $time = $this->timeMin;
  761. }
  762. if($time > $this->timeMax) {
  763. $time = $this->timeMax;
  764. }
  765. $this->value = $time;
  766. return $time;
  767. }
  768. /**
  769. * @see Field.setValue(mixed)
  770. */
  771. public function setValue($newValue) {
  772. $this->day->setValue(date('j', $newValue));
  773. $this->month->setValue(date('n', $newValue));
  774. $this->year->setValue(date('Y', $newValue));
  775. }
  776. /**
  777. * @see Field.getAsHtml()
  778. */
  779. public function getAsHTML() {
  780. $day = $this->day;
  781. $month = $this->month;
  782. $year = $this->year;
  783. $output = '<fieldset><legend>'.$this->legend.'</legend>';
  784. $output .= '<label for="'.$year->getName().'">Year</label>';
  785. $output .= $year->getAsHTML();
  786. $output .= '<label for="'.$month->getName().'">Month</label>';
  787. $output .= $month->getAsHTML();
  788. $output .= '<label for="'.$day->getName().'">Day</label>';
  789. $output .= $day->getAsHTML();
  790. $output .= '</fieldset><br />';
  791. return $output;
  792. }
  793. /**
  794. * @see Field.hasValue()
  795. */
  796. public function hasValue() {
  797. return $this->initialValue != $this->getValue();
  798. }
  799. /**
  800. * @see Field.hasUserValue()
  801. */
  802. public function hasUserValue() {
  803. return $this->day->hasUserValue() || $this->month->hasUserValue() ||
  804. $this->year->hasUserValue();
  805. }
  806. /**
  807. * No additions are allowed.
  808. * @see Field.formatAddition()
  809. */
  810. public function formatAddition($addition) {
  811. return '';
  812. }
  813. }
  814.  
  815. /**
  816. * Describes a field (or rather a group of fields) that allows the user to
  817. * select a certain timestamp (year, month, day, hour, minute and second).
  818. * @author Andreas Launila
  819. * @package com.lokorin.lokorin.lib
  820. */
  821. class TimeField extends DateField {
  822. /**
  823. * The hour selection field.
  824. * @var TextField
  825. */
  826. private $hour;
  827. /**
  828. * The minute selection field.
  829. * @var TextField
  830. */
  831. private $minute;
  832. /**
  833. * The second selection field.
  834. * @var TextField
  835. */
  836. private $second;
  837. /**
  838. * Constructor for TimeField.
  839. * @param string $name The name identifier of the date field.
  840. * @param string $displayName The name that should be displayed to the
  841. * user.
  842. * @param integer $timeMin The lowest unix timestamp that the date field
  843. * should allow the user to select.
  844. * @param integer $timeMax The highest unix timestamp that the date field
  845. * should allow the user to select.
  846. * @param integer $initialValue The unix timestamp that should be
  847. * displayed initially.
  848. */
  849. public function __construct($name, $displayName, $timeMin = 0,
  850. $timeMax = 2000000000, $initialValue = 0) {
  851. //Set up the fields.
  852. /*
  853. * Hour
  854. */
  855. $this->hour = new TextField($name.'_hour');
  856. $this->hour->setWidth(4);
  857. /*
  858. * Minute
  859. */
  860. $this->minute = new TextField($name.'_minute');
  861. $this->minute->setWidth(4);
  862. /*
  863. * Second
  864. */
  865. $this->second = new TextField($name.'_second');
  866. $this->second->setWidth(4);
  867. parent::__construct($name, $displayName, $timeMin, $timeMax, $initialValue);
  868. }
  869. /**
  870. * @see Field.hasUserValue()
  871. */
  872. public function hasUserValue() {
  873. return parent::hasUserValue() || $this->hour->hasUserValue() ||
  874. $this->minute->hasUserValue() || $this->second->hasUserValue();
  875. }
  876. /**
  877. * @see Field.getValue()
  878. */
  879. public function getValue() {
  880. //Retrieve the represented unix timestamp.
  881. $time = mktime(
  882. $this->hour->getValue(),
  883. $this->minute->getValue(),
  884. $this->second->getValue(),
  885. parent::$this->month->getValue(),
  886. parent::$this->day->getValue(),
  887. parent::$this->year->getValue()
  888. );
  889. //Make sure it's within the permitted interval.
  890. if($time < parent::$this->timeMin) {
  891. $time = $this->timeMin;
  892. }
  893. if($time > parent::$this->timeMax) {
  894. $time = $this->timeMax;
  895. }
  896. $this->value = $time;
  897. return $time;
  898. }
  899. /**
  900. * @see Field.setValue()
  901. */
  902. public function setValue($newValue) {
  903. parent::setValue($newValue);
  904. $this->hour->setValue(date('G', $newValue));
  905. $this->minute->setValue(date('i', $newValue));
  906. $this->second->setValue(date('s', $newValue));
  907. }
  908. /**
  909. * @see Field.getAsHtml()
  910. */
  911. public function getAsHTML() {
  912. $output = '<fieldset><legend>'.parent::$this->legend.'</legend>';
  913. $output .= '<label for="'.$this->year->getName().'">Year</label>';
  914. $output .= $this->year->getAsHTML();
  915. $output .= '<label for="'.$this->month->getName().'">Month</label>';
  916. $output .= $this->month->getAsHTML();
  917. $output .= '<label for="'.$this->day->getName().'">Day</label>';
  918. $output .= $this->day->getAsHTML();
  919. $output .= '<label for="'.$this->hour->getName().'">Hour</label>';
  920. $output .= $this->hour->getAsHTML();
  921. $output .= '<label for="'.$this->minute->getName().'">Minute</label>';
  922. $output .= $this->minute->getAsHTML();
  923. $output .= '<label for="'.$this->second->getName().'">Second</label>';
  924. $output .= $this->second->getAsHTML();
  925. $output .= '</fieldset><br />';
  926. return $output;
  927. }
  928. }
  929.  
  930. /**
  931. * Describes a file field.
  932. * @author Andreas Launila
  933. * @package com.lokorin.lokorin.lib
  934. */
  935. class Browse extends SizedField {
  936. /**
  937. * Constructor for Browse.
  938. * @param boolean $required True if the field has to contain something to
  939. * be valid, false otherwise. False by default.
  940. */
  941. public function __construct($name, $required = false) {
  942. parent::__construct($name, $required);
  943. $this->setValue('');
  944. }
  945. /**
  946. * @see field.getAsHtml()
  947. */
  948. public function getAsHtml() {
  949. return sprintf('<input type="file" %s/>', $this->getAttributes());
  950. }
  951. }
  952.  
  953. /**
  954. * Describes an form.
  955. * @author Andreas Launila
  956. * @package com.lokorin.lokorin.lib
  957. */
  958. class Form implements Validatable {
  959. /**
  960. * Contains arrays describing contained fields with two keys each:
  961. * (Field)field: The actual field.
  962. * (string)displayName: The name to be displayed for the field.
  963. * @var array
  964. */
  965. private $fields;
  966. /**
  967. * The action to be used by the form.
  968. * @var string
  969. */
  970. private $action;
  971. /**
  972. * The method to be used by the form.
  973. * @var string
  974. */
  975. private $method;
  976. /**
  977. * The legend value that should be used for the form.
  978. * @var string
  979. */
  980. private $legend;
  981. /**
  982. * The encoding type to use for the form.
  983. * @var string
  984. */
  985. private $encType;
  986. /**
  987. * If errors should be displayed or not (true by default).
  988. * @var boolean
  989. */
  990. private $displayErrors;
  991. /**
  992. * The css class to be used by the form element.
  993. * @var string
  994. */
  995. private $cssClass;
  996.  
  997. /**
  998. * Constructor for Form.
  999. * @param string $legend The legends that should be used for the form,
  1000. * none by default.
  1001. * @param string $method The method to be used bt the form (post by
  1002. * default).
  1003. * @param string $action The action to be used by the form. By default the
  1004. * action is set to the requested uri.
  1005. * @param string $encType The encoding type that should be used for the
  1006. * form.
  1007. */
  1008. public function __construct($legend = '', $method = 'post', $action = '', $encType = '') {
  1009. if($action == '') {
  1010. $action = SELF;
  1011. }
  1012. $this->action = $action;
  1013. $this->method = $method;
  1014. $this->legend = $legend;
  1015. $this->encType = $encType;
  1016. $this->displayErrors = true;
  1017. }
  1018.  
  1019. /**
  1020. * Adds a new field to the form.
  1021. * @param field $field The actual field.
  1022. * @param string $displayName The name that should be shown to the user. If
  1023. * nothing specified then nothing is shown to the user.
  1024. */
  1025. public function addField($field, $displayName = '') {
  1026. //Add the field.
  1027. $this->fields[] = array(
  1028. 'displayName' => $displayName,
  1029. 'field' => $field);
  1030. }
  1031.  
  1032. /**
  1033. * Adds multiple fields to the form.
  1034. * @param array $fields An array with key being the display name and value
  1035. * being the associated field.
  1036. */
  1037. public function addFields($fields) {
  1038. foreach($fields as $dispName => $field) {
  1039. $this->addField($field, $dispName);
  1040. }
  1041. }
  1042. /**
  1043. * Gets the (X)HTML representation of the form.
  1044. * @return string A form.
  1045. */
  1046. public function getForm() {
  1047. $form = '<form action="'.$this->action.'" method="'.$this->method.'"';
  1048. if(strlen($this->cssClass) != 0) {
  1049. $form .= ' class="'.$this->cssClass.'"';
  1050. }
  1051. if(strlen($this->encType) != 0) {
  1052. $form .= ' enctype="'.$this->encType.'"';
  1053. }
  1054. $form .= '><fieldset>'."\n";
  1055. if(strlen($this->legend) != 0) {
  1056. $form .= '<legend>'.$this->legend.'</legend>';
  1057. }
  1058.  
  1059. foreach($this->fields as $field) {
  1060. //Should we add an label?
  1061. if(strlen($field['displayName']) != 0) {
  1062. //Add a label for the field.
  1063. $id = $field['field']->getId();
  1064. if(strlen($id) == 0) {
  1065. //We have to define an id for the field, use the name.
  1066. $id = $field['field']->getName();
  1067. $field['field']->setId($id);
  1068. }
  1069. $form .= $field['field']->formatAddition('<label for="%id">'.
  1070. $field['displayName'].'</label>'."\n");
  1071. }
  1072.  
  1073. if($this->displayErrors && $this->hasAnyUserValue()) {
  1074. //Check if there is an error.
  1075. if(!$field['field']->isValid()) {
  1076. //Add the error message
  1077. $form .= '<span class="error">'.$field['field']->getError().'</span>';
  1078. }
  1079. }
  1080.  
  1081. //Add the field itself
  1082. $form .= $field['field']->getAsHtml()."\n";
  1083. if(is_subclass_of($field['field'], 'SizedField')) {
  1084. $form .= '<br />';
  1085. }
  1086. }
  1087.  
  1088. $form .= '</fieldset></form>';
  1089. return $form;
  1090. }
  1091.  
  1092. /**
  1093. * @see Validatable.isValid()
  1094. */
  1095. public function isValid() {
  1096. foreach($this->fields as $field) {
  1097. if(!$field['field']->isValid()) {
  1098. return false;
  1099. }
  1100. }
  1101. return true;
  1102. }
  1103.  
  1104. /**
  1105. * @see Validatable.getError()
  1106. */
  1107. public function getError() {
  1108. return 'The form is not correctly filled out.';
  1109. }
  1110.  
  1111. /**
  1112. * Gets the field instance corresponding to the given (field) name.
  1113. * @param string $name The name of the field to search for.
  1114. * @return Field The requested field (if one is found), false otherwise.
  1115. */
  1116. public function getField($name) {
  1117. foreach($this->fields as $field) {
  1118. if($field['field']->getName() == $name) {
  1119. return $field['field'];
  1120. }
  1121. }
  1122. return false;
  1123. }
  1124.  
  1125. /**
  1126. * Gets the value of one of the form's fields.
  1127. * @param string $fieldName The name of the field to get the value for.
  1128. * @return mixed The value of the field (if the field was found), an
  1129. * empty string otherwise.
  1130. */
  1131. public function getValue($fieldName) {
  1132. $field = $this->getField($fieldName);
  1133. if($field === false) {
  1134. return '';
  1135. } else {
  1136. return $field->getValue();
  1137. }
  1138. }
  1139. /**
  1140. * Checks if the form has a field with the specified name and if that
  1141. * field has a non empty value.
  1142. * @param string $fieldName The name of the field to check.
  1143. * @return boolean True if the field exists and has a non empty value,
  1144. * false otherwise.
  1145. */
  1146. public function hasValue($fieldName) {
  1147. $field = $this->getField($fieldName);
  1148. if($field === false) {
  1149. return false;
  1150. }
  1151. return $field->hasValue();
  1152. }
  1153. /**
  1154. * Sets a specified field's value to a new specified value.
  1155. * @param string $fieldName The name of the field which's value should be
  1156. * set.
  1157. * @param mixed $newValue The new value that should be used.
  1158. */
  1159. public function setValue($fieldName, $newValue) {
  1160. $this->getField($fieldName)->setValue($newValue);
  1161. }
  1162. /**
  1163. * Removes all recorded field values from the form.
  1164. */
  1165. public function clear() {
  1166. foreach($this->fields as $field) {
  1167. $field['field']->clear();
  1168. }
  1169. }
  1170. /**
  1171. * Sets if the form should display errors or not (the default is true).
  1172. * @param boolean $newVal True if errors should be displayed, false
  1173. * otherwise.
  1174. */
  1175. public function setDisplayErrors($newVal) {
  1176. $this->displayErrors = $newVal;
  1177. }
  1178. /**
  1179. * Sets the css class to be used by the form element.
  1180. * @param string $newCssClass The new css class name to use.
  1181. */
  1182. public function setCssClass($newCssClass) {
  1183. $this->cssClass = $newCssClass;
  1184. }
  1185. /**
  1186. * Removes the first field encountered with the specified field name.
  1187. * @param string $fieldName The name of the field that should be removed.
  1188. */
  1189. public function removeField($fieldName) {
  1190. foreach($this->fields as $key => $field) {
  1191. if($field['field']->getName() == $fieldName) {
  1192. unset($this->fields[$key]);
  1193. return;
  1194. }
  1195. }
  1196. }
  1197. /**
  1198. * Checks if any of the form's fields has any user set values.
  1199. * @return boolean True if at least a field has a non empty value that
  1200. * has been set by a user, false otherwise.
  1201. */
  1202. public function hasAnyUserValue() {
  1203. foreach($this->fields as $field) {
  1204. if($field['field']->hasUserValue()) {
  1205. return true;
  1206. }
  1207. }
  1208. return false;
  1209. }
  1210. }
  1211.  
  1212. ?>

Documentation generated on Sun, 16 Apr 2006 21:03:26 +0200 by phpDocumentor 1.3.0RC4