value * @param $optArg if something was passed in on the attribute value as well as this one, then the attribute * value becomes this value */ public function __construct($attribute = null, $optArg = null) { $this->extraData = array(); $this->autoAddSubmit = true; $tmpName = ""; if (is_array($optArg)) { $tmpName = $attribute; $attribute = $optArg; } // Create the FieldSet2 $this->fields = Form2::factory("FieldSet", array("fields")); parent::__construct($tmpName, $attribute); // Give this form a unique name if none was passed in if (!$this->name) $this->name = "form_" . ++self::$numForms; // Add a hidden field to check for form submission $submit = &$this->add("HiddenField", "submit_$this->name", array("value" => $this->name, "ignore" => true)); $this->idName = $this->idName ? $this->idName : "id"; // Add some tracking for sub forms if ($this->parentIdName) $this->add("HiddenField", "{$this->name}_{$this->idName}", array("ignore" => true)); } /** @overload Attribute::validateAttribute */ public function validateAttribute($name, $value) { switch ($name) { case "layout": errorFatal("You must use the get/set member functions for layout work"); case "database": $this->attributeArray['database'] = dbInit($value); return false; break; case "action": $this->url = $value; break; case "id": $this->id = $id; break; default: return parent::validateAttribute($name, $value); break; } } /** * Function to set the layout for the form */ public function setLayout($name, $options = null) { $this->fields->setLayout($name, $options); } /** @overload Attribute::setAttribute */ public function clearAttribute($name) { switch ($name) { case "name": case "layout": errorFatal("Cannot remove attribute $name. Try changing it with \$form->$name instead."); break; default: parent::clearAttribute($name); break; } } /** * @b Private. Merges the given attribute and value with the * attributes list. If null is sent as the value, clears that * attribute. This function will also take necessary action if a * special attribute is passed in, such as creating a new layout. * @private * * @param $name the attribute name * @param $value the attribute value */ private function mergeAttribute($name, $value) { // Do nothing if no name is passed in if ($name === null) { return; } // Clear the attribute if null is passed in for the value else if ($value === null) { $this->clearAttribute($name); } else { // Merge this attribute with the master list $this->attributes[$name] = $value; } } /** * Sets the data associated with this form. If @c $data is a database * result, the method ensures that the result only contains one row and * uses that row. * * @param $data a database result set or associative array of field name->value */ public function setData($data) { if (dbIsResultSet($data)) { if (dbGetNumRows($data) != 1) errorFatal("Form::setData(): singularity constraint violated (rows = " . dbGetNumRows($data) . ")"); $data = dbTryFetchAssoc($data); } if (!is_array($data)) return; if ($data["{$this->table}_{$this->idName}"]) $this->id = $data["{$this->table}_{$this->idName}"]; $this->fields->setData($data); } public function getData($name = null) { return $this->fields->getData($name); } public function hasField($name) { return $this->fields->hasField($name); } public function ignore($name) { $this->fields->ignore($name); } /** * Validates the data in a single field, or all the fields in this form * if nothing is passed in. * * @param $name the name of the field to validate */ public function validate($name = null) { $ret = $this->fields->validate($name); // parent::validate(); if ($this->parentIdName) $this->id = $this->getData("{$this->name}_{$this->idName}"); return $ret; } /** * Gets the SQL data for the entire form. */ public function getSqlData() { $sql = $this->fields->getSqlData(); $tmp = array($sql); foreach ($this->extraData as $column => $data) { $tmp[] = "$column = $data"; } if (count($tmp) > 1) $sql = implode(",\n", $tmp); return $sql; } /** * Adds something to the sink directly in the sql * @param $column is the column to be added * @param $data is the data for the column, it is not quoted */ public function addData($column, $data) { $this->extraData[$column] = $data; } /** * Sinks the form with a database. * * @return the id of the row in the database */ public function sink($parentId = null) { $database = &$this->database; $table = $this->table; $idName = $this->idName; $id = $this->id ? $this->id : "NULL"; $sql = $this->getSqlData(); if ($sql) $sql = array($sql); if ($parentId && $this->parentIdName) { if ($this->parentIdName != $idName) $sql[] = "$this->parentIdName = $parentId"; else $id = $parentId; } $sql = implode(",\n", $sql); if ($sql) { $newId = dbExecute(" INSERT INTO $table SET $idName = $id, $sql ON DUPLICATE KEY UPDATE $sql ", true, $database); } else if ($table) { $newId = dbExecute("INSERT INTO $table VALUES ()", false, $database); } if ($newId != $id) $this->setData(array("{$this->table}_{$this->idName}" => $newId)); $ret = (int)($newId ? $newId : $id); $this->fields->sink($ret); return $ret; } /** * Gets the layout object. * * @return the layout object */ public function &getLayout() { return $this->fields->getLayout(); } /** * Adds a Field object to the form * * @param $field the field type * @param $name the name of the field * @param $attributes an associative array of attribute to value * @param $required if the field is required * @param $title field title * * @return a reference to the field */ public function &add($field, $name, $attributes = null, $required = null, $title = null) { if ($required !== null) $attributes["required"] = $required; if ($title !== null) $attributes["title"] = $title; return $this->fields->add($field, $name, $attributes); } /** * Removes a field from the form * * @param $fieldName the field type */ public function remove($fieldName) { $this->fields->remove($fieldName); } /** * Draws a standard header for a form that posts back to itself. * * @param $id the value of the @c "id" param * @param $params additional parameters appended to the URL * @param $drawLayout should the layout be used to draw the header */ public function drawHeader($id, $params = null, $drawLayout = true) { if (!$this->url) { $url = htmlspecialchars($_SERVER["SCRIPT_NAME"]); if ($id) $url .= "?id=$id"; if ($params) $url = utilAddUrlParams($url, $params); } else $url = $this->url; // Check to see if we need multipart encoding $enctype = null; if ($this->fields->isMultiPart()) $enctype = "enctype=\"multipart/form-data\""; echo "
\n"; } /** * Draws all the rows of the form */ public function drawAllRows() { $this->fields->drawAllRows(); } /** * Draws the given field. * * @param $name the field name */ public function draw($name = null) { $this->fields->draw($name); } /** * Draws the given field. * * @param $name the field name */ public function drawRow($name) { $this->fields->drawRow($name); } /** * Draws all hidden fields. */ public function drawHiddenFields($position = "begin") { $this->fields->drawHiddenFields($position); } /** * Draws the entire form. This is equivalent to calling drawHeader(), * drawAllRows(), and drawFooter(). * * @param $id passed to drawHeader() * @param $params an optional string to be appended on the URL. Passed to drawHeader() */ public function drawAll($id = null, $params = null) { if (!$this->fields->hasField("submit") && $this->autoAddSubmit == true) $this->add("SubmitButton", "submit"); if (!$id) $id = $this->id; $this->drawHeader($id, $params); $this->drawAllRows(); $this->drawFooter(); } /** * Checks to see if the form is submtited. * * @return true if the form has been submitted */ public function isSubmitted() { return $_POST["submit_$this->name"] == $this->name; } /** * Event function to allow this form to be a sub form in a greater form * @param $layout is the layout to use for drawing stuff * FIXME: This should be using the layout passed into it. */ public function onDrawRow(&$layout) { $this->draw(); } /** * Checks to see if this form has an error * @return true or false depending on the existance of an error */ public function hasError() { return $this->fields->hasError(); } /** * Retrieve the error for this form * @return the error of the form, if it exists */ public function getError() { return $this->fields->getError(); } /** * Set an error on a field at will * @param $name is the name of the field * @param $message is the message to be set as the error */ public function setError($name, $message) { return $this->fields->setError($name, $message); } /** * Creates an instance of a class and dynamically includes the source * * @param $type the field type * @param $options the options for the constructor * @return the new field */ public static function factory($type, $options = null) { $paramList = array(); for ($i = 0; $i < count($options); $i++) $paramList[$i] = '$options[' . $i . ']'; $paramList = implode($paramList, ","); return eval("return new {$type}2($paramList);"); } } /** @} */ ?>