diff --git a/forms/FormField.php b/forms/FormField.php
index 693c50253..0d0ebe525 100644
--- a/forms/FormField.php
+++ b/forms/FormField.php
@@ -1,19 +1,25 @@
Subclassing
- *
- * Define a {@link dataValue()} method that returns a value suitable for inserting into a single database field.
- * For example, you might tidy up the format of a date or currency field.
- * Define {@link saveInto()} to totally customise saving.
- * For example, data might be saved to the filesystem instead of the data record,
- * or saved to a component of the data record instead of the data record itself.
- *
+ *
+ * In addition to single fields, FormField objects can be "composite", for example, the
+ * {@link TabSet} field. Composite fields let us define complex forms without having to resort to
+ * custom HTML.
+ *
+ * To subclass:
+ *
+ * Define a {@link dataValue()} method that returns a value suitable for inserting into a single
+ * database field.
+ *
+ * For example, you might tidy up the format of a date or currency field. Define {@link saveInto()}
+ * to totally customise saving.
+ *
+ * For example, data might be saved to the filesystem instead of the data record, or saved to a
+ * component of the data record instead of the data record itself.
+ *
* @package forms
* @subpackage core
*/
@@ -24,153 +30,244 @@ class FormField extends RequestHandler {
*/
protected $form;
- protected $name, $title, $value ,$message, $messageType, $extraClass;
-
/**
- * @var $description string Adds a "title"-attribute to the markup.
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * @var null|string
+ */
+ protected $title;
+
+ /**
+ * @var mixed
+ */
+ protected $value;
+
+ /**
+ * @var string
+ */
+ protected $message;
+
+ /**
+ * @var string
+ */
+ protected $messageType;
+
+ /**
+ * @var string
+ */
+ protected $extraClass;
+
+ /**
+ * Adds a title attribute to the markup.
+ *
+ * @var string
+ *
* @todo Implement in all subclasses
*/
protected $description;
-
+
/**
- * @var $extraClasses array Extra CSS-classes for the formfield-container
+ * Extra CSS classes for the FormField container.
+ *
+ * @var array
*/
protected $extraClasses;
-
- public $dontEscape;
-
+
/**
- * @var $rightTitle string Used in SmallFieldHolder to force a right-aligned label, or in FieldHolder
- * to create contextual label.
+ * @var bool
+ */
+ public $dontEscape;
+
+ /**
+ * Right-aligned, contextual label for the field.
+ *
+ * @var string
*/
protected $rightTitle;
-
+
/**
- * @var $leftTitle string Used in SmallFieldHolder() to force a left-aligned label with correct spacing.
- * Please use $title for FormFields rendered with FieldHolder().
+ * Left-aligned, contextual label for the field.
+ *
+ * @var string
*/
protected $leftTitle;
-
+
/**
* Stores a reference to the FieldList that contains this object.
+ *
* @var FieldList
*/
protected $containerFieldList;
-
+
/**
- * @var boolean
+ * @var bool
*/
protected $readonly = false;
/**
- * @var boolean
+ * @var bool
*/
protected $disabled = false;
-
+
/**
- * @var string custom validation message for the Field
- */
- protected $customValidationMessage = "";
-
- /**
- * Name of the template used to render this form field. If not set, then
- * will look up the class ancestry for the first matching template where
- * the template name equals the class name.
- *
- * To explicitly use a custom template or one named other than the form
- * field see {@link setTemplate()}, {@link setFieldHolderTemplate()}
+ * Custom validation message for the field.
*
* @var string
*/
- protected
- $template,
- $fieldHolderTemplate,
- $smallFieldHolderTemplate;
-
+ protected $customValidationMessage = '';
+
/**
- * @var array All attributes on the form field (not the field holder).
- * Partially determined based on other instance properties, please use {@link getAttributes()}.
+ * Name of the template used to render this form field. If not set, then will look up the class
+ * ancestry for the first matching template where the template name equals the class name.
+ *
+ * To explicitly use a custom template or one named other than the form field see
+ * {@link setTemplate()}.
+ *
+ * @var string
+ */
+ protected $template;
+
+ /**
+ * Name of the template used to render this form field. If not set, then will look up the class
+ * ancestry for the first matching template where the template name equals the class name.
+ *
+ * To explicitly use a custom template or one named other than the form field see
+ * {@link setFieldHolderTemplate()}.
+ *
+ * @var string
+ */
+ protected $fieldHolderTemplate;
+
+ /**
+ * @var string
+ */
+ protected $smallFieldHolderTemplate;
+
+ /**
+ * All attributes on the form field (not the field holder).
+ *
+ * Partially determined based on other instance properties.
+ *
+ * @see getAttributes()
+ *
+ * @var array
*/
protected $attributes = array();
/**
- * Takes a fieldname and converts camelcase to spaced
- * words. Also resolves combined fieldnames with dot syntax
- * to spaced words.
+ * Takes a field name and converts camelcase to spaced words. Also resolves combined field
+ * names with dot syntax to spaced words.
*
* Examples:
+ *
* - 'TotalAmount' will return 'Total Amount'
* - 'Organisation.ZipCode' will return 'Organisation Zip Code'
*
* @param string $fieldName
+ *
* @return string
*/
public static function name_to_label($fieldName) {
if(strpos($fieldName, '.') !== false) {
$parts = explode('.', $fieldName);
- $label = $parts[count($parts)-2] . ' ' . $parts[count($parts)-1];
+
+ $label = $parts[count($parts) - 2] . ' ' . $parts[count($parts) - 1];
} else {
$label = $fieldName;
}
- $label = preg_replace("/([a-z]+)([A-Z])/","$1 $2", $label);
-
- return $label;
+
+ return preg_replace('/([a-z]+)([A-Z])/', '$1 $2', $label);
}
/**
* Construct and return HTML tag.
+ *
+ * @param string $tag
+ * @param array $attributes
+ * @param null|string $content
+ *
+ * @return string
*/
public static function create_tag($tag, $attributes, $content = null) {
$preparedAttributes = '';
- foreach($attributes as $k => $v) {
- // Note: as indicated by the $k == value item here; the decisions over what to include in the attributes
- // can sometimes get finicky
- if(!empty($v) || $v === '0' || ($k == 'value' && $v !== null) ) {
- $preparedAttributes .= " $k=\"" . Convert::raw2att($v) . "\"";
+
+ foreach($attributes as $attributeKey => $attributeValue) {
+ if(!empty($attributeValue) || $attributeValue === '0' || ($attributeKey == 'value' && $attributeValue !== null)) {
+ $preparedAttributes .= sprintf(
+ ' %s="%s"', $attributeKey, Convert::raw2att($attributeValue)
+ );
}
}
- if($content || $tag != 'input') return "<$tag$preparedAttributes>$content$tag>";
- else return "<$tag$preparedAttributes />";
+ if($content || $tag != 'input') {
+ return sprintf(
+ '<%s%s>%s%s>', $tag, $preparedAttributes, $content, $tag
+ );
+ }
+
+ return sprintf(
+ '<%s%s />', $tag, $preparedAttributes
+ );
}
/**
* Creates a new field.
*
* @param string $name The internal field name, passed to forms.
- * @param string $title The human-readable field label.
+ * @param null|string $title The human-readable field label.
* @param mixed $value The value of the field.
*/
public function __construct($name, $title = null, $value = null) {
$this->name = $name;
- $this->title = ($title === null) ? self::name_to_label($name) : $title;
- if($value !== NULL) $this->setValue($value);
+ if($title === null) {
+ $this->title = self::name_to_label($name);
+ } else {
+ $this->title = $title;
+ }
+
+ if($value !== null) {
+ $this->setValue($value);
+ }
parent::__construct();
}
-
+
/**
- * Return a Link to this field
+ * Return a Link to this field.
+ *
+ * @param null|string $action
+ *
+ * @return string
*/
public function Link($action = null) {
return Controller::join_links($this->form->FormAction(), 'field/' . $this->name, $action);
}
-
+
/**
- * Returns the HTML ID of the field - used in the template by label tags.
- * The ID is generated as FormName_FieldName. All Field functions should ensure
- * that this ID is included in the field.
+ * Returns the HTML ID of the field.
+ *
+ * The ID is generated as FormName_FieldName. All Field functions should ensure that this ID is
+ * included in the field.
*/
public function ID() {
- $name = preg_replace('/(^-)|(-$)/', '', preg_replace('/[^A-Za-z0-9_-]+/', '-', $this->name));
- if($this->form) return $this->form->FormName() . '_' . $name;
- else return $name;
+ $name = $this->name;
+ $name = preg_replace('/[^A-Za-z0-9_-]+/', '-', $name);
+ $name = preg_replace('/(^-)|(-$)/', '', $name);
+
+ if($this->form) {
+ return $this->form->FormName() . '_' . $name;
+ }
+
+ return $name;
}
-
+
/**
- * Returns the field name - used by templates.
- *
+ * Returns the field name.
+ *
* @return string
*/
public function getName() {
@@ -179,130 +276,160 @@ class FormField extends RequestHandler {
/**
* Returns the field message, used by form validation.
+ *
* Use {@link setError()} to set this property.
- *
+ *
* @return string
*/
public function Message() {
return $this->message;
- }
-
- /**
- * Returns the field message type, used by form validation.
- * Arbitrary value which is mostly used for CSS classes
- * in the rendered HTML, e.g. "required".
+ }
+
+ /**
+ * Returns the field message type.
+ *
+ * Arbitrary value which is mostly used for CSS classes in the rendered HTML, e.g "required".
+ *
* Use {@link setError()} to set this property.
- *
+ *
* @return string
*/
public function MessageType() {
return $this->messageType;
- }
-
+ }
+
/**
- * Returns the field value - used by templates.
+ * Returns the field value.
+ *
+ * @return mixed
*/
public function Value() {
return $this->value;
}
-
+
/**
* Method to save this form field into the given data object.
- * By default, makes use of $this->dataValue()
- *
- * @param DataObjectInterface $record DataObject to save data into
+ *
+ * @param DataObjectInterface $record
*/
public function saveInto(DataObjectInterface $record) {
if($this->name) {
$record->setCastedField($this->name, $this->dataValue());
}
}
-
+
/**
- * Returns the field value suitable for insertion into the data object
+ * Returns the field value suitable for insertion into the data object.
+ *
+ * @return mixed
*/
public function dataValue() {
return $this->value;
}
-
+
/**
- * Returns the field label - used by templates.
+ * Returns the field label.
*/
public function Title() {
return $this->title;
}
-
- public function setTitle($val) {
- $this->title = $val;
+
+ /**
+ * @param string $title
+ *
+ * @return $this
+ */
+ public function setTitle($title) {
+ $this->title = $title;
+
return $this;
}
/**
- * Gets the contextual label than can be used for additional field description.
- * Can be shown to the right or under the field in question.
- *
- * @return string Contextual label text.
+ * @return string
*/
public function RightTitle() {
return $this->rightTitle;
}
/**
- * Sets the contextual label.
+ * @param string $rightTitle
*
- * @param $val string Text to set on the label.
+ * @return $this
*/
- public function setRightTitle($val) {
- $this->rightTitle = $val;
- return $this;
- }
+ public function setRightTitle($rightTitle) {
+ $this->rightTitle = $rightTitle;
- public function LeftTitle() {
- return $this->leftTitle;
- }
-
- public function setLeftTitle($val) {
- $this->leftTitle = $val;
return $this;
}
/**
- * Compiles all CSS-classes. Optionally includes a "nolabel"-class
- * if no title was set on the formfield.
- * Uses {@link Message()} and {@link MessageType()} to add validatoin
- * error classes which can be used to style the contained tags.
- *
- * @return string CSS-classnames
+ * @return string
+ */
+ public function LeftTitle() {
+ return $this->leftTitle;
+ }
+
+ /**
+ * @param string $leftTitle
+ *
+ * @return $this
+ */
+ public function setLeftTitle($leftTitle) {
+ $this->leftTitle = $leftTitle;
+
+ return $this;
+ }
+
+ /**
+ * Compiles all CSS-classes. Optionally includes a "nolabel" class if no title was set on the
+ * FormField.
+ *
+ * Uses {@link Message()} and {@link MessageType()} to add validation error classes which can
+ * be used to style the contained tags.
+ *
+ * @return string
*/
public function extraClass() {
$classes = array();
$classes[] = $this->Type();
- if($this->extraClasses) $classes = array_merge($classes, array_values($this->extraClasses));
-
- // Allow customization of label and field tag positioning
- if(!$this->Title()) $classes[] = "nolabel";
-
- // Allow custom styling of any element in the container based
- // on validation errors, e.g. red borders on input tags.
- // CSS-Class needs to be different from the one rendered
- // through {@link FieldHolder()}
- if($this->Message()) $classes[] .= "holder-" . $this->MessageType();
-
+ if($this->extraClasses) {
+ $classes = array_merge(
+ $classes,
+ array_values($this->extraClasses)
+ );
+ }
+
+ if(!$this->Title()) {
+ $classes[] = 'nolabel';
+ }
+
+ // Allow custom styling of any element in the container based on validation errors,
+ // e.g. red borders on input tags.
+ //
+ // CSS class needs to be different from the one rendered through {@link FieldHolder()}.
+ if($this->Message()) {
+ $classes[] .= 'holder-' . $this->MessageType();
+ }
+
return implode(' ', $classes);
}
-
+
/**
- * Add one or more CSS-classes to the formfield-container. Multiple class
- * names should be space delimited.
- *
+ * Add one or more CSS-classes to the FormField container.
+ *
+ * Multiple class names should be space delimited.
+ *
* @param string $class
+ *
+ * @return $this
*/
public function addExtraClass($class) {
$classes = preg_split('/\s+/', $class);
- foreach ($classes as $class) {
+ foreach($classes as $class) {
$this->extraClasses[$class] = $class;
}
@@ -310,199 +437,252 @@ class FormField extends RequestHandler {
}
/**
- * Remove one or more CSS-classes from the formfield-container.
- *
+ * Remove one or more CSS-classes from the FormField container.
+ *
* @param string $class
+ *
+ * @return $this
*/
public function removeExtraClass($class) {
$classes = preg_split('/\s+/', $class);
- foreach ($classes as $class) {
+ foreach($classes as $class) {
unset($this->extraClasses[$class]);
}
-
+
return $this;
}
/**
* Set an HTML attribute on the field element, mostly an tag.
- *
- * Some attributes are best set through more specialized methods, to avoid interfering with built-in behaviour:
+ *
+ * Some attributes are best set through more specialized methods, to avoid interfering with
+ * built-in behaviour:
+ *
* - 'class': {@link addExtraClass()}
* - 'title': {@link setDescription()}
* - 'value': {@link setValue}
* - 'name': {@link setName}
- *
- * CAUTION Doesn't work on most fields which are composed of more than one HTML form field:
- * AjaxUniqueTextField, CheckboxSetField, ComplexTableField, CompositeField, ConfirmedPasswordField,
- * CountryDropdownField, CreditCardField, CurrencyField, DateField, DatetimeField, FieldGroup, GridField,
- * HtmlEditorField, ImageField, ImageFormAction, InlineFormAction, ListBoxField, etc.
- *
- * @param string
- * @param string
+ *
+ * Caution: this doesn't work on most fields which are composed of more than one HTML form
+ * field.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @return $this
*/
public function setAttribute($name, $value) {
$this->attributes[$name] = $value;
+
return $this;
}
/**
* Get an HTML attribute defined by the field, or added through {@link setAttribute()}.
- * Caution: Doesn't work on all fields, see {@link setAttribute()}.
- *
- * @return string
+ *
+ * Caution: this doesn't work on all fields, see {@link setAttribute()}.
+ *
+ * @return null|string
*/
public function getAttribute($name) {
- $attrs = $this->getAttributes();
- if(isset($attrs[$name])) return $attrs[$name];
+ $attributes = $this->getAttributes();
+
+ if(isset($attributes[$name])) {
+ return $attributes[$name];
+ }
+
+ return null;
}
-
+
/**
* @return array
*/
public function getAttributes() {
- $attrs = array(
+ $attributes = array(
'type' => 'text',
'name' => $this->getName(),
- 'value' => $this->Value(),
+ 'value' => $this->Value(),
'class' => $this->extraClass(),
'id' => $this->ID(),
'disabled' => $this->isDisabled(),
'readonly' => $this->isReadonly()
);
-
- if ($this->Required()) {
- $attrs['required'] = 'required';
- $attrs['aria-required'] = 'true';
+
+ if($this->Required()) {
+ $attributes['required'] = 'required';
+ $attributes['aria-required'] = 'true';
}
- return array_merge($attrs, $this->attributes);
+ return array_merge($attributes, $this->attributes);
}
/**
- * @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
+ * 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.
+ *
+ * @param array $attributes
+ *
+ * @return string
*/
- public function getAttributesHTML($attrs = null) {
- $exclude = (is_string($attrs)) ? func_get_args() : null;
+ public function getAttributesHTML($attributes = null) {
+ $exclude = null;
- if(!$attrs || is_string($attrs)) $attrs = $this->getAttributes();
+ if(is_string($attributes)) {
+ $exclude = func_get_args();
+ }
- // Remove empty
- $attrs = array_filter((array)$attrs, function($v) {
+ if(!$attributes || is_string($attributes)) {
+ $attributes = $this->getAttributes();
+ }
+
+ $attributes = (array) $attributes;
+
+ $attributes = array_filter($attributes, function ($v) {
return ($v || $v === 0 || $v === '0');
- });
+ });
- // Remove excluded
- if($exclude) $attrs = array_diff_key($attrs, array_flip($exclude));
+ if($exclude) {
+ $attributes = array_diff_key(
+ $attributes,
+ array_flip($exclude)
+ );
+ }
- // Create markkup
$parts = array();
- foreach($attrs as $name => $value) {
- $parts[] = ($value === true) ? "{$name}=\"{$name}\"" : "{$name}=\"" . Convert::raw2att($value) . "\"";
+
+ foreach($attributes as $name => $value) {
+ if($value === true) {
+ $parts[] = sprintf('%s="%s"', $name, $name);
+ } else {
+ $parts[] = sprintf('%s="%s"', $name, Convert::raw2att($value));
+ }
}
return implode(' ', $parts);
}
/**
- * Returns a version of a title suitable for insertion into an HTML attribute
+ * Returns a version of a title suitable for insertion into an HTML attribute.
+ *
+ * @return string
*/
public function attrTitle() {
return Convert::raw2att($this->title);
}
+
/**
- * Returns a version of a title suitable for insertion into an HTML attribute
+ * Returns a version of a title suitable for insertion into an HTML attribute.
+ *
+ * @return string
*/
public function attrValue() {
return Convert::raw2att($this->value);
}
-
+
/**
* Set the field value.
- *
+ *
* @param mixed $value
- * @param mixed $data Optional data source passed in by {@see Form::loadDataFrom}
- * @return FormField Self reference
+ * @param null|array|DataObject $data {@see Form::loadDataFrom}
+ *
+ * @return $this
*/
public function setValue($value) {
$this->value = $value;
+
return $this;
}
-
+
/**
- * Set the field name
+ * Set the field name.
+ *
+ * @param string $name
+ *
+ * @return $this
*/
public function setName($name) {
$this->name = $name;
+
return $this;
}
-
+
/**
* Set the container form.
- * This is called whenever you create a new form and put fields inside it, so that you don't
- * have to worry about linking the two.
+ *
+ * This is called automatically when fields are added to forms.
+ *
+ * @param Form $form
+ *
+ * @return $this
*/
public function setForm($form) {
$this->form = $form;
+
return $this;
}
-
+
/**
* Get the currently used form.
*
* @return Form
*/
public function getForm() {
- return $this->form;
+ return $this->form;
}
-
+
/**
- * Return TRUE if security token protection is enabled on the parent {@link Form}.
+ * Return true if security token protection is enabled on the parent {@link Form}.
*
* @return bool
*/
public function securityTokenEnabled() {
$form = $this->getForm();
- if(!$form) return false;
-
+
+ if(!$form) {
+ return false;
+ }
+
return $form->getSecurityToken()->isEnabled();
}
-
+
/**
- * Sets the error message to be displayed on the form field
- * Set by php validation of the form.
+ * Sets the error message to be displayed on the form field.
*
- * @param string $message Message to show to the user. Allows HTML content,
- * which means you need to use Convert::raw2xml() for any user supplied data.
+ * Allows HTML content, so remember to use Convert::raw2xml().
+ *
+ * @param string $message
+ * @param string $messageType
+ *
+ * @return $this
*/
public function setError($message, $messageType) {
- $this->message = $message;
- $this->messageType = $messageType;
-
+ $this->message = $message;
+ $this->messageType = $messageType;
+
return $this;
}
-
+
/**
- * Set the custom error message to show instead of the default
- * format of Please Fill In XXX. Different from setError() as
- * that appends it to the standard error messaging
- *
- * @param string Message for the error
- */
- public function setCustomValidationMessage($msg) {
- $this->customValidationMessage = $msg;
-
- return $this;
- }
-
- /**
- * Get the custom error message for this form field. If a custom
- * message has not been defined then just return blank. The default
- * error is defined on {@link Validator}.
+ * Set the custom error message to show instead of the default format.
+ *
+ * Different from setError() as that appends it to the standard error messaging.
+ *
+ * @param string $customValidationMessage
+ *
+ * @return $this
+ */
+ public function setCustomValidationMessage($customValidationMessage) {
+ $this->customValidationMessage = $customValidationMessage;
+
+ return $this;
+ }
+
+ /**
+ * Get the custom error message for this form field. If a custom message has not been defined
+ * then just return blank. The default error is defined on {@link Validator}.
*
- * @todo Should the default error message be stored here instead
* @return string
*/
public function getCustomValidationMessage() {
@@ -511,98 +691,120 @@ class FormField extends RequestHandler {
/**
* Set name of template (without path or extension).
- * Caution: Not consistently implemented in all subclasses,
- * please check the {@link Field()} method on the subclass for support.
- *
- * @param string
+ *
+ * Caution: Not consistently implemented in all subclasses, please check the {@link Field()}
+ * method on the subclass for support.
+ *
+ * @param string $template
+ *
+ * @return $this
*/
public function setTemplate($template) {
$this->template = $template;
-
+
return $this;
}
-
+
/**
* @return string
*/
public function getTemplate() {
return $this->template;
}
-
+
/**
* @return string
*/
public function getFieldHolderTemplate() {
return $this->fieldHolderTemplate;
}
-
+
/**
- * Set name of template (without path or extension) for the holder,
- * which in turn is responsible for rendering {@link Field()}.
- *
- * Caution: Not consistently implemented in all subclasses,
- * please check the {@link Field()} method on the subclass for support.
- *
- * @param string
+ * Set name of template (without path or extension) for the holder, which in turn is
+ * responsible for rendering {@link Field()}.
+ *
+ * Caution: Not consistently implemented in all subclasses, please check the {@link Field()}
+ * method on the subclass for support.
+ *
+ * @param string $fieldHolderTemplate
+ *
+ * @return $this
*/
- public function setFieldHolderTemplate($template) {
- $this->fieldHolderTemplate = $template;
-
+ public function setFieldHolderTemplate($fieldHolderTemplate) {
+ $this->fieldHolderTemplate = $fieldHolderTemplate;
+
return $this;
}
-
+
/**
* @return string
*/
public function getSmallFieldHolderTemplate() {
return $this->smallFieldHolderTemplate;
}
-
+
/**
- * Set name of template (without path or extension) for the small holder,
- * which in turn is responsible for rendering {@link Field()}.
- *
- * Caution: Not consistently implemented in all subclasses,
- * please check the {@link Field()} method on the subclass for support.
- *
- * @param string
+ * Set name of template (without path or extension) for the small holder, which in turn is
+ * responsible for rendering {@link Field()}.
+ *
+ * Caution: Not consistently implemented in all subclasses, please check the {@link Field()}
+ * method on the subclass for support.
+ *
+ * @param string $smallFieldHolderTemplate
+ *
+ * @return $this
*/
- public function setSmallFieldHolderTemplate($template) {
- $this->smallFieldHolderTemplate = $template;
-
+ public function setSmallFieldHolderTemplate($smallFieldHolderTemplate) {
+ $this->smallFieldHolderTemplate = $smallFieldHolderTemplate;
+
return $this;
}
-
+
/**
- * Returns the form field - used by templates.
+ * Returns the form field.
+ *
* Although FieldHolder is generally what is inserted into templates, all of the field holder
- * templates make use of $Field. It's expected that FieldHolder will give you the "complete"
+ * templates make use of $Field. It's expected that FieldHolder will give you the "complete"
* representation of the field on the form, whereas Field will give you the core editing widget,
* such as an input tag.
- *
- * @param array $properties key value pairs of template variables
+ *
+ * @param array $properties
+ *
* @return string
*/
public function Field($properties = array()) {
- $obj = ($properties) ? $this->customise($properties) : $this;
+ $context = $this;
+
+ if(count($properties)) {
+ $context = $context->customise($properties);
+ }
+
$this->extend('onBeforeRender', $this);
- return $obj->renderWith($this->getTemplates());
+
+ return $context->renderWith($this->getTemplates());
}
/**
- * Returns a "field holder" for this field - used by templates.
- *
+ * Returns a "field holder" for this field.
+ *
* Forms are constructed by concatenating a number of these field holders.
+ *
* The default field holder is a label and a form field inside a div.
+ *
* @see FieldHolder.ss
- *
- * @param array $properties key value pairs of template variables
+ *
+ * @param array $properties
+ *
* @return string
*/
public function FieldHolder($properties = array()) {
- $obj = ($properties) ? $this->customise($properties) : $this;
+ $context = $this;
- return $obj->renderWith($this->getFieldHolderTemplates());
+ if(count($properties)) {
+ $context = $this->customise($properties);
+ }
+
+ return $context->renderWith($this->getFieldHolderTemplates());
}
/**
@@ -613,71 +815,81 @@ class FormField extends RequestHandler {
* @return string
*/
public function SmallFieldHolder($properties = array()) {
- $obj = ($properties) ? $this->customise($properties) : $this;
+ $context = $this;
- return $obj->renderWith($this->getSmallFieldHolderTemplates());
+ if(count($properties)) {
+ $context = $this->customise($properties);
+ }
+
+ return $context->renderWith($this->getSmallFieldHolderTemplates());
}
-
+
/**
- * Returns an array of templates to use for rendering {@link FieldH}
+ * Returns an array of templates to use for rendering {@link FieldHolder}.
*
* @return array
*/
public function getTemplates() {
return $this->_templates($this->getTemplate());
}
-
+
/**
- * Returns an array of templates to use for rendering {@link FieldHolder}
+ * Returns an array of templates to use for rendering {@link FieldHolder}.
*
* @return array
*/
public function getFieldHolderTemplates() {
return $this->_templates(
- $this->getFieldHolderTemplate(),
+ $this->getFieldHolderTemplate(),
'_holder'
);
}
/**
- * Returns an array of templates to use for rendering {@link SmallFieldHolder}
+ * Returns an array of templates to use for rendering {@link SmallFieldHolder}.
*
* @return array
- */
+ */
public function getSmallFieldHolderTemplates() {
return $this->_templates(
- $this->getSmallFieldHolderTemplate(),
+ $this->getSmallFieldHolderTemplate(),
'_holder_small'
);
}
/**
- * Generate an array of classname strings to use for rendering this form
- * field into HTML
+ * Generate an array of class name strings to use for rendering this form field into HTML.
*
- * @param string $custom custom template (if set)
- * @param string $suffix template suffix
+ * @param string $customTemplate
+ * @param string $customTemplateSuffix
*
- * @return array $stack a stack of
+ * @return array
*/
- private function _templates($custom = null, $suffix = null) {
+ private function _templates($customTemplate = null, $customTemplateSuffix = null) {
$matches = array();
-
+
foreach(array_reverse(ClassInfo::ancestry($this)) as $className) {
- $matches[] = $className . $suffix;
-
- if($className == "FormField") break;
+ $matches[] = $className . $customTemplateSuffix;
+
+ if($className == "FormField") {
+ break;
+ }
}
-
- if($custom) array_unshift($matches, $custom);
-
+
+ if($customTemplate) {
+ array_unshift($matches, $customTemplate);
+ }
+
return $matches;
}
-
+
/**
* Returns true if this field is a composite field.
+ *
* To create composite field types, you should subclass {@link CompositeField}.
+ *
+ * @return bool
*/
public function isComposite() {
return false;
@@ -685,68 +897,91 @@ class FormField extends RequestHandler {
/**
* Returns true if this field has its own data.
- * Some fields, such as titles and composite fields, don't actually have any data. It doesn't
- * make sense for data-focused methods to look at them. By overloading hasData() to return false,
- * you can prevent any data-focused methods from looking at it.
+ *
+ * Some fields, such as titles and composite fields, don't actually have any data. It doesn't
+ * make sense for data-focused methods to look at them. By overloading hasData() to return
+ * false, you can prevent any data-focused methods from looking at it.
*
* @see FieldList::collateDataFields()
+ *
+ * @return bool
*/
public function hasData() {
return true;
}
/**
- * @return boolean
+ * @return bool
*/
public function isReadonly() {
- return $this->readonly;
+ return $this->readonly;
}
/**
- * Sets readonly-flag on form-field. Please use performReadonlyTransformation()
- * to actually transform this instance.
- * @param $bool boolean Setting "false" has no effect on the field-state.
+ * Sets a read-only flag on this FormField.
+ *
+ * Use performReadonlyTransformation() to transform this instance.
+ *
+ * Setting this to false has no effect on the field.
+ *
+ * @param bool $readonly
+ *
+ * @return $this
*/
- public function setReadonly($bool) {
- $this->readonly = $bool;
+ public function setReadonly($readonly) {
+ $this->readonly = $readonly;
+
return $this;
}
-
+
/**
- * @return boolean
+ * @return bool
*/
public function isDisabled() {
return $this->disabled;
}
/**
- * Sets disabed-flag on form-field. Please use performDisabledTransformation()
- * to actually transform this instance.
- * @param $bool boolean Setting "false" has no effect on the field-state.
+ * Sets a disabled flag on this FormField.
+ *
+ * Use performDisabledTransformation() to transform this instance.
+ *
+ * Setting this to false has no effect on the field.
+ *
+ * @param bool $disabled
+ *
+ * @return $this
*/
- public function setDisabled($bool) {
- $this->disabled = $bool;
+ public function setDisabled($disabled) {
+ $this->disabled = $disabled;
+
return $this;
}
-
+
/**
- * Returns a readonly version of this field
+ * Returns a read-only version of this field.
+ *
+ * @return FormField
*/
public function performReadonlyTransformation() {
$copy = $this->castedCopy('ReadonlyField');
+
$copy->setReadonly(true);
+
return $copy;
}
-
+
/**
* Return a disabled version of this field.
- * Tries to find a class of the class name of this field suffixed with "_Disabled",
- * failing that, finds a method {@link setDisabled()}.
+ *
+ * Tries to find a class of the class name of this field suffixed with "_Disabled", failing
+ * that, finds a method {@link setDisabled()}.
*
* @return FormField
*/
public function performDisabledTransformation() {
$disabledClassName = $this->class . '_Disabled';
+
if(ClassInfo::exists($disabledClassName)) {
$clone = $this->castedCopy($disabledClassName);
} else {
@@ -754,46 +989,70 @@ class FormField extends RequestHandler {
$clone->setDisabled(true);
}
- return $clone;
- }
-
- public function transform(FormTransformation $trans) {
- return $trans->transform($this);
+ return $clone;
}
-
- public function hasClass($class){
- $patten = '/'.strtolower($class).'/i';
- $subject = strtolower($this->class." ".$this->extraClass());
+
+ /**
+ * @param FormTransformation $transformation
+ *
+ * @return mixed
+ */
+ public function transform(FormTransformation $transformation) {
+ return $transformation->transform($this);
+ }
+
+ /**
+ * @param string $class
+ *
+ * @return int
+ */
+ public function hasClass($class) {
+ $patten = '/' . strtolower($class) . '/i';
+
+ $subject = strtolower($this->class . ' ' . $this->extraClass());
+
return preg_match($patten, $subject);
}
-
+
/**
- * Returns the field type - used by templates.
+ * Returns the field type.
+ *
* The field type is the class name with the word Field dropped off the end, all lowercase.
- * It's handy for assigning HTML classes. Doesn't signify the attribute,
- * see {link getAttributes()}.
- *
+ *
+ * It's handy for assigning HTML classes. Doesn't signify the attribute.
+ *
+ * @see {link getAttributes()}.
+ *
* @return string
*/
public function Type() {
- return strtolower(preg_replace('/Field$/', '', $this->class));
+ return strtolower(preg_replace('/Field$/', '', $this->class));
}
/**
* @deprecated 3.2 Use FormField::create_tag()
+ *
+ * @param string $tag
+ * @param array $attributes
+ * @param null|string $content
+ *
+ * @return string
*/
public function createTag($tag, $attributes, $content = null) {
Deprecation::notice('3.2', 'Use FormField::create_tag()');
+
return self::create_tag($tag, $attributes, $content);
- }
+ }
/**
- * Abstract method each {@link FormField} subclass must implement,
- * determines whether the field is valid or not based on the value.
+ * Abstract method each {@link FormField} subclass must implement, determines whether the field
+ * is valid or not based on the value.
+ *
* @todo Make this abstract.
*
- * @param Validator
- * @return boolean
+ * @param Validator $validator
+ *
+ * @return bool
*/
public function validate($validator) {
return true;
@@ -801,13 +1060,16 @@ class FormField extends RequestHandler {
/**
* Describe this field, provide help text for it.
- * By default, renders as a
- * underneath the form field.
- *
- * @return string Description
+ *
+ * By default, renders as a underneath the form field.
+ *
+ * @param string $description
+ *
+ * @return $this
*/
public function setDescription($description) {
$this->description = $description;
+
return $this;
}
@@ -817,38 +1079,52 @@ class FormField extends RequestHandler {
public function getDescription() {
return $this->description;
}
-
- public function debug() {
- return "$this->class ($this->name: $this->title : $this->message)"
- . " = $this->value";
- }
-
+
/**
- * This function is used by the template processor. If you refer to a field as a $ variable, it
+ * @return string
+ */
+ public function debug() {
+ return sprintf(
+ '%s (%s: %s : %s) = %s',
+ $this->class,
+ $this->name,
+ $this->title,
+ $this->message,
+ $this->value
+ );
+ }
+
+ /**
+ * This function is used by the template processor. If you refer to a field as a $ variable, it
* will return the $Field value.
+ *
+ * @return string
*/
public function forTemplate() {
return $this->Field();
}
-
+
/**
- * @uses Validator->fieldIsRequired()
- * @return boolean
+ * @return bool
*/
public function Required() {
if($this->form && ($validator = $this->form->Validator)) {
return $validator->fieldIsRequired($this->name);
}
+
+ return false;
}
/**
* Set the FieldList that contains this field.
*
- * @param FieldList $list
+ * @param FieldList $containerFieldList
+ *
* @return FieldList
*/
- public function setContainerFieldList($list) {
- $this->containerFieldList = $list;
+ public function setContainerFieldList($containerFieldList) {
+ $this->containerFieldList = $containerFieldList;
+
return $this;
}
@@ -861,47 +1137,61 @@ class FormField extends RequestHandler {
return $this->containerFieldList;
}
- public function rootFieldList() {
- if(is_object($this->containerFieldList)) return $this->containerFieldList->rootFieldList();
- else user_error("rootFieldList() called on $this->class object without a containerFieldList", E_USER_ERROR);
- }
-
/**
- * Returns another instance of this field, but "cast" to a different class.
- * The logic tries to retain all of the instance properties,
- * and may be overloaded by subclasses to set additional ones.
+ * @return null|FieldList
+ */
+ public function rootFieldList() {
+ if(is_object($this->containerFieldList)) {
+ return $this->containerFieldList->rootFieldList();
+ }
+
+ user_error(
+ "rootFieldList() called on $this->class object without a containerFieldList",
+ E_USER_ERROR
+ );
+
+ return null;
+ }
+
+ /**
+ * Returns another instance of this field, but "cast" to a different class. The logic tries to
+ * retain all of the instance properties, and may be overloaded by subclasses to set additional
+ * ones.
*
- * Assumes the standard FormField parameter signature with
- * its name as the only mandatory argument. Mainly geared towards
- * creating *_Readonly or *_Disabled subclasses of the same type,
- * or casting to a {@link ReadonlyField}.
+ * Assumes the standard FormField parameter signature with its name as the only mandatory
+ * argument. Mainly geared towards creating *_Readonly or *_Disabled subclasses of the same
+ * type, or casting to a {@link ReadonlyField}.
+ *
+ * Does not copy custom field templates, since they probably won't apply to the new instance.
+ *
+ * @param mixed $classOrCopy Class name for copy, or existing copy instance to update
*
- * Does not copy custom field templates, since they probably won't apply to
- * the new instance.
- *
- * @param String $classOrCopy Class name for copy, or existing copy instance to update
* @return FormField
*/
public function castedCopy($classOrCopy) {
- $field = (is_object($classOrCopy)) ? $classOrCopy : new $classOrCopy($this->name);
+ $field = $classOrCopy;
+
+ if(!is_object($field)) {
+ $field = new $classOrCopy($this->name);
+ }
+
$field
- ->setValue($this->value) // get value directly from property, avoid any conversions
+ ->setValue($this->value)
->setForm($this->form)
->setTitle($this->Title())
->setLeftTitle($this->LeftTitle())
->setRightTitle($this->RightTitle())
->addExtraClass($this->extraClass())
->setDescription($this->getDescription());
-
- // Only include built-in attributes, ignore anything
- // set through getAttributes(), since those might change important characteristics
- // of the field, e.g. its "type" attribute.
- foreach($this->attributes as $k => $v) {
- $field->setAttribute($k, $v);
-}
+
+ // Only include built-in attributes, ignore anything set through getAttributes().
+ // Those might change important characteristics of the field, e.g. its "type" attribute.
+ foreach($this->attributes as $attributeKey => $attributeValue) {
+ $field->setAttribute($attributeKey, $attributeValue);
+ }
+
$field->dontEscape = $this->dontEscape;
return $field;
}
-
}