"Varchar", "Title" => "Varchar(255)", "Default" => "Varchar", "Sort" => "Int", "Required" => "Boolean", "CustomErrorMessage" => "Varchar(255)", "CustomRules" => "Text", "CustomSettings" => "Text", "CustomParameter" => "Varchar(200)" ); private static $has_one = array( "Parent" => "UserDefinedForm", ); private static $extensions = array( "Versioned('Stage', 'Live')" ); /** * @var bool */ protected $readonly; /** * Set the visibility of an individual form field * * @param bool */ public function setReadonly($readonly = true) { $this->readonly = $readonly; } /** * Returns whether this field is readonly * * @return bool */ private function isReadonly() { return $this->readonly; } /** * Template to render the form field into * * @return String */ public function EditSegment() { return $this->renderWith('EditableFormField'); } /** * Flag indicating that this field will set its own error message via data-msg='' attributes * * @return bool */ public function getSetsOwnError() { return false; } /** * Return whether a user can delete this form field * based on whether they can edit the page * * @return bool */ public function canDelete($member = null) { return ($this->Parent()->canEdit($member = null) && !$this->isReadonly()); } /** * Return whether a user can edit this form field * based on whether they can edit the page * * @return bool */ public function canEdit($member = null) { return ($this->Parent()->canEdit($member = null) && !$this->isReadonly()); } /** * Publish this Form Field to the live site * * Wrapper for the {@link Versioned} publish function */ public function doPublish($fromStage, $toStage, $createNewVersion = false) { $this->publish($fromStage, $toStage, $createNewVersion); } /** * Delete this form from a given stage * * Wrapper for the {@link Versioned} deleteFromStage function */ public function doDeleteFromStage($stage) { $this->deleteFromStage($stage); } /** * checks wether record is new, copied from Sitetree */ function isNew() { if(empty($this->ID)) return true; if(is_numeric($this->ID)) return false; return stripos($this->ID, 'new') === 0; } /** * checks if records is changed on stage * @return boolean */ public function getIsModifiedOnStage() { // new unsaved fields could be never be published if($this->isNew()) return false; $stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID); $liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID); return ($stageVersion && $stageVersion != $liveVersion); } /** * Show this form on load or not * * @return bool */ public function getShowOnLoad() { return ($this->getSetting('ShowOnLoad') == "Show" || $this->getSetting('ShowOnLoad') == '') ? true : false; } /** * To prevent having tables for each fields minor settings we store it as * a serialized array in the database. * * @return Array Return all the Settings */ public function getSettings() { return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array(); } /** * Set the custom settings for this field as we store the minor details in * a serialized array in the database * * @param Array the custom settings */ public function setSettings($settings = array()) { $this->CustomSettings = serialize($settings); } /** * Set a given field setting. Appends the option to the settings or overrides * the existing value * * @param String key * @param String value */ public function setSetting($key, $value) { $settings = $this->getSettings(); $settings[$key] = $value; $this->setSettings($settings); } /** * Set the allowed css classes for the extraClass custom setting * * @param array The permissible CSS classes to add */ public function setAllowedCss(array $allowed) { if (is_array($allowed_css)){ foreach ($allowed_css as $k => $v){ self::$allowed_css[$k] = (!is_null($v)) ? $v : $k; } } } /** * Return just one custom setting or empty string if it does * not exist * * @param String Value to use as key * @return String */ public function getSetting($setting) { $settings = $this->getSettings(); if(isset($settings) && count($settings) > 0) { if(isset($settings[$setting])) { return $settings[$setting]; } } return ''; } /** * Get the path to the icon for this field type, relative to the site root. * * @return string */ public function getIcon() { return USERFORMS_DIR . '/images/' . strtolower($this->class) . '.png'; } /** * Return whether or not this field has addable options * such as a dropdown field or radio set * * @return bool */ public function getHasAddableOptions() { return false; } /** * Return whether or not this field needs to show the extra * options dropdown list * * @return bool */ public function showExtraOptions() { return true; } /** * Return the custom validation fields for this field for the CMS * * @return array */ public function Dependencies() { return ($this->CustomRules) ? unserialize($this->CustomRules) : array(); } /** * Return the custom validation fields for the field * * @return DataObjectSet */ public function CustomRules() { $output = new ArrayList(); $fields = $this->Parent()->Fields(); // check for existing ones if($rules = $this->Dependencies()) { foreach($rules as $rule => $data) { // recreate all the field object to prevent caching $outputFields = new ArrayList(); foreach($fields as $field) { $new = clone $field; $new->isSelected = ($new->Name == $data['ConditionField']) ? true : false; $outputFields->push($new); } $output->push(new ArrayData(array( 'FieldName' => $this->getFieldName(), 'Display' => $data['Display'], 'Fields' => $outputFields, 'ConditionField' => $data['ConditionField'], 'ConditionOption' => $data['ConditionOption'], 'Value' => $data['Value'] ))); } } return $output; } /** * Title field of the field in the backend of the page * * @return TextField */ public function TitleField() { $label = _t('EditableFormField.ENTERQUESTION', 'Enter Question'); $field = new TextField('Title', $label, $this->getField('Title')); $field->setName($this->getFieldName('Title')); if(!$this->canEdit()) { return $field->performReadonlyTransformation(); } return $field; } /** Returns the Title for rendering in the front-end (with XML values escaped) */ public function getTitle() { return Convert::raw2att($this->getField('Title')); } /** * Return the base name for this form field in the * form builder. Optionally returns the name with the given field * * @param String Field Name * * @return String */ public function getFieldName($field = false) { return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]"; } /** * Generate a name for the Setting field * * @param String name of the setting * @return String */ public function getSettingName($field) { $name = $this->getFieldName('CustomSettings'); return $name . '[' . $field .']'; } /** * How to save the data submitted in this field into * the database object which this field represents. * * Any class's which call this should also call * {@link parent::populateFromPostData()} to ensure * that this method is called * * @access public */ public function populateFromPostData($data) { $this->Title = (isset($data['Title'])) ? $data['Title']: ""; $this->Default = (isset($data['Default'])) ? $data['Default'] : ""; $this->Sort = (isset($data['Sort'])) ? $data['Sort'] : null; $this->Required = !empty($data['Required']) ? 1 : 0; $this->Name = $this->class.$this->ID; $this->CustomRules = ""; $this->CustomErrorMessage = (isset($data['CustomErrorMessage'])) ? $data['CustomErrorMessage'] : ""; $this->CustomSettings = ""; // custom settings if(isset($data['CustomSettings'])) { $this->setSettings($data['CustomSettings']); } // custom validation if(isset($data['CustomRules'])) { $rules = array(); foreach($data['CustomRules'] as $key => $value) { if(is_array($value)) { $fieldValue = (isset($value['Value'])) ? $value['Value'] : ''; if(isset($value['ConditionOption']) && $value['ConditionOption'] == "Blank" || $value['ConditionOption'] == "NotBlank") { $fieldValue = ""; } $rules[] = array( 'Display' => (isset($value['Display'])) ? $value['Display'] : "", 'ConditionField' => (isset($value['ConditionField'])) ? $value['ConditionField'] : "", 'ConditionOption' => (isset($value['ConditionOption'])) ? $value['ConditionOption'] : "", 'Value' => $fieldValue ); } } $this->CustomRules = serialize($rules); } $this->write(); } /** * Implement custom field Configuration on this field. Includes such things as * settings and options of a given editable form field * * @return FieldSet */ public function getFieldConfiguration() { $extraClass = ($this->getSetting('ExtraClass')) ? $this->getSetting('ExtraClass') : ''; if (is_array(self::$allowed_css) && !empty(self::$allowed_css)) { foreach(self::$allowed_css as $k => $v) { if (!is_array($v)) $cssList[$k]=$v; elseif ($k == $this->ClassName()) $cssList = array_merge($cssList, $v); } $ec = new DropdownField( $this->getSettingName('ExtraClass'), _t('EditableFormField.EXTRACLASSA', 'Extra Styling/Layout'), $cssList, $extraClass ); } else { $ec = new TextField( $this->getSettingName('ExtraClass'), _t('EditableFormField.EXTRACLASSB', 'Extra css Class - separate multiples with a space'), $extraClass ); } $right = new TextField( $this->getSettingName('RightTitle'), _t('EditableFormField.RIGHTTITLE', 'Right Title'), $this->getSetting('RightTitle') ); $fields = FieldList::create( $ec, $right ); $this->extend('updateFieldConfiguration', $fields); return $fields; } /** * Append custom validation fields to the default 'Validation' * section in the editable options view * * @return FieldSet */ public function getFieldValidationOptions() { $fields = new FieldList( new CheckboxField($this->getFieldName('Required'), _t('EditableFormField.REQUIRED', 'Is this field Required?'), $this->Required), new TextField($this->getFieldName('CustomErrorMessage'), _t('EditableFormField.CUSTOMERROR','Custom Error Message'), $this->CustomErrorMessage) ); if(!$this->canEdit()) { foreach($fields as $field) { $field->performReadonlyTransformation(); } } $this->extend('updateFieldValidationOptions', $fields); return $fields; } /** * Return a FormField to appear on the front end. Implement on * your subclass * * @return FormField */ public function getFormField() { user_error("Please implement a getFormField() on your EditableFormClass ". $this->ClassName, E_USER_ERROR); } /** * Return the instance of the submission field class * * @return SubmittedFormField */ public function getSubmittedFormField() { return new SubmittedFormField(); } /** * Show this form field (and its related value) in the reports and in emails. * * @return bool */ public function showInReports() { return true; } /** * Return the validation information related to this field. This is * interrupted as a JSON object for validate plugin and used in the * PHP. * * @see http://docs.jquery.com/Plugins/Validation/Methods * @return Array */ public function getValidation() { return $this->Required ? array('required' => true) : array(); } public function getValidationJSON() { return Convert::raw2json($this->getValidation()); } /** * Return the error message for this field. Either uses the custom * one (if provided) or the default SilverStripe message * * @return Varchar */ public function getErrorMessage() { $title = strip_tags("'". ($this->Title ? $this->Title : $this->Name) . "'"); $standard = sprintf(_t('Form.FIELDISREQUIRED', '%s is required').'.', $title); // only use CustomErrorMessage if it has a non empty value $errorMessage = (!empty($this->CustomErrorMessage)) ? $this->CustomErrorMessage : $standard; return DBField::create_field('Varchar', $errorMessage); } }