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. * * @package forms * @subpackage core */ class FormField extends RequestHandler { protected $form; protected $name, $title, $value ,$message, $messageType, $extraClass; /** * @var $description string Adds a "title"-attribute to the markup. * @todo Implement in all subclasses */ protected $description; /** * @var $extraClasses array Extra CSS-classes for the formfield-container */ protected $extraClasses; public $dontEscape; /** * @var $rightTitle string Used in SmallFieldHolder() to force a right-aligned label. */ 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(). */ protected $leftTitle; /** * Set the "tabindex" HTML attribute on the field. * * @var int */ protected $tabIndex; /** * Stores a reference to the FieldSet that contains this object. * @var FieldSet */ protected $containerFieldSet; /** * @var $readonly boolean */ protected $readonly = false; /** * @var $disabled boolean */ protected $disabled = false; /** * @var Custom Validation Message for the Field */ protected $customValidationMessage = ""; /** * Create a new field. * @param name The internal field name, passed to forms. * @param title The field label. * @param value The value of the field. * @param form Reference to the container form * @param maxLength The Maximum length of the attribute */ function __construct($name, $title = null, $value = null, $form = null, $rightTitle = null) { $this->name = $name; $this->title = ($title === null) ? $name : $title; if($value !== NULL) $this->setValue($value); if($form) $this->setForm($form); parent::__construct(); } /** * Return a Link to this field */ 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. */ function id() { $name = ereg_replace('(^-)|(-$)','',ereg_replace('[^A-Za-z0-9_-]+','-',$this->name)); if($this->form) return $this->form->FormName() . '_' . $name; else return $name; } /** * Returns the field name - used by templates. * * @return string */ function Name() { return $this->name; } function attrName() { return $this->name; } /** * Returns the field message, used by form validation. * Use {@link setError()} to set this property. * * @return string */ 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". * Use {@link setError()} to set this property. * * @return string */ function MessageType() { return $this->messageType; } /** * Returns the field value - used by templates. */ function Value() { return $this->value; } /** * Method to save this form field into the given data object. * By default, makes use of $this->dataValue() */ function saveInto(DataObjectInterface $record) { if($this->name) { $record->setCastedField($this->name, $this->dataValue()); } } /** * Returns the field value suitable for insertion into the data object */ function dataValue() { return $this->value; } /** * Returns the field label - used by templates. */ function Title() { return $this->title; } function setTitle($val) { $this->title = $val; } function RightTitle() { return $this->rightTitle; } function setRightTitle($val) { $this->rightTitle = $val; } function LeftTitle() { return $this->leftTitle; } function setLeftTitle($val) { $this->leftTitle = $val; } /** * Set tabindex HTML attribute * (defaults to none). * * @param int $index */ public function setTabIndex($index) { $this->tabIndex = $index; } /** * Get tabindex (if previously set) * * @return int */ public function getTabIndex() { return $this->tabIndex; } /** * Get tabindex HTML string * * @param int $increment Increase current tabindex by this value * @return string */ protected function getTabIndexHTML($increment = 0) { $tabIndex = (int)$this->getTabIndex() + (int)$increment; return (is_numeric($tabIndex)) ? ' tabindex = "' . $tabIndex . '"' : ''; } /** * 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 */ function extraClass() { $output = ""; if(is_array($this->extraClasses)) { $output = " " . implode($this->extraClasses, " "); } // Allow customization of label and field tag positioning if(!$this->Title()) $output .= " 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()) $output .= " holder-" . $this->MessageType(); return $output; } /** * Add a CSS-class to the formfield-container. * * @param $class String */ function addExtraClass($class) { $this->extraClasses[$class] = $class; } /** * Remove a CSS-class from the formfield-container. * * @param $class String */ function removeExtraClass($class) { if(isset($this->extraClasses) && array_key_exists($class, $this->extraClasses)) unset($this->extraClasses[$class]); } /** * Returns a version of a title suitable for insertion into an HTML attribute */ function attrTitle() { return Convert::raw2att($this->title); } /** * Returns a version of a title suitable for insertion into an HTML attribute */ function attrValue() { return Convert::raw2att($this->value); } /** * Set the field value. * Returns $this. */ function setValue($value) { $this->value = $value; return $this; } /** * Set the field name */ function setName($name) { $this->name = $name; } /** * 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. */ function setForm($form) { $this->form = $form; } /** * Get the currently used form. * * @return Form */ function getForm() { return $this->form; } /** * Return TRUE if security token protection is enabled on the parent {@link Form}. * * @return bool */ public function securityTokenEnabled() { return $this->getForm() && $this->getForm()->securityTokenEnabled(); } /** * Sets the error message to be displayed on the form field * Set by php validation of the form */ function setError($message,$messageType){ $this->message = $message; $this->messageType = $messageType; } /** * 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; } /** * 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() { return $this->customValidationMessage; } /** * Returns the form field - used by templates. * 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" * representation of the field on the form, whereas Field will give you the core editing widget, * such as an input tag. * * Our base FormField class just returns a span containing the value. This should be overridden! */ function Field() { if($this->value) $value = $this->dontEscape ? ($this->reserveNL ? Convert::raw2xml($this->value) : $this->value) : Convert::raw2xml($this->value); else $value = '(' . _t('FormField.NONE', 'none') . ')'; $attributes = array( 'id' => $this->id(), 'class' => 'readonly' . ($this->extraClass() ? $this->extraClass() : '') ); $hiddenAttributes = array( 'type' => 'hidden', 'name' => $this->name, 'value' => $this->value, 'tabindex' => $this->getTabIndex() ); $containerSpan = $this->createTag('span', $attributes, $value); $hiddenInput = $this->createTag('input', $hiddenAttributes); return $containerSpan . "\n" . $hiddenInput; } /** * Returns a "Field Holder" for this field - used by templates. * Forms are constructed from by concatenating a number of these field holders. The default * field holder is a label and form field inside a paragraph tag. * * Composite fields can override FieldHolder to create whatever visual effects you like. It's * a good idea to put the actual HTML for field holders into templates. The default field holder * is the DefaultFieldHolder template. This lets you override the HTML for specific sites, if it's * necessary. * * @todo Add "validationError" if needed. */ function FieldHolder() { $Title = $this->XML_val('Title'); $Message = $this->XML_val('Message'); $MessageType = $this->XML_val('MessageType'); $RightTitle = $this->XML_val('RightTitle'); $Type = $this->XML_val('Type'); $extraClass = $this->XML_val('extraClass'); $Name = $this->XML_val('Name'); $Field = $this->XML_val('Field'); // Only of the the following titles should apply $titleBlock = (!empty($Title)) ? "" : ""; $rightTitleBlock = (!empty($RightTitle)) ? "" : ""; // $MessageType is also used in {@link extraClass()} with a "holder-" prefix $messageBlock = (!empty($Message)) ? "
" : ""; return <<$titleBlock