Version: current

      1 <?php
      2 /**
      3  * Represents the base class of a editable form field
      4  * object like {@link EditableTextField}.
      5  *
      6  * @package userforms
      7  */
      8
      9 class EditableFormField extends DataObject {
     10
     11     static $default_sort = "Sort";
     12
     13     /**
     14      * A list of CSS classes that can be added
     15      *
     16      * @var array
     17      */
     18     public static $allowed_css = array();
     19
     20     static $db = array(
     21         "Name" => "Varchar",
     22         "Title" => "Varchar(255)",
     23         "Default" => "Varchar",
     24         "Sort" => "DBInt",
     25         "Required" => "Boolean",
     26         "CustomErrorMessage" => "Varchar(255)",
     27         "CustomRules" => "Text",
     28         "CustomSettings" => "Text",
     29         "CustomParameter" => "Varchar(200)",
     30     );
     31
     32     static $has_one = array(
     33         "Parent" => "UserDefinedForm",
     34     );
     35
     36     static $extensions = array(
     37         "Versioned('Stage', 'Live')"
     38     );
     39
     40     /**
     41      * @var bool
     42      */
     43     protected $readonly;
     44
     45     /**
     46      * Список возможных autocomplete
     47      *
     48      *
     49      * @return <type>
     50      */
     51     static function get_possible_autocompletes($empty=false) {
     52         if (property_exists('FormField', 'possible_autocomplete_values')) {
     53             $rs = array();
     54             if ($empty) {
     55                 $rs['off'] = _t("EditableFormField.Autocomplete_off");
     56             }
     57             foreach(FormField::$possible_autocomplete_values as $value) {
     58                 $rs[$value] = _t("EditableFormField.Autocomplete_{$value}");
     59             }
     60             return $rs;
     61         }
     62         return false;
     63     }
     64
     65     /**
     66      * Set the visibility of an individual form field
     67      *
     68      * @param bool
     69      */
     70     public function setReadonly($readonly = true) {
     71         $this->readonly = $readonly;
     72     }
     73
     74     /**
     75      * Returns whether this field is readonly
     76      *
     77      * @return bool
     78      */
     79     public function isReadonly() {
     80         return $this->readonly;
     81     }
     82
     83     /**
     84      * Template to render the form field into
     85      *
     86      * @return String
     87      */
     88     function EditSegment() {
     89         return $this->renderWith('EditableFormField');
     90     }
     91
     92     function canCreate($member = null) {
     93         return true;
     94     }
     95
     96     /**
     97      * Return whether a user can delete this form field
     98      * based on whether they can edit the page
     99      *
    100      * @return bool
    101      */
    102     public function canDelete($member = null) {
    103         return ($this->Parent()->canEdit() && !$this->isReadonly());
    104     }
    105
    106     /**
    107      * Return whether a user can edit this form field
    108      * based on whether they can edit the page
    109      *
    110      * @return bool
    111      */
    112     public function canEdit($member = null) {
    113         return ($this->Parent()->canEdit($member) && !$this->isReadonly());
    114     }
    115
    116     /**
    117      * Publish this Form Field to the live site
    118      *
    119      * Wrapper for the {@link Versioned} publish function
    120      */
    121     public function doPublish($fromStage="Stage", $toStage="Live", $createNewVersion = false) {
    122         $this->publish($fromStage, $toStage, $createNewVersion);
    123     }
    124
    125     /**
    126      * Delete this form from a given stage
    127      *
    128      * Wrapper for the {@link Versioned} deleteFromStage function
    129      */
    130     public function doDeleteFromStage($stage) {
    131         $this->deleteFromStage($stage);
    132     }
    133
    134
    135     /**
    136      * Show this form on load or not
    137      *
    138      * @return bool
    139      */
    140     function getShowOnLoad() {
    141         return ($this->getSetting('ShowOnLoad') == "Show" || $this->getSetting('ShowOnLoad') == '') ? true : false;
    142     }
    143
    144     /**
    145      * To prevent having tables for each fields minor settings we store it as
    146      * a serialized array in the database.
    147      *
    148      * @return Array Return all the Settings
    149      */
    150     public function getSettings() {
    151         return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
    152     }
    153
    154     /**
    155      * Set the custom settings for this field as we store the minor details in
    156      * a serialized array in the database
    157      *
    158      * @param Array the custom settings
    159      */
    160     public function setSettings($settings = array()) {
    161         $this->CustomSettings = serialize($settings);
    162     }
    163
    164     /**
    165      * Set a given field setting. Appends the option to the settings or overrides
    166      * the existing value
    167      *
    168      * @param String key
    169      * @param String value
    170      */
    171     public function setSetting($key, $value) {
    172         $settings = $this->getSettings();
    173         $settings[$key] = $value;
    174
    175         $this->setSettings($settings);
    176     }
    177
    178     /**
    179      * Set the allowed css classes for the extraClass custom setting
    180      *
    181      * @param array The permissible CSS classes to add
    182      */
    183     public function setAllowedCss(array $allowed) {
    184         if (is_array($allowed_css)){
    185             foreach ($allowed_css as $k => $v){
    186                 self::$allowed_css[$k] = (!is_null($v)) ? $v : $k;
    187             }
    188         }
    189     }
    190
    191     /**
    192      * Return just one custom setting or empty string if it does
    193      * not exist
    194      *
    195      * @param String Value to use as key
    196      * @return String
    197      */
    198     public function getSetting($setting) {
    199         $settings = $this->getSettings();
    200         if(isset($settings) && count($settings) > 0) {
    201             if(isset($settings[$setting])) {
    202                 return $settings[$setting];
    203             }
    204         }
    205         return '';
    206     }
    207
    208     /**
    209      * Get the path to the icon for this field type, relative to the site root.
    210      *
    211      * @return string
    212      */
    213     public function getIcon() {
    214         return 'userforms/images/' . strtolower($this->class) . '.png';
    215     }
    216
    217     /**
    218      * Return whether or not this field has addable options
    219      * such as a dropdown field or radio set
    220      *
    221      * @return bool
    222      */
    223     public function getHasAddableOptions() {
    224         return false;
    225     }
    226
    227     /**
    228      * Return whether or not this field needs to show the extra
    229      * options dropdown list
    230      *
    231      * @return bool
    232      */
    233     public function showExtraOptions() {
    234         return true;
    235     }
    236
    237     /**
    238      * Return the custom validation fields for this field for the CMS
    239      *
    240      * @return array
    241      */
    242     public function Dependencies() {
    243         return ($this->CustomRules) ? unserialize($this->CustomRules) : array();
    244     }
    245
    246     /**
    247      * Return the custom validation fields for the field
    248      *
    249      * @return DataObjectSet
    250      */
    251     public function CustomRules() {
    252         $output = new DataObjectSet();
    253         $fields = $this->Parent()->Fields();
    254
    255         // check for existing ones
    256         if($rules = $this->Dependencies()) {
    257             foreach($rules as $rule => $data) {
    258                 // recreate all the field object to prevent caching
    259                 $outputFields = new DataObjectSet();
    260
    261                 foreach($fields as $field) {
    262                     $new = clone $field;
    263
    264                     $new->isSelected = ($new->Name == $data['ConditionField']) ? true : false;
    265                     $outputFields->push($new);
    266                 }
    267
    268                 $output->push(new ArrayData(array(
    269                     'FieldName' => $this->getFieldName(),
    270                     'Display' => $data['Display'],
    271                     'Fields' => $outputFields,
    272                     'ConditionField' => $data['ConditionField'],
    273                     'ConditionOption' => $data['ConditionOption'],
    274                     'Value' => $data['Value']
    275                 )));
    276             }
    277         }
    278
    279         return $output;
    280     }
    281
    282     /**
    283      * Title field of the field in the backend of the page
    284      *
    285      * @return TextField
    286      */
    287     function TitleField() {
    288         $label = _t('EditableFormField.ENTERQUESTION', 'Enter Question');
    289
    290         $field = new TextField('Title', $label, $this->getField('Title'));
    291         $field->setName($this->getFieldName('Title'));
    292
    293         if(!$this->canEdit()) {
    294             return $field->performReadonlyTransformation();
    295         }
    296
    297         return $field;
    298     }
    299
    300     /** Returns the Title for rendering in the front-end (with XML values escaped) */
    301     function getTitle() {
    302         return Convert::raw2att($this->getField('Title'));
    303     }
    304
    305     /**
    306      * Return the base name for this form field in the
    307      * form builder. Optionally returns the name with the given field
    308      *
    309      * @param String Field Name
    310      *
    311      * @return String
    312      */
    313     public function getFieldName($field = false) {
    314         return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
    315     }
    316
    317     /**
    318      * Generate a name for the Setting field
    319      *
    320      * @param String name of the setting
    321      * @return String
    322      */
    323     public function getSettingName($field) {
    324         $name = $this->getFieldName('CustomSettings');
    325
    326         return $name . '[' . $field .']';
    327     }
    328
    329     /**
    330      * How to save the data submitted in this field into
    331      * the database object which this field represents.
    332      *
    333      * Any class's which call this should also call
    334      * {@link parent::populateFromPostData()} to ensure
    335      * that this method is called
    336      *
    337      * @access public
    338      */
    339     public function populateFromPostData($data) {
    340         $this->Title        = (isset($data['Title'])) ? $data['Title']: "";
    341         $this->Default      = (isset($data['Default'])) ? $data['Default'] : "";
    342         $this->Sort         = (isset($data['Sort'])) ? $data['Sort'] : null;
    343         $this->Required     = !empty($data['Required']) ? 1 : 0;
    344         $this->Name         = $this->class.$this->ID;
    345         $this->CustomRules  = "";
    346         $this->CustomErrorMessage   = (isset($data['CustomErrorMessage'])) ? $data['CustomErrorMessage'] : "";
    347         $this->CustomSettings       = "";
    348
    349         // custom settings
    350         if(isset($data['CustomSettings'])) {
    351             $this->setSettings($data['CustomSettings']);
    352         }
    353
    354         // custom validation
    355         if(isset($data['CustomRules'])) {
    356             $rules = array();
    357
    358             foreach($data['CustomRules'] as $key => $value) {
    359
    360                 if(is_array($value)) {
    361                     $fieldValue = (isset($value['Value'])) ? $value['Value'] : '';
    362
    363                     if(isset($value['ConditionOption']) && $value['ConditionOption'] == "Blank" || $value['ConditionOption'] == "NotBlank") {
    364                         $fieldValue = "";
    365                     }
    366
    367                     $rules[] = array(
    368                         'Display' => (isset($value['Display'])) ? $value['Display'] : "",
    369                         'ConditionField' => (isset($value['ConditionField'])) ? $value['ConditionField'] : "",
    370                         'ConditionOption' => (isset($value['ConditionOption'])) ? $value['ConditionOption'] : "",
    371                         'Value' => $fieldValue
    372                     );
    373                 }
    374             }
    375
    376             $this->CustomRules = serialize($rules);
    377         }
    378
    379         $this->write();
    380     }
    381
    382     /**
    383      * Implement custom field Configuration on this field. Includes such things as
    384      * settings and options of a given editable form field
    385      *
    386      * @return FieldSet
    387      */
    388     public function getFieldConfiguration() {
    389         $extraClass = ($this->getSetting('ExtraClass')) ? $this->getSetting('ExtraClass') : '';
    390
    391         if (is_array(self::$allowed_css) && !empty(self::$allowed_css)) {
    392             foreach(self::$allowed_css as $k => $v) {
    393                 if (!is_array($v)) $cssList[$k]=$v;
    394                 elseif ($k == $this->ClassName()) $cssList = array_merge($cssList, $v);
    395             }
    396
    397             $ec = new DropdownField(
    398                 $this->getSettingName('ExtraClass'),
    399                 _t('EditableFormField.EXTRACLASSA', 'Extra Styling/Layout'),
    400                 $cssList, $extraClass
    401             );
    402
    403         }
    404         else {
    405             $ec = new TextField(
    406                 $this->getSettingName('ExtraClass'),
    407                 _t('EditableFormField.EXTRACLASSB', 'Extra css Class - separate multiples with a space'),
    408                 $extraClass
    409             );
    410         }
    411
    412         $right = new TextField(
    413             $this->getSettingName('RightTitle'),
    414             _t('EditableFormField.RIGHTTITLE', 'Right Title'),
    415             $this->getSetting('RightTitle')
    416         );
    417
    418         $placeholder = new TextField(
    419             $this->getSettingName('Placeholder'),
    420             _t('EditableFormField.PLACEHOLDER', 'Placeholder'),
    421             $this->getSetting('Placeholder')
    422         );
    423
    424         return new FieldSet(
    425             $ec,
    426             $right,
    427             $placeholder
    428         );
    429     }
    430
    431     /**
    432      * Append custom validation fields to the default 'Validation'
    433      * section in the editable options view
    434      *
    435      * @return FieldSet
    436      */
    437     public function getFieldValidationOptions() {
    438         $fields = new FieldSet(
    439             new CheckboxField($this->getFieldName('Required'), _t('EditableFormField.REQUIRED', 'Is this field Required?'), $this->Required),
    440             new TextField($this->getFieldName('CustomErrorMessage'), _t('EditableFormField.CUSTOMERROR','Custom Error Message'), $this->CustomErrorMessage)
    441         );
    442
    443         if(!$this->canEdit()) {
    444             foreach($fields as $field) {
    445                 $field->performReadonlyTransformation();
    446             }
    447         }
    448
    449         return $fields;
    450     }
    451
    452     /**
    453      * Return a FormField to appear on the front end. Implement on
    454      * your subclass
    455      *
    456      * @return FormField
    457      */
    458     public function getFormField() {
    459         user_error("Please implement a getFormField() on your EditableFormClass ". $this->ClassName, E_USER_ERROR);
    460     }
    461
    462     /**
    463      * Return the instance of the submission field class
    464      *
    465      * @return SubmittedFormField
    466      */
    467     public function getSubmittedFormField() {
    468         return new SubmittedFormField();
    469     }
    470
    471
    472     /**
    473      * Show this form field (and its related value) in the reports and in emails.
    474      *
    475      * @return bool
    476      */
    477     function showInReports() {
    478         return true;
    479     }
    480
    481     /**
    482      * Return the validation information related to this field. This is
    483      * interrupted as a JSON object for validate plugin and used in the
    484      * PHP.
    485      *
    486      * @see http://docs.jquery.com/Plugins/Validation/Methods
    487      * @return Array
    488      */
    489     public function getValidation() {
    490         return ($this->Required) ? array('required' => true) : array();
    491     }
    492
    493     /**
    494      * Return the error message for this field. Either uses the custom
    495      * one (if provided) or the default SilverStripe message
    496      *
    497      * @return Varchar
    498      */
    499     public function getErrorMessage() {
    500         $title = strip_tags("'". ($this->Title ? $this->Title : $this->Name) . "'");
    501         $standard = sprintf(_t('Form.FIELDISREQUIRED', '%s is required').'.', $title);
    502
    503         $errorMessage = ($this->CustomErrorMessage) ? $this->CustomErrorMessage : $standard;
    504
    505         return DBField::create('Varchar', $errorMessage);
    506     }
    507 }
    508

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -