Update and fix PHP docblocks, document spelling mistakes and strip trailing whitespace on Form.php

This commit is contained in:
Stig Lindqvist 2015-06-12 10:28:32 +12:00
parent 04b803dfc6
commit 95860e9229

View File

@ -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.
*
*
* <h2>Validation</h2>
* 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
* <form action="..."> 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
* <legend> element before the <fieldset>
* 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 <input type="hidden"> 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 <legend> 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 <form> tag.
*
*
* @return string HTTP method
*/
public function FormHttpMethod() {
return $this->formMethod;
}
/**
* Returns the form method to be used in the <form> 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
* <legend> 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 = "<h3>$this->class</h3><ul>";
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;