Query/tests/simpletest/form.php

361 lines
12 KiB
PHP

<?php
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id: form.php 2013 2011-04-29 09:29:45Z pp11 $
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/selector.php');
/**#@-*/
/**
* Form tag class to hold widget values.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleForm {
private $method;
private $action;
private $encoding;
private $default_target;
private $id;
private $buttons;
private $images;
private $widgets;
private $radios;
private $checkboxes;
/**
* Starts with no held controls/widgets.
* @param SimpleTag $tag Form tag to read.
* @param SimplePage $page Holding page.
*/
function __construct($tag, $page) {
$this->method = $tag->getAttribute('method');
$this->action = $this->createAction($tag->getAttribute('action'), $page);
$this->encoding = $this->setEncodingClass($tag);
$this->default_target = false;
$this->id = $tag->getAttribute('id');
$this->buttons = array();
$this->images = array();
$this->widgets = array();
$this->radios = array();
$this->checkboxes = array();
}
/**
* Creates the request packet to be sent by the form.
* @param SimpleTag $tag Form tag to read.
* @return string Packet class.
* @access private
*/
protected function setEncodingClass($tag) {
if (strtolower($tag->getAttribute('method')) == 'post') {
if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') {
return 'SimpleMultipartEncoding';
}
return 'SimplePostEncoding';
}
return 'SimpleGetEncoding';
}
/**
* Sets the frame target within a frameset.
* @param string $frame Name of frame.
* @access public
*/
function setDefaultTarget($frame) {
$this->default_target = $frame;
}
/**
* Accessor for method of form submission.
* @return string Either get or post.
* @access public
*/
function getMethod() {
return ($this->method ? strtolower($this->method) : 'get');
}
/**
* Combined action attribute with current location
* to get an absolute form target.
* @param string $action Action attribute from form tag.
* @param SimpleUrl $base Page location.
* @return SimpleUrl Absolute form target.
*/
protected function createAction($action, $page) {
if (($action === '') || ($action === false)) {
return $page->expandUrl($page->getUrl());
}
return $page->expandUrl(new SimpleUrl($action));;
}
/**
* Absolute URL of the target.
* @return SimpleUrl URL target.
* @access public
*/
function getAction() {
$url = $this->action;
if ($this->default_target && ! $url->getTarget()) {
$url->setTarget($this->default_target);
}
if ($this->getMethod() == 'get') {
$url->clearRequest();
}
return $url;
}
/**
* Creates the encoding for the current values in the
* form.
* @return SimpleFormEncoding Request to submit.
* @access private
*/
protected function encode() {
$class = $this->encoding;
$encoding = new $class();
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
$this->widgets[$i]->write($encoding);
}
return $encoding;
}
/**
* ID field of form for unique identification.
* @return string Unique tag ID.
* @access public
*/
function getId() {
return $this->id;
}
/**
* Adds a tag contents to the form.
* @param SimpleWidget $tag Input tag to add.
*/
function addWidget($tag) {
if (strtolower($tag->getAttribute('type')) == 'submit') {
$this->buttons[] = $tag;
} elseif (strtolower($tag->getAttribute('type')) == 'image') {
$this->images[] = $tag;
} elseif ($tag->getName()) {
$this->setWidget($tag);
}
}
/**
* Sets the widget into the form, grouping radio
* buttons if any.
* @param SimpleWidget $tag Incoming form control.
* @access private
*/
protected function setWidget($tag) {
if (strtolower($tag->getAttribute('type')) == 'radio') {
$this->addRadioButton($tag);
} elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
$this->addCheckbox($tag);
} else {
$this->widgets[] = &$tag;
}
}
/**
* Adds a radio button, building a group if necessary.
* @param SimpleRadioButtonTag $tag Incoming form control.
* @access private
*/
protected function addRadioButton($tag) {
if (! isset($this->radios[$tag->getName()])) {
$this->widgets[] = new SimpleRadioGroup();
$this->radios[$tag->getName()] = count($this->widgets) - 1;
}
$this->widgets[$this->radios[$tag->getName()]]->addWidget($tag);
}
/**
* Adds a checkbox, making it a group on a repeated name.
* @param SimpleCheckboxTag $tag Incoming form control.
* @access private
*/
protected function addCheckbox($tag) {
if (! isset($this->checkboxes[$tag->getName()])) {
$this->widgets[] = $tag;
$this->checkboxes[$tag->getName()] = count($this->widgets) - 1;
} else {
$index = $this->checkboxes[$tag->getName()];
if (! SimpleTestCompatibility::isA($this->widgets[$index], 'SimpleCheckboxGroup')) {
$previous = $this->widgets[$index];
$this->widgets[$index] = new SimpleCheckboxGroup();
$this->widgets[$index]->addWidget($previous);
}
$this->widgets[$index]->addWidget($tag);
}
}
/**
* Extracts current value from form.
* @param SimpleSelector $selector Criteria to apply.
* @return string/array Value(s) as string or null
* if not set.
* @access public
*/
function getValue($selector) {
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
if ($selector->isMatch($this->widgets[$i])) {
return $this->widgets[$i]->getValue();
}
}
foreach ($this->buttons as $button) {
if ($selector->isMatch($button)) {
return $button->getValue();
}
}
return null;
}
/**
* Sets a widget value within the form.
* @param SimpleSelector $selector Criteria to apply.
* @param string $value Value to input into the widget.
* @return boolean True if value is legal, false
* otherwise. If the field is not
* present, nothing will be set.
* @access public
*/
function setField($selector, $value, $position=false) {
$success = false;
$_position = 0;
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
if ($selector->isMatch($this->widgets[$i])) {
$_position++;
if ($position === false or $_position === (int)$position) {
if ($this->widgets[$i]->setValue($value)) {
$success = true;
}
}
}
}
return $success;
}
/**
* Used by the page object to set widgets labels to
* external label tags.
* @param SimpleSelector $selector Criteria to apply.
* @access public
*/
function attachLabelBySelector($selector, $label) {
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
if ($selector->isMatch($this->widgets[$i])) {
if (method_exists($this->widgets[$i], 'setLabel')) {
$this->widgets[$i]->setLabel($label);
return;
}
}
}
}
/**
* Test to see if a form has a submit button.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasSubmit($selector) {
foreach ($this->buttons as $button) {
if ($selector->isMatch($button)) {
return true;
}
}
return false;
}
/**
* Test to see if a form has an image control.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasImage($selector) {
foreach ($this->images as $image) {
if ($selector->isMatch($image)) {
return true;
}
}
return false;
}
/**
* Gets the submit values for a selected button.
* @param SimpleSelector $selector Criteria to apply.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button
* in the form.
* @access public
*/
function submitButton($selector, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->buttons as $button) {
if ($selector->isMatch($button)) {
$encoding = $this->encode();
$button->write($encoding);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Gets the submit values for an image.
* @param SimpleSelector $selector Criteria to apply.
* @param integer $x X-coordinate of click.
* @param integer $y Y-coordinate of click.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button in the
* form.
* @access public
*/
function submitImage($selector, $x, $y, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->images as $image) {
if ($selector->isMatch($image)) {
$encoding = $this->encode();
$image->write($encoding, $x, $y);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Simply submits the form without the submit button
* value. Used when there is only one button or it
* is unimportant.
* @return hash Submitted values.
* @access public
*/
function submit($additional = false) {
$encoding = $this->encode();
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
?>