form.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. /**
  3. * Base include file for SimpleTest.
  4. * @package SimpleTest
  5. * @subpackage WebTester
  6. * @version $Id$
  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. if ($this->getMethod() == 'get') {
  103. $url->clearRequest();
  104. }
  105. return $url;
  106. }
  107. /**
  108. * Creates the encoding for the current values in the
  109. * form.
  110. * @return SimpleFormEncoding Request to submit.
  111. * @access private
  112. */
  113. protected function encode() {
  114. $class = $this->encoding;
  115. $encoding = new $class();
  116. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  117. $this->widgets[$i]->write($encoding);
  118. }
  119. return $encoding;
  120. }
  121. /**
  122. * ID field of form for unique identification.
  123. * @return string Unique tag ID.
  124. * @access public
  125. */
  126. function getId() {
  127. return $this->id;
  128. }
  129. /**
  130. * Adds a tag contents to the form.
  131. * @param SimpleWidget $tag Input tag to add.
  132. */
  133. function addWidget($tag) {
  134. if (strtolower($tag->getAttribute('type')) == 'submit') {
  135. $this->buttons[] = $tag;
  136. } elseif (strtolower($tag->getAttribute('type')) == 'image') {
  137. $this->images[] = $tag;
  138. } elseif ($tag->getName()) {
  139. $this->setWidget($tag);
  140. }
  141. }
  142. /**
  143. * Sets the widget into the form, grouping radio
  144. * buttons if any.
  145. * @param SimpleWidget $tag Incoming form control.
  146. * @access private
  147. */
  148. protected function setWidget($tag) {
  149. if (strtolower($tag->getAttribute('type')) == 'radio') {
  150. $this->addRadioButton($tag);
  151. } elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
  152. $this->addCheckbox($tag);
  153. } else {
  154. $this->widgets[] = &$tag;
  155. }
  156. }
  157. /**
  158. * Adds a radio button, building a group if necessary.
  159. * @param SimpleRadioButtonTag $tag Incoming form control.
  160. * @access private
  161. */
  162. protected function addRadioButton($tag) {
  163. if (! isset($this->radios[$tag->getName()])) {
  164. $this->widgets[] = new SimpleRadioGroup();
  165. $this->radios[$tag->getName()] = count($this->widgets) - 1;
  166. }
  167. $this->widgets[$this->radios[$tag->getName()]]->addWidget($tag);
  168. }
  169. /**
  170. * Adds a checkbox, making it a group on a repeated name.
  171. * @param SimpleCheckboxTag $tag Incoming form control.
  172. * @access private
  173. */
  174. protected function addCheckbox($tag) {
  175. if (! isset($this->checkboxes[$tag->getName()])) {
  176. $this->widgets[] = $tag;
  177. $this->checkboxes[$tag->getName()] = count($this->widgets) - 1;
  178. } else {
  179. $index = $this->checkboxes[$tag->getName()];
  180. if (! SimpleTestCompatibility::isA($this->widgets[$index], 'SimpleCheckboxGroup')) {
  181. $previous = $this->widgets[$index];
  182. $this->widgets[$index] = new SimpleCheckboxGroup();
  183. $this->widgets[$index]->addWidget($previous);
  184. }
  185. $this->widgets[$index]->addWidget($tag);
  186. }
  187. }
  188. /**
  189. * Extracts current value from form.
  190. * @param SimpleSelector $selector Criteria to apply.
  191. * @return string/array Value(s) as string or null
  192. * if not set.
  193. * @access public
  194. */
  195. function getValue($selector) {
  196. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  197. if ($selector->isMatch($this->widgets[$i])) {
  198. return $this->widgets[$i]->getValue();
  199. }
  200. }
  201. foreach ($this->buttons as $button) {
  202. if ($selector->isMatch($button)) {
  203. return $button->getValue();
  204. }
  205. }
  206. return null;
  207. }
  208. /**
  209. * Sets a widget value within the form.
  210. * @param SimpleSelector $selector Criteria to apply.
  211. * @param string $value Value to input into the widget.
  212. * @return boolean True if value is legal, false
  213. * otherwise. If the field is not
  214. * present, nothing will be set.
  215. * @access public
  216. */
  217. function setField($selector, $value, $position=false) {
  218. $success = false;
  219. $_position = 0;
  220. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  221. if ($selector->isMatch($this->widgets[$i])) {
  222. $_position++;
  223. if ($position === false or $_position === (int)$position) {
  224. if ($this->widgets[$i]->setValue($value)) {
  225. $success = true;
  226. }
  227. }
  228. }
  229. }
  230. return $success;
  231. }
  232. /**
  233. * Used by the page object to set widgets labels to
  234. * external label tags.
  235. * @param SimpleSelector $selector Criteria to apply.
  236. * @access public
  237. */
  238. function attachLabelBySelector($selector, $label) {
  239. for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
  240. if ($selector->isMatch($this->widgets[$i])) {
  241. if (method_exists($this->widgets[$i], 'setLabel')) {
  242. $this->widgets[$i]->setLabel($label);
  243. return;
  244. }
  245. }
  246. }
  247. }
  248. /**
  249. * Test to see if a form has a submit button.
  250. * @param SimpleSelector $selector Criteria to apply.
  251. * @return boolean True if present.
  252. * @access public
  253. */
  254. function hasSubmit($selector) {
  255. foreach ($this->buttons as $button) {
  256. if ($selector->isMatch($button)) {
  257. return true;
  258. }
  259. }
  260. return false;
  261. }
  262. /**
  263. * Test to see if a form has an image control.
  264. * @param SimpleSelector $selector Criteria to apply.
  265. * @return boolean True if present.
  266. * @access public
  267. */
  268. function hasImage($selector) {
  269. foreach ($this->images as $image) {
  270. if ($selector->isMatch($image)) {
  271. return true;
  272. }
  273. }
  274. return false;
  275. }
  276. /**
  277. * Gets the submit values for a selected button.
  278. * @param SimpleSelector $selector Criteria to apply.
  279. * @param hash $additional Additional data for the form.
  280. * @return SimpleEncoding Submitted values or false
  281. * if there is no such button
  282. * in the form.
  283. * @access public
  284. */
  285. function submitButton($selector, $additional = false) {
  286. $additional = $additional ? $additional : array();
  287. foreach ($this->buttons as $button) {
  288. if ($selector->isMatch($button)) {
  289. $encoding = $this->encode();
  290. $button->write($encoding);
  291. if ($additional) {
  292. $encoding->merge($additional);
  293. }
  294. return $encoding;
  295. }
  296. }
  297. return false;
  298. }
  299. /**
  300. * Gets the submit values for an image.
  301. * @param SimpleSelector $selector Criteria to apply.
  302. * @param integer $x X-coordinate of click.
  303. * @param integer $y Y-coordinate of click.
  304. * @param hash $additional Additional data for the form.
  305. * @return SimpleEncoding Submitted values or false
  306. * if there is no such button in the
  307. * form.
  308. * @access public
  309. */
  310. function submitImage($selector, $x, $y, $additional = false) {
  311. $additional = $additional ? $additional : array();
  312. foreach ($this->images as $image) {
  313. if ($selector->isMatch($image)) {
  314. $encoding = $this->encode();
  315. $image->write($encoding, $x, $y);
  316. if ($additional) {
  317. $encoding->merge($additional);
  318. }
  319. return $encoding;
  320. }
  321. }
  322. return false;
  323. }
  324. /**
  325. * Simply submits the form without the submit button
  326. * value. Used when there is only one button or it
  327. * is unimportant.
  328. * @return hash Submitted values.
  329. * @access public
  330. */
  331. function submit($additional = false) {
  332. $encoding = $this->encode();
  333. if ($additional) {
  334. $encoding->merge($additional);
  335. }
  336. return $encoding;
  337. }
  338. }
  339. ?>