form.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. <?php
  2. /**
  3. * Base include file for SimpleTest.
  4. * @package SimpleTest
  5. * @subpackage WebTester
  6. * @version $Id: form.php 1784 2008-04-26 13:07:14Z pp11 $
  7. */
  8. /**#@+
  9. * include SimpleTest files
  10. */
  11. require_once(dirname(__FILE__) . '/tag.php');
  12. require_once(dirname(__FILE__) . '/encoding.php');
  13. require_once(dirname(__FILE__) . '/selector.php');
  14. /**#@-*/
  15. /**
  16. * Form tag class to hold widget values.
  17. * @package SimpleTest
  18. * @subpackage WebTester
  19. */
  20. class SimpleForm {
  21. private $method;
  22. private $action;
  23. private $encoding;
  24. private $default_target;
  25. private $id;
  26. private $buttons;
  27. private $images;
  28. private $widgets;
  29. private $radios;
  30. private $checkboxes;
  31. /**
  32. * Starts with no held controls/widgets.
  33. * @param SimpleTag $tag Form tag to read.
  34. * @param SimplePage $page Holding page.
  35. */
  36. function __construct($tag, $page) {
  37. $this->method = $tag->getAttribute('method');
  38. $this->action = $this->createAction($tag->getAttribute('action'), $page);
  39. $this->encoding = $this->setEncodingClass($tag);
  40. $this->default_target = false;
  41. $this->id = $tag->getAttribute('id');
  42. $this->buttons = array();
  43. $this->images = array();
  44. $this->widgets = array();
  45. $this->radios = array();
  46. $this->checkboxes = array();
  47. }
  48. /**
  49. * Creates the request packet to be sent by the form.
  50. * @param SimpleTag $tag Form tag to read.
  51. * @return string Packet class.
  52. * @access private
  53. */
  54. protected function setEncodingClass($tag) {
  55. if (strtolower($tag->getAttribute('method')) == 'post') {
  56. if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') {
  57. return 'SimpleMultipartEncoding';
  58. }
  59. return 'SimplePostEncoding';
  60. }
  61. return 'SimpleGetEncoding';
  62. }
  63. /**
  64. * Sets the frame target within a frameset.
  65. * @param string $frame Name of frame.
  66. * @access public
  67. */
  68. function setDefaultTarget($frame) {
  69. $this->default_target = $frame;
  70. }
  71. /**
  72. * Accessor for method of form submission.
  73. * @return string Either get or post.
  74. * @access public
  75. */
  76. function getMethod() {
  77. return ($this->method ? strtolower($this->method) : 'get');
  78. }
  79. /**
  80. * Combined action attribute with current location
  81. * to get an absolute form target.
  82. * @param string $action Action attribute from form tag.
  83. * @param SimpleUrl $base Page location.
  84. * @return SimpleUrl Absolute form target.
  85. */
  86. protected function createAction($action, $page) {
  87. if (($action === '') || ($action === false)) {
  88. return $page->expandUrl($page->getUrl());
  89. }
  90. return $page->expandUrl(new SimpleUrl($action));;
  91. }
  92. /**
  93. * Absolute URL of the target.
  94. * @return SimpleUrl URL target.
  95. * @access public
  96. */
  97. function getAction() {
  98. $url = $this->action;
  99. if ($this->default_target && ! $url->getTarget()) {
  100. $url->setTarget($this->default_target);
  101. }
  102. return $url;
  103. }
  104. /**
  105. * Creates the encoding for the current values in the
  106. * form.
  107. * @return SimpleFormEncoding Request to submit.
  108. * @access private
  109. */
  110. protected function encode() {
  111. $class = $this->encoding;
  112. $encoding = new $class();
  113. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  114. $this->widgets[$i]->write($encoding);
  115. }
  116. return $encoding;
  117. }
  118. /**
  119. * ID field of form for unique identification.
  120. * @return string Unique tag ID.
  121. * @access public
  122. */
  123. function getId() {
  124. return $this->id;
  125. }
  126. /**
  127. * Adds a tag contents to the form.
  128. * @param SimpleWidget $tag Input tag to add.
  129. * @access public
  130. */
  131. function addWidget($tag) {
  132. if (strtolower($tag->getAttribute('type')) == 'submit') {
  133. $this->buttons[] = $tag;
  134. } elseif (strtolower($tag->getAttribute('type')) == 'image') {
  135. $this->images[] = $tag;
  136. } elseif ($tag->getName()) {
  137. $this->setWidget($tag);
  138. }
  139. }
  140. /**
  141. * Sets the widget into the form, grouping radio
  142. * buttons if any.
  143. * @param SimpleWidget $tag Incoming form control.
  144. * @access private
  145. */
  146. protected function setWidget($tag) {
  147. if (strtolower($tag->getAttribute('type')) == 'radio') {
  148. $this->addRadioButton($tag);
  149. } elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
  150. $this->addCheckbox($tag);
  151. } else {
  152. $this->widgets[] = &$tag;
  153. }
  154. }
  155. /**
  156. * Adds a radio button, building a group if necessary.
  157. * @param SimpleRadioButtonTag $tag Incoming form control.
  158. * @access private
  159. */
  160. protected function addRadioButton($tag) {
  161. if (! isset($this->radios[$tag->getName()])) {
  162. $this->widgets[] = new SimpleRadioGroup();
  163. $this->radios[$tag->getName()] = count($this->widgets) - 1;
  164. }
  165. $this->widgets[$this->radios[$tag->getName()]]->addWidget($tag);
  166. }
  167. /**
  168. * Adds a checkbox, making it a group on a repeated name.
  169. * @param SimpleCheckboxTag $tag Incoming form control.
  170. * @access private
  171. */
  172. protected function addCheckbox($tag) {
  173. if (! isset($this->checkboxes[$tag->getName()])) {
  174. $this->widgets[] = $tag;
  175. $this->checkboxes[$tag->getName()] = count($this->widgets) - 1;
  176. } else {
  177. $index = $this->checkboxes[$tag->getName()];
  178. if (! SimpleTestCompatibility::isA($this->widgets[$index], 'SimpleCheckboxGroup')) {
  179. $previous = $this->widgets[$index];
  180. $this->widgets[$index] = new SimpleCheckboxGroup();
  181. $this->widgets[$index]->addWidget($previous);
  182. }
  183. $this->widgets[$index]->addWidget($tag);
  184. }
  185. }
  186. /**
  187. * Extracts current value from form.
  188. * @param SimpleSelector $selector Criteria to apply.
  189. * @return string/array Value(s) as string or null
  190. * if not set.
  191. * @access public
  192. */
  193. function getValue($selector) {
  194. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  195. if ($selector->isMatch($this->widgets[$i])) {
  196. return $this->widgets[$i]->getValue();
  197. }
  198. }
  199. foreach ($this->buttons as $button) {
  200. if ($selector->isMatch($button)) {
  201. return $button->getValue();
  202. }
  203. }
  204. return null;
  205. }
  206. /**
  207. * Sets a widget value within the form.
  208. * @param SimpleSelector $selector Criteria to apply.
  209. * @param string $value Value to input into the widget.
  210. * @return boolean True if value is legal, false
  211. * otherwise. If the field is not
  212. * present, nothing will be set.
  213. * @access public
  214. */
  215. function setField($selector, $value, $position=false) {
  216. $success = false;
  217. $_position = 0;
  218. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  219. if ($selector->isMatch($this->widgets[$i])) {
  220. $_position++;
  221. if ($position === false or $_position === (int)$position) {
  222. if ($this->widgets[$i]->setValue($value)) {
  223. $success = true;
  224. }
  225. }
  226. }
  227. }
  228. return $success;
  229. }
  230. /**
  231. * Used by the page object to set widgets labels to
  232. * external label tags.
  233. * @param SimpleSelector $selector Criteria to apply.
  234. * @access public
  235. */
  236. function attachLabelBySelector($selector, $label) {
  237. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  238. if ($selector->isMatch($this->widgets[$i])) {
  239. if (method_exists($this->widgets[$i], 'setLabel')) {
  240. $this->widgets[$i]->setLabel($label);
  241. return;
  242. }
  243. }
  244. }
  245. }
  246. /**
  247. * Test to see if a form has a submit button.
  248. * @param SimpleSelector $selector Criteria to apply.
  249. * @return boolean True if present.
  250. * @access public
  251. */
  252. function hasSubmit($selector) {
  253. foreach ($this->buttons as $button) {
  254. if ($selector->isMatch($button)) {
  255. return true;
  256. }
  257. }
  258. return false;
  259. }
  260. /**
  261. * Test to see if a form has an image control.
  262. * @param SimpleSelector $selector Criteria to apply.
  263. * @return boolean True if present.
  264. * @access public
  265. */
  266. function hasImage($selector) {
  267. foreach ($this->images as $image) {
  268. if ($selector->isMatch($image)) {
  269. return true;
  270. }
  271. }
  272. return false;
  273. }
  274. /**
  275. * Gets the submit values for a selected button.
  276. * @param SimpleSelector $selector Criteria to apply.
  277. * @param hash $additional Additional data for the form.
  278. * @return SimpleEncoding Submitted values or false
  279. * if there is no such button
  280. * in the form.
  281. * @access public
  282. */
  283. function submitButton($selector, $additional = false) {
  284. $additional = $additional ? $additional : array();
  285. foreach ($this->buttons as $button) {
  286. if ($selector->isMatch($button)) {
  287. $encoding = $this->encode();
  288. $button->write($encoding);
  289. if ($additional) {
  290. $encoding->merge($additional);
  291. }
  292. return $encoding;
  293. }
  294. }
  295. return false;
  296. }
  297. /**
  298. * Gets the submit values for an image.
  299. * @param SimpleSelector $selector Criteria to apply.
  300. * @param integer $x X-coordinate of click.
  301. * @param integer $y Y-coordinate of click.
  302. * @param hash $additional Additional data for the form.
  303. * @return SimpleEncoding Submitted values or false
  304. * if there is no such button in the
  305. * form.
  306. * @access public
  307. */
  308. function submitImage($selector, $x, $y, $additional = false) {
  309. $additional = $additional ? $additional : array();
  310. foreach ($this->images as $image) {
  311. if ($selector->isMatch($image)) {
  312. $encoding = $this->encode();
  313. $image->write($encoding, $x, $y);
  314. if ($additional) {
  315. $encoding->merge($additional);
  316. }
  317. return $encoding;
  318. }
  319. }
  320. return false;
  321. }
  322. /**
  323. * Simply submits the form without the submit button
  324. * value. Used when there is only one button or it
  325. * is unimportant.
  326. * @return hash Submitted values.
  327. * @access public
  328. */
  329. function submit() {
  330. return $this->encode();
  331. }
  332. }
  333. ?>