Version: current

      1 <?php
      2 /**
      3  * A form field allowing a user to customize and create form fields.
      4  * for saving into a {@link UserDefinedForm}
      5  *
      6  * @package userforms
      7  */
      8
      9 class FieldEditor extends FormField {
     10
     11     /**
     12      * Field Editor Template
     13      *
     14      * @return String
     15      */
     16     function FieldHolder() {
     17         return $this->renderWith("FieldEditor");
     18     }
     19
     20     /**
     21      * Returns whether a user can edit the form
     22      *
     23      * @return boolean
     24      */
     25     public function canEdit() {
     26         if($this->readonly) return false;
     27
     28         return $this->form->getRecord()->canEdit();
     29     }
     30
     31     /**
     32      * Returns whether a user delete a field in the form. The {@link EditableFormField}s
     33      * check if they can delete themselves but this counts as an {@link self::canEdit()}
     34      * function rather than a delete
     35      *
     36      * @return boolean
     37      */
     38     public function canDelete() {
     39         if($this->readonly) return false;
     40
     41         return $this->form->getRecord()->canEdit();
     42     }
     43
     44     /**
     45      * Transform this form field to a readonly version.
     46      *
     47      * @return ViewableData_Customised
     48      */
     49     function performReadonlyTransformation() {
     50         $clone = clone $this;
     51         $clone->readonly = true;
     52         $fields = $clone->Fields();
     53         if($fields) foreach($fields as $field) {
     54             $field->setReadonly();
     55         }
     56
     57         return $clone->customise(array('Fields' => $fields));
     58     }
     59
     60     /**
     61      * Return the fields for the user forms
     62      *
     63      * @return DataObjectSet
     64      */
     65     function Fields() {
     66         // Don't return any fields unless we actually have the dependent parameters set on the form field
     67         if($this->form && $this->form->getRecord() && $this->name) {
     68             $relationName = $this->name;
     69             $fields = $this->form->getRecord()->getComponents($relationName);
     70
     71             if($fields) {
     72                 foreach($fields as $field) {
     73                     if(!$this->canEdit()) {
     74                         if(is_a($field, 'FormField')) {
     75                             $fields->remove($field);
     76                             $fields->push($field->performReadonlyTransformation());
     77                         }
     78                     }
     79                 }
     80             }
     81
     82             return $fields;
     83         }
     84     }
     85
     86     /**
     87      * Return a DataObjectSet of all the addable fields to populate
     88      * the add field menu
     89      *
     90      * @return DataObjectSet
     91      */
     92     function CreatableFields() {
     93         $fields = ClassInfo::subclassesFor('EditableFormField');
     94
     95         if($fields) {
     96             array_shift($fields); // get rid of subclass 0
     97             asort($fields); // get in order
     98             $output = new DataObjectSet();
     99             foreach($fields as $field => $title) {
    100                 // get the nice title and strip out field
    101                 $niceTitle = singleton($title)->i18n_singular_name();
    102                 if($niceTitle && singleton($title)->canCreate()) {
    103                     $output->push(new ArrayData(array(
    104                         'ClassName' => $field,
    105                         'Title' => "$niceTitle"
    106                     )));
    107                 }
    108             }
    109             return $output;
    110         }
    111         return false;
    112     }
    113
    114     /**
    115      * Handles saving the page. Needs to keep an eye on fields
    116      * and options which have been removed / added
    117      *
    118      * @param DataObject Record to Save it In
    119      */
    120     function saveInto(DataObjectInterface $record) {
    121         $name = $this->name;
    122         $fieldSet = $record->$name();
    123
    124         // store the field IDs and delete the missing fields
    125         // alternatively, we could delete all the fields and re add them
    126         $missingFields = array();
    127
    128         foreach($fieldSet as $existingField) {
    129             $missingFields[$existingField->ID] = $existingField;
    130         }
    131
    132         if(isset($_REQUEST[$name]) && is_array($_REQUEST[$name])) {
    133             foreach($_REQUEST[$name] as $newEditableID => $newEditableData) {
    134                 if(!is_numeric($newEditableID)) continue;
    135
    136                 // get it from the db
    137                 $editable = DataObject::get_by_id('EditableFormField', $newEditableID);
    138
    139                 // if it exists in the db update it
    140                 if($editable) {
    141
    142                     // remove it from the removed fields list
    143                     if(isset($missingFields[$editable->ID]) && isset($newEditableData) && is_array($newEditableData)) {
    144                         unset($missingFields[$editable->ID]);
    145                     }
    146
    147                     // set form id
    148                     if($editable->ParentID == 0) {
    149                         $editable->ParentID = $record->ID;
    150                     }
    151
    152                     // save data
    153                     $editable->populateFromPostData($newEditableData);
    154                 }
    155             }
    156         }
    157
    158         // remove the fields not saved
    159         if($this->canEdit()) {
    160             foreach($missingFields as $removedField) {
    161                 if(is_numeric($removedField->ID)) {
    162                     // check we can edit this
    163                     $removedField->delete();
    164                 }
    165             }
    166         }
    167     }
    168
    169     /**
    170      * Add a field to the field editor. Called via a ajax get request
    171      * from the userdefinedform javascript
    172      *
    173      * @return bool|html
    174      */
    175     public function addfield() {
    176         // get the last field in this form editor
    177         $parentID = $this->form->getRecord()->ID;
    178
    179         if($parentID) {
    180             $parentID = Convert::raw2sql($parentID);
    181
    182             $highestSort = DB::query("SELECT MAX(\"Sort\") FROM \"EditableFormField\" WHERE \"ParentID\" = '$parentID'");
    183
    184             $sort = $highestSort->value() + 1;
    185
    186             $className = (isset($_REQUEST['Type'])) ? $_REQUEST['Type'] : '';
    187             if(!$className) user_error('Please select a field type to created', E_USER_WARNING);
    188
    189             if(is_subclass_of($className, "EditableFormField")) {
    190                 $field = new $className();
    191                 $field->write();
    192                 $field->ParentID = $this->form->getRecord()->ID;
    193                 $field->Name = $field->class . $field->ID;
    194                 $field->Sort = $sort;
    195                 $field->write();
    196                 return $field->EditSegment();
    197             }
    198         }
    199         return false;
    200     }
    201
    202     /**
    203      * Return the html for a field option such as a
    204      * dropdown field or a radio check box field
    205      *
    206      * @return bool|html
    207      */
    208     public function addoptionfield() {
    209         // passed via the ajax
    210         $parent = (isset($_REQUEST['Parent'])) ? $_REQUEST['Parent'] : false;
    211
    212         // work out the sort by getting the sort of the last field in the form +1
    213         if($parent) {
    214             $sql_parent = Convert::raw2sql($parent);
    215
    216             $highestSort = DB::query("SELECT MAX(\"Sort\") FROM \"EditableOption\" WHERE \"ParentID\" = '$sql_parent'");
    217
    218             $sort = $highestSort->value() + 1;
    219
    220             if($parent) {
    221                 $object = new EditableOption();
    222                 $object->write();
    223                 $object->ParentID = $parent;
    224                 $object->Sort = $sort;
    225                 $object->Name = 'option' . $object->ID;
    226                 $object->write();
    227                 return $object->EditSegment();
    228             }
    229         }
    230         return false;
    231     }
    232 }

[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. -