diff --git a/forms/Form.php b/forms/Form.php index 0826d2f17..6699dfa56 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -11,13 +11,13 @@ * can be passed using the URL or get variables. These restrictions are in place so that we can * recreate the form object upon form submission, without the use of a session, which would be too * resource-intensive. - * + * * You will need to create at least one method for processing the submission (through {@link FormAction}). * This method will be passed two parameters: the raw request data, and the form object. * Usually you want to save data into a {@link DataObject} by using {@link saveInto()}. * If you want to process the submitted data in any way, please use {@link getData()} rather than * the raw request data. - * + * *

Validation

* Each form needs some form of {@link Validator} to trigger the {@link FormField->validate()} methods for each field. * You can't disable validator for security reasons, because crucial behaviour like extension checks for file uploads @@ -33,9 +33,9 @@ * You can find out the base URL for your form by looking at the *
value. For example, the edit form in the CMS would be located at * "admin/EditForm". This URL will render the form without its surrounding - * template when called through GET instead of POST. - * - * By appending to this URL, you can render invidual form elements + * template when called through GET instead of POST. + * + * By appending to this URL, you can render individual form elements * through the {@link FormField->FieldHolder()} method. * For example, the "URLSegment" field in a standard CMS form would be * accessible through "admin/EditForm/field/URLSegment/FieldHolder". @@ -53,37 +53,57 @@ class Form extends RequestHandler { * A performance enhancement over the generate-the-form-tag-and-then-remove-it code that was there previously */ public $IncludeFormTag = true; - + + /** + * @var FieldList + */ protected $fields; - + + /** + * @var FieldList + */ protected $actions; /** * @var Controller */ protected $controller; - + + /** + * @var string + */ protected $name; + /** + * @var Validator + */ protected $validator; - + + /** + * @var string + */ protected $formMethod = "post"; /** * @var boolean */ protected $strictFormMethodCheck = false; - - protected static $current_action; - + /** - * @var Dataobject $record Populated by {@link loadDataFrom()}. + * @var string + */ + protected static $current_action; + + /** + * @var DataObject $record Populated by {@link loadDataFrom()}. */ protected $record; /** * Keeps track of whether this form has a default action or not. * Set to false by $this->disableDefaultAction(); + * + * @var boolean */ protected $hasDefaultAction = true; @@ -95,47 +115,59 @@ class Form extends RequestHandler { * @var string */ protected $target; - + /** - * Legend value, to be inserted into the + * Legend value, to be inserted into the * element before the
* in Form.ss template. * * @var string */ protected $legend; - + /** * The SS template to render this form HTML into. * Default is "Form", but this can be changed to * another template for customisation. - * + * * @see Form->setTemplate() * @var string */ protected $template; - - protected $buttonClickedFunc; - - protected $message; - - protected $messageType; - + /** - * Should we redirect the user back down to the + * @var callable + */ + protected $buttonClickedFunc; + + /** + * @var string + */ + protected $message; + + /** + * @var string + */ + protected $messageType; + + /** + * Should we redirect the user back down to the * the form on validation errors rather then just the page - * + * * @var bool */ protected $redirectToFormOnValidationError = false; - + + /** + * @var bool + */ protected $security = true; - + /** * @var SecurityToken */ protected $securityToken = null; - + /** * @var array $extraClasses List of additional CSS classes for the form tag. */ @@ -152,17 +184,25 @@ class Form extends RequestHandler { */ protected $attributes = array(); + /** + * @var array + */ private static $allowed_actions = array( - 'handleField', + 'handleField', 'httpSubmission', 'forTemplate', ); + /** + * @var bool + */ + protected $securityTokenAdded; + /** * Create a new form, with the given fields an action buttons. - * + * * @param Controller $controller The parent controller, necessary to create the appropriate form action tag. - * @param String $name The method on the controller that will return this form object. + * @param string $name The method on the controller that will return this form object. * @param FieldList $fields All of the fields in the form - a {@link FieldList} of {@link FormField} objects. * @param FieldList $actions All of the action buttons in the form - a {@link FieldLis} of * {@link FormAction} objects @@ -170,7 +210,7 @@ class Form extends RequestHandler { */ public function __construct($controller, $name, FieldList $fields, FieldList $actions, $validator = null) { parent::__construct(); - + if(!$fields instanceof FieldList) { throw new InvalidArgumentException('$fields must be a valid FieldList instance'); } @@ -188,7 +228,7 @@ class Form extends RequestHandler { $this->actions = $actions; $this->controller = $controller; $this->name = $name; - + if(!$this->controller) user_error("$this->class form created without a controller", E_USER_ERROR); // Form validation @@ -197,7 +237,7 @@ class Form extends RequestHandler { // Form error controls $this->setupFormErrors(); - + // Check if CSRF protection is enabled, either on the parent controller or from the default setting. Note that // method_exists() is used as some controllers (e.g. GroupTest) do not always extend from Object. if(method_exists($controller, 'securityTokenEnabled') || (method_exists($controller, 'hasMethod') @@ -207,10 +247,13 @@ class Form extends RequestHandler { } else { $securityEnabled = SecurityToken::is_enabled(); } - + $this->securityToken = ($securityEnabled) ? new SecurityToken() : new NullSecurityToken(); } - + + /** + * @var array + */ private static $url_handlers = array( 'field/$FieldName!' => 'handleField', 'POST ' => 'httpSubmission', @@ -221,6 +264,8 @@ class Form extends RequestHandler { /** * Set up current form errors in session to * the current form if appropriate. + * + * @return $this */ public function setupFormErrors() { $errorInfo = Session::get("FormInfo.{$this->FormName()}"); @@ -247,17 +292,20 @@ class Form extends RequestHandler { return $this; } - + /** * Handle a form submission. GET and POST requests behave identically. * Populates the form with {@link loadDataFrom()}, calls {@link validate()}, * and only triggers the requested form action/method * if the form is valid. + * + * @param SS_HTTPRequest $request + * @throws SS_HTTPResponse_Exception */ public function httpSubmission($request) { // Strict method check if($this->strictFormMethodCheck) { - + // Throws an error if the method is bad... if($this->formMethod != strtolower($request->httpMethod())) { $response = Controller::curr()->getResponse(); @@ -265,15 +313,15 @@ class Form extends RequestHandler { $this->httpError(405, _t("Form.BAD_METHOD", "This form requires a ".$this->formMethod." submission")); } - // ...and only uses the vairables corresponding to that method type + // ...and only uses the variables corresponding to that method type $vars = $this->formMethod == 'get' ? $request->getVars() : $request->postVars(); } else { $vars = $request->requestVars(); } - + // Populate the form $this->loadDataFrom($vars, true); - + // Protection against CSRF attacks $token = $this->getSecurityToken(); if( ! $token->checkRequest($request)) { @@ -296,7 +344,7 @@ class Form extends RequestHandler { return $this->controller->redirectBack(); } } - + // Determine the action button clicked $funcName = null; foreach($vars as $paramName => $paramVal) { @@ -308,18 +356,18 @@ class Form extends RequestHandler { parse_str($paramVars, $newRequestParams); $vars = array_merge((array)$vars, (array)$newRequestParams); } - + // Cleanup action_, _x and _y from image fields $funcName = preg_replace(array('/^action_/','/_x$|_y$/'),'',$paramName); break; } } - - // If the action wasnt' set, choose the default on the form. + + // If the action wasn't set, choose the default on the form. if(!isset($funcName) && $defaultAction = $this->defaultAction()){ $funcName = $defaultAction->actionName(); } - + if(isset($funcName)) { Form::set_current_action($funcName); $this->setButtonClicked($funcName); @@ -335,7 +383,7 @@ class Form extends RequestHandler { && !$this->actions->dataFieldByName('action_' . $funcName) ) { return $this->httpError( - 403, + 403, sprintf('Action "%s" not allowed on controller (Class: %s)', $funcName, get_class($this->controller)) ); } elseif( @@ -345,7 +393,7 @@ class Form extends RequestHandler { // all form methods are callable (e.g. the legacy "callfieldmethod()") ) { return $this->httpError( - 403, + 403, sprintf('Action "%s" not allowed on form (Name: "%s")', $funcName, $this->name) ); } @@ -362,17 +410,17 @@ class Form extends RequestHandler { } if (!$fieldsHaveMethod) { return $this->httpError( - 403, + 403, sprintf('Action "%s" not allowed on any fields of form (Name: "%s")', $funcName, $this->Name()) ); } }*/ - + // Validate the form if(!$this->validate()) { return $this->getValidationErrorResponse(); } - + // First, try a handler method on the controller (has been checked for allowed_actions above already) if($this->controller->hasMethod($funcName)) { return $this->controller->$funcName($vars, $this, $request); @@ -382,10 +430,14 @@ class Form extends RequestHandler { } elseif($field = $this->checkFieldsForAction($this->Fields(), $funcName)) { return $field->$funcName($vars, $this, $request); } - + return $this->httpError(404); } + /** + * @param string $action + * @return bool + */ public function checkAccessAction($action) { return ( parent::checkAccessAction($action) @@ -403,15 +455,15 @@ class Form extends RequestHandler { * Returns the appropriate response up the controller chain * if {@link validate()} fails (which is checked prior to executing any form actions). * By default, returns different views for ajax/non-ajax request, and - * handles 'appliction/json' requests with a JSON object containing the error messages. + * handles 'application/json' requests with a JSON object containing the error messages. * Behaviour can be influenced by setting {@link $redirectToFormOnValidationError}. - * + * * @return SS_HTTPResponse|string */ protected function getValidationErrorResponse() { $request = $this->getRequest(); if($request->isAjax()) { - // Special case for legacy Validator.js implementation + // Special case for legacy Validator.js implementation // (assumes eval'ed javascript collected through FormResponse) $acceptType = $request->getHeader('Accept'); if(strpos($acceptType, 'application/json') !== FALSE) { @@ -424,7 +476,7 @@ class Form extends RequestHandler { $response = new SS_HTTPResponse($this->forTemplate()); $response->addHeader('Content-Type', 'text/html'); } - + return $response; } else { if($this->getRedirectToFormOnValidationError()) { @@ -440,10 +492,12 @@ class Form extends RequestHandler { return $this->controller->redirectBack(); } } - + /** * Fields can have action to, let's check if anyone of the responds to $funcname them - * + * + * @param SS_List|array $fields + * @param callable $funcName * @return FormField */ protected function checkFieldsForAction($fields, $funcName) { @@ -465,13 +519,13 @@ class Form extends RequestHandler { * for tabs instead. This means that if you have a tab and a * formfield with the same name, this method gives priority * to the formfield. - * + * * @param SS_HTTPRequest $request * @return FormField */ public function handleField($request) { $field = $this->Fields()->dataFieldByName($request->param('FieldName')); - + if($field) { return $field; } else { @@ -486,19 +540,21 @@ class Form extends RequestHandler { public function makeReadonly() { $this->transform(new ReadonlyTransformation()); } - + /** - * Set whether the user should be redirected back down to the - * form on the page upon validation errors in the form or if + * Set whether the user should be redirected back down to the + * form on the page upon validation errors in the form or if * they just need to redirect back to the page * - * @param bool Redirect to the form + * @param bool $bool + * @return $this + * @internal param Redirect $bool to the form */ public function setRedirectToFormOnValidationError($bool) { $this->redirectToFormOnValidationError = $bool; return $this; } - + /** * Get whether the user should be redirected back down to the * form on the page upon validation errors @@ -512,6 +568,10 @@ class Form extends RequestHandler { /** * Add a plain text error message to a field on this form. It will be saved into the session * and used the next time this form is displayed. + * @param string $fieldName + * @param string $message + * @param string $messageType + * @param bool $escapeHtml */ public function addErrorMessage($fieldName, $message, $messageType, $escapeHtml = true) { Session::add_to_array("FormInfo.{$this->FormName()}.errors", array( @@ -521,6 +581,9 @@ class Form extends RequestHandler { )); } + /** + * @param FormTransformation $trans + */ public function transform(FormTransformation $trans) { $newFields = new FieldList(); foreach($this->fields as $field) { @@ -539,7 +602,7 @@ class Form extends RequestHandler { if($this->validator) $this->validator->removeValidation(); } - + /** * Get the {@link Validator} attached to this form. * @return Validator @@ -550,8 +613,10 @@ class Form extends RequestHandler { /** * Set the {@link Validator} on this form. + * @param Validator $validator + * @return $this */ - public function setValidator( Validator $validator ) { + public function setValidator(Validator $validator ) { if($validator) { $this->validator = $validator; $this->validator->setForm($this); @@ -569,6 +634,7 @@ class Form extends RequestHandler { /** * Convert this form to another format. + * @param FormTransformation $format */ public function transformTo(FormTransformation $format) { $newFields = new FieldList(); @@ -582,48 +648,48 @@ class Form extends RequestHandler { $this->validator->removeValidation(); } - + /** * Generate extra special fields - namely the security token field (if required). - * + * * @return FieldList */ public function getExtraFields() { $extraFields = new FieldList(); - + $token = $this->getSecurityToken(); $tokenField = $token->updateFieldSet($this->fields); if($tokenField) $tokenField->setForm($this); $this->securityTokenAdded = true; - + // add the "real" HTTP method if necessary (for PUT, DELETE and HEAD) if($this->FormMethod() != $this->FormHttpMethod()) { $methodField = new HiddenField('_method', '', $this->FormHttpMethod()); $methodField->setForm($this); $extraFields->push($methodField); } - + return $extraFields; } - + /** * Return the form's fields - used by the templates - * + * * @return FieldList The form fields */ public function Fields() { foreach($this->getExtraFields() as $field) { if(!$this->fields->fieldByName($field->getName())) $this->fields->push($field); } - + return $this->fields; } - + /** * Return all fields * in a form - including fields nested in {@link CompositeFields}. * Useful when doing custom field layouts. - * + * * @return FieldList */ public function HiddenFields() { @@ -637,20 +703,21 @@ class Form extends RequestHandler { public function VisibleFields() { return $this->Fields()->VisibleFields(); } - + /** * Setter for the form fields. * * @param FieldList $fields + * @return $this */ public function setFields($fields) { $this->fields = $fields; return $this; } - + /** * Return the form's action buttons - used by the templates - * + * * @return FieldList The action list */ public function Actions() { @@ -661,12 +728,13 @@ class Form extends RequestHandler { * Setter for the form actions. * * @param FieldList $actions + * @return $this */ public function setActions($actions) { $this->actions = $actions; return $this; } - + /** * Unset all form actions */ @@ -676,8 +744,9 @@ class Form extends RequestHandler { } /** - * @param String - * @param String + * @param string $name + * @param string $value + * @return $this */ public function setAttribute($name, $value) { $this->attributes[$name] = $value; @@ -685,12 +754,15 @@ class Form extends RequestHandler { } /** - * @return String + * @return string $name */ public function getAttribute($name) { if(isset($this->attributes[$name])) return $this->attributes[$name]; } + /** + * @return array + */ public function getAttributes() { $attrs = array( 'id' => $this->FormName(), @@ -712,10 +784,11 @@ class Form extends RequestHandler { /** * Return the attributes of the form tag - used by the templates. - * - * @param Array Custom attributes to process. Falls back to {@link getAttributes()}. + * + * @param array Custom attributes to process. Falls back to {@link getAttributes()}. * If at least one argument is passed as a string, all arguments act as excludes by name. - * @return String HTML attributes, ready for insertion into an HTML tag + * + * @return string HTML attributes, ready for insertion into an HTML tag */ public function getAttributesHTML($attrs = null) { $exclude = (is_string($attrs)) ? func_get_args() : null; @@ -738,12 +811,12 @@ class Form extends RequestHandler { $attrs = $this->getAttributes(); // Remove empty - $attrs = array_filter((array)$attrs, create_function('$v', 'return ($v || $v === 0);')); - + $attrs = array_filter((array)$attrs, create_function('$v', 'return ($v || $v === 0);')); + // Remove excluded if($exclude) $attrs = array_diff_key($attrs, array_flip($exclude)); - // Create markkup + // Create markup $parts = array(); foreach($attrs as $name => $value) { $parts[] = ($value === true) ? "{$name}=\"{$name}\"" : "{$name}=\"" . Convert::raw2att($value) . "\""; @@ -757,41 +830,45 @@ class Form extends RequestHandler { } /** - * Set the target of this form to any value - useful for opening the form contents in a new window or refreshing - * another frame - * - * @param target The value of the target - */ + * Set the target of this form to any value - useful for opening the form contents in a new window or refreshing + * another frame + * + * @param string $target The value of the target + * @return $this + */ public function setTarget($target) { $this->target = $target; return $this; } - + /** * Set the legend value to be inserted into * the element in the Form.ss template. + * @param $legend + * @return $this */ public function setLegend($legend) { $this->legend = $legend; return $this; } - + /** * Set the SS template that this form should use * to render with. The default is "Form". - * + * * @param string $template The name of the template (without the .ss extension) + * @return $this */ public function setTemplate($template) { $this->template = $template; return $this; } - + /** * Return the template to render this form with. * If the template isn't set, then default to the * form class name e.g "Form". - * + * * @return string */ public function getTemplate() { @@ -824,7 +901,8 @@ class Form extends RequestHandler { * Sets the form encoding type. The most common encoding types are defined * in {@link ENC_TYPE_URLENCODED} and {@link ENC_TYPE_MULTIPART}. * - * @param string $enctype + * @param $encType + * @return $this */ public function setEncType($encType) { $this->encType = $encType; @@ -840,18 +918,18 @@ class Form extends RequestHandler { * gets evaluated in {@link Director::direct()}. * See {@link FormMethod()} to get a HTTP method * for safe insertion into a tag. - * + * * @return string HTTP method */ public function FormHttpMethod() { return $this->formMethod; } - + /** * Returns the form method to be used in the tag. * See {@link FormHttpMethod()} to get the "real" method. - * - * @return string Form tag compatbile HTTP method: 'get' or 'post' + * + * @return string Form tag compatible HTTP method: 'get' or 'post' */ public function FormMethod() { if(in_array($this->formMethod,array('get','post'))) { @@ -860,12 +938,13 @@ class Form extends RequestHandler { return 'post'; } } - + /** * Set the form method: GET, POST, PUT, DELETE. - * - * @param $method string - * @param $strict If non-null, pass value to {@link setStrictFormMethodCheck()}. + * + * @param string $method + * @param bool $strict If non-null, pass value to {@link setStrictFormMethodCheck()}. + * @return $this */ public function setFormMethod($method, $strict = null) { $this->formMethod = strtolower($method); @@ -884,6 +963,7 @@ class Form extends RequestHandler { * form. * * @param $bool boolean + * @return $this */ public function setStrictFormMethodCheck($bool) { $this->strictFormMethodCheck = (bool)$bool; @@ -896,12 +976,12 @@ class Form extends RequestHandler { public function getStrictFormMethodCheck() { return $this->strictFormMethodCheck; } - + /** * Return the form's action attribute. * This is build by adding an executeForm get variable to the parent controller's Link() value - * - * @return string + * + * @return string */ public function FormAction() { if ($this->formActionPath) { @@ -912,15 +992,18 @@ class Form extends RequestHandler { return Controller::join_links($this->controller->Link(), $this->name); } } - + /** @ignore */ private $formActionPath = false; - + /** * Set the form action attribute to a custom URL. - * + * * Note: For "normal" forms, you shouldn't need to use this method. It is recommended only for situations where * you have two relatively distinct parts of the system trying to communicate via a form post. + * + * @param string $path + * @return $this */ public function setFormAction($path) { $this->formActionPath = $path; @@ -942,12 +1025,15 @@ class Form extends RequestHandler { /** * Set the HTML ID attribute of the form + * + * @param string $id + * @return $this */ public function setHTMLID($id) { $this->htmlID = $id; return $this; } - + /** * Returns this form's controller. * This is used in the templates. @@ -1005,14 +1091,14 @@ class Form extends RequestHandler { * The next functions store and modify the forms * message attributes. messages are stored in session under * $_SESSION[formname][message]; - * + * * @return string */ public function Message() { $this->getMessageFromSession(); return $this->message; } - + /** * @return string */ @@ -1037,12 +1123,13 @@ class Form extends RequestHandler { /** * Set a status message for the form. - * - * @param message the text of the message - * @param type Should be set to good, bad, or warning. + * + * @param string $message the text of the message + * @param string $type Should be set to good, bad, or warning. * @param boolean $escapeHtml Automatically sanitize the message. Set to FALSE if the message contains HTML. * In that case, you might want to use {@link Convert::raw2xml()} to escape any * user supplied data in the message. + * @return $this */ public function setMessage($message, $type, $escapeHtml = true) { $this->message = ($escapeHtml) ? Convert::raw2xml($message) : $message; @@ -1052,16 +1139,16 @@ class Form extends RequestHandler { /** * Set a message to the session, for display next time this form is shown. - * - * @param message the text of the message - * @param type Should be set to good, bad, or warning. + * + * @param string $message the text of the message + * @param string $type Should be set to good, bad, or warning. * @param boolean $escapeHtml Automatically sanitize the message. Set to FALSE if the message contains HTML. * In that case, you might want to use {@link Convert::raw2xml()} to escape any * user supplied data in the message. */ public function sessionMessage($message, $type, $escapeHtml = true) { Session::set( - "FormInfo.{$this->FormName()}.formError.message", + "FormInfo.{$this->FormName()}.formError.message", $escapeHtml ? Convert::raw2xml($message) : $message ); Session::set("FormInfo.{$this->FormName()}.formError.type", $type); @@ -1069,7 +1156,7 @@ class Form extends RequestHandler { public static function messageForForm( $formName, $message, $type, $escapeHtml = true) { Session::set( - "FormInfo.{$formName}.formError.message", + "FormInfo.{$formName}.formError.message", $escapeHtml ? Convert::raw2xml($message) : $message ); Session::set("FormInfo.{$formName}.formError.type", $type); @@ -1089,13 +1176,13 @@ class Form extends RequestHandler { /** * Returns the DataObject that has given this form its data * through {@link loadDataFrom()}. - * + * * @return DataObject */ public function getRecord() { return $this->record; } - + /** * Get the legend value to be inserted into the * element in Form.ss @@ -1113,7 +1200,7 @@ class Form extends RequestHandler { * Triggered through {@link httpSubmission()}. * Note that CSRF protection takes place in {@link httpSubmission()}, * if it fails the form data will never reach this method. - * + * * @return boolean */ public function validate(){ @@ -1123,7 +1210,7 @@ class Form extends RequestHandler { if($errors){ // Load errors into session and post back $data = $this->getData(); - Session::set("FormInfo.{$this->FormName()}.errors", $errors); + Session::set("FormInfo.{$this->FormName()}.errors", $errors); Session::set("FormInfo.{$this->FormName()}.data", $data); return false; } @@ -1141,20 +1228,20 @@ class Form extends RequestHandler { * If you passed an array, it will call $object[MyField]. * Doesn't save into dataless FormFields ({@link DatalessField}), * as determined by {@link FieldList->dataFields()}. - * + * * By default, if a field isn't set (as determined by isset()), * its value will not be saved to the field, retaining * potential existing values. - * + * * Passed data should not be escaped, and is saved to the FormField instances unescaped. * Escaping happens automatically on saving the data through {@link saveInto()}. - * + * * @uses FieldList->dataFields() * @uses FormField->setValue() - * + * * @param array|DataObject $data * @param int $mergeStrategy - * For every field, {@link $data} is interogated whether it contains a relevant property/key, and + * For every field, {@link $data} is interrogated whether it contains a relevant property/key, and * what that property/key's value is. * * By default, if {@link $data} does contain a property/key, the fields value is always replaced by {@link $data}'s @@ -1172,7 +1259,7 @@ class Form extends RequestHandler { * For backwards compatibility reasons, this parameter can also be set to === true, which is the same as passing * CLEAR_MISSING * - * @param $fieldList An optional list of fields to process. This can be useful when you have a + * @param FieldList $fieldList An optional list of fields to process. This can be useful when you have a * form that has some fields that save to one object, and some that save to another. * @return Form */ @@ -1198,9 +1285,9 @@ class Form extends RequestHandler { if($dataFields) foreach($dataFields as $field) { $name = $field->getName(); - // Skip fields that have been exlcuded + // Skip fields that have been excluded if($fieldList && !in_array($name, $fieldList)) continue; - + // First check looks for (fieldname)_unchanged, an indicator that we shouldn't overwrite the field value if(is_array($data) && isset($data[$name . '_unchanged'])) continue; @@ -1253,13 +1340,13 @@ class Form extends RequestHandler { return $this; } - + /** * Save the contents of this form into the given data object. * It will make use of setCastedField() to do this. - * - * @param $dataObject The object to save data into - * @param $fieldList An optional list of fields to process. This can be useful when you have a + * + * @param DataObjectInterface $dataObject The object to save data into + * @param FieldList $fieldList An optional list of fields to process. This can be useful when you have a * form that has some fields that save to one object, and some that save to another. */ public function saveInto(DataObjectInterface $dataObject, $fieldList = null) { @@ -1282,7 +1369,7 @@ class Form extends RequestHandler { } if($lastField) $lastField->saveInto($dataObject); } - + /** * Get the submitted data from this form through * {@link FieldList->dataFields()}, which filters out @@ -1290,13 +1377,13 @@ class Form extends RequestHandler { * Calls {@link FormField->dataValue()} on each field, * which returns a value suitable for insertion into a DataObject * property. - * + * * @return array */ public function getData() { $dataFields = $this->fields->dataFields(); $data = array(); - + if($dataFields){ foreach($dataFields as $field) { if($field->getName()) { @@ -1311,8 +1398,9 @@ class Form extends RequestHandler { * Call the given method on the given field. * This is used by Ajax-savvy form fields. By putting '&action=callfieldmethod' to the end * of the form action, they can access server-side data. - * @param fieldName The name of the field. Can be overridden by $_REQUEST[fieldName] - * @param methodName The name of the field. Can be overridden by $_REQUEST[methodName] + * + * @param array $data + * @return mixed */ public function callfieldmethod($data) { $fieldName = $data['fieldName']; @@ -1335,12 +1423,11 @@ class Form extends RequestHandler { } else { user_error("Form::callfieldmethod() Field '$fieldName' not found", E_USER_ERROR); } - } /** * Return a rendered version of this form. - * + * * This is returned when you access a form as $FormObject rather * than <% with FormObject %> */ @@ -1365,7 +1452,7 @@ class Form extends RequestHandler { $this->getTemplate(), 'Form' )); - + return $view->dontRewriteHashlinks()->process($this); } @@ -1391,6 +1478,8 @@ class Form extends RequestHandler { /** * Render this form using the given template, and return the result as a string * You can pass either an SSViewer or a template name + * @param string|array $template + * @return HTMLText */ public function renderWithoutActionButton($template) { $custom = $this->customise(array( @@ -1404,13 +1493,18 @@ class Form extends RequestHandler { /** * Sets the button that was clicked. This should only be called by the Controller. - * @param funcName The name of the action method that will be called. + * + * @param callable $funcName The name of the action method that will be called. + * @return $this */ public function setButtonClicked($funcName) { $this->buttonClickedFunc = $funcName; return $this; } + /** + * @return mixed + */ public function buttonClicked() { foreach($this->actions->dataFields() as $action) { if($action->hasMethod('actionname') && $this->buttonClickedFunc == $action->actionName()) { @@ -1421,6 +1515,8 @@ class Form extends RequestHandler { /** * Return the default button that should be clicked when another one isn't available + * + * @return mixed|void */ public function defaultAction() { if($this->hasDefaultAction && $this->actions) @@ -1436,45 +1532,45 @@ class Form extends RequestHandler { $this->hasDefaultAction = false; return $this; } - + /** * Disable the requirement of a security token on this form instance. This security protects - * against CSRF attacks, but you should disable this if you don't want to tie + * against CSRF attacks, but you should disable this if you don't want to tie * a form to a session - eg a search form. - * + * * Check for token state with {@link getSecurityToken()} and {@link SecurityToken->isEnabled()}. */ public function disableSecurityToken() { $this->securityToken = new NullSecurityToken(); return $this; } - + /** * Enable {@link SecurityToken} protection for this form instance. - * + * * Check for token state with {@link getSecurityToken()} and {@link SecurityToken->isEnabled()}. */ public function enableSecurityToken() { $this->securityToken = new SecurityToken(); return $this; } - + /** * Returns the security token for this form (if any exists). * Doesn't check for {@link securityTokenEnabled()}. * Use {@link SecurityToken::inst()} to get a global token. - * + * * @return SecurityToken|null */ public function getSecurityToken() { return $this->securityToken; } - + /** * Returns the name of a field, if that's the only field that the current controller is interested in. * It checks for a call to the callfieldmethod action. * This is useful for optimising your forms - * + * * @return string */ public static function single_field_required() { @@ -1491,26 +1587,29 @@ class Form extends RequestHandler { /** * Set the current form action. Should only be called by Controller. + * + * @param $action */ public static function set_current_action($action) { self::$current_action = $action; } - + /** - * Compiles all CSS-classes. - * + * Compiles all CSS-classes. + * * @return string */ public function extraClass() { return implode(array_unique($this->extraClasses), ' '); } - + /** * Add a CSS-class to the form-container. If needed, multiple classes can - * be added by delimiting a string with spaces. + * be added by delimiting a string with spaces. * * @param string $class A string containing a classname or several class - * names delimited by a single space. + * names delimited by a single space. + * @return $this */ public function addExtraClass($class) { //split at white space @@ -1527,6 +1626,7 @@ class Form extends RequestHandler { * be passed through as a space delimited string * * @param string $class + * @return $this */ public function removeExtraClass($class) { //split at white space @@ -1537,7 +1637,7 @@ class Form extends RequestHandler { } return $this; } - + public function debug() { $result = "

$this->class

    "; foreach($this->fields as $field) { @@ -1550,28 +1650,34 @@ class Form extends RequestHandler { return $result; } - - + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TESTING HELPERS ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - + /** * Test a submission of this form. + * @param string $action + * @param array $data * @return SS_HTTPResponse the response object that the handling controller produces. You can interrogate this in * your unit test. + * @throws SS_HTTPResponse_Exception */ public function testSubmission($action, $data) { $data['action_' . $action] = true; return Director::test($this->FormAction(), $data, Controller::curr()->getSession()); - + //$response = $this->controller->run($data); //return $response; } - + /** * Test an ajax submission of this form. + * + * @param string $action + * @param array $data * @return SS_HTTPResponse the response object that the handling controller produces. You can interrogate this in * your unit test. */ @@ -1587,14 +1693,16 @@ class Form extends RequestHandler { */ class Form_FieldMap extends ViewableData { protected $form; - + public function __construct($form) { $this->form = $form; parent::__construct(); } - + /** * Ensure that all potential method calls get passed to __call(), therefore to dataFieldByName + * @param string $method + * @return bool */ public function hasMethod($method) { return true;