Webylon 3.2 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • 1c
    • exchange
      • catalog
  • auth
  • Booking
  • building
    • company
  • cart
    • shipping
    • steppedcheckout
  • Catalog
    • monument
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • AssetManager
  • CartTableListField_Item
  • ComplexTableField
  • ComplexTableField_Item
  • ComplexTableField_ItemRequest
  • ComplexTableField_Popup
  • CountryDropdownField
  • DataObjectManager
  • DataObjectManager_Item
  • DataObjectManager_ItemRequest
  • DocumentPageFiles_Manager
  • FileDataObjectManager
  • FileDataObjectManager_Item
  • FileDataObjectManager_ItemRequest
  • HasManyComplexTableField
  • HasManyComplexTableField_Item
  • HasManyDataObjectManager
  • HasManyDataObjectManager_Item
  • HasManyFileDataObjectManager
  • HasManyFileDataObjectManager_Item
  • HasOneComplexTableField
  • HasOneComplexTableField_Item
  • HasOneDataObjectManager
  • HasOneDataObjectManager_Item
  • HasOneFileDataObjectManager
  • HasOneFileDataObjectManager_Item
  • ImageAssetManager
  • ImageDataObjectManager
  • ImageDataObjectManager_Item
  • ImageDataObjectManager_ItemRequest
  • LanguageDropdownField
  • ManyManyComplexTableField
  • ManyManyComplexTableField_Item
  • ManyManyDataObjectManager
  • ManyManyDataObjectManager_Item
  • ManyManyFileDataObjectManager
  • ManyManyFileDataObjectManager_Item
  • Mediaweb3DPageFiles_Manager
  • MediawebPageFiles_Manager
  • MediawebPagePhoto_Manager
  • MediawebPageTexture_Manager
  • PhotoAlbumManager
  • ScaffoldingComplexTableField_Popup
  • SubpageListField_Item
  • SubPageListField_ItemRequest
  • SubsiteAgnosticTableListField
  • TableField
  • TableField_Item
  • TableListField
  • TableListField_Item
  • TableListField_ItemRequest
  • TreeDropdownField
  • TreeDropdownField_Readonly
  • TreeMultiselectField
  • TreeMultiselectField_Readonly
  • TreeSelectorField
  1 <?php
  2 /**
  3  * TableField behaves in the same manner as TableListField, however allows the addition of 
  4  * fields and editing of attributes specified, and filtering results.
  5  * 
  6  * Caution: If you insert DropdownFields in the fieldTypes-array, make sure they have an empty first option.
  7  * Otherwise the saving can't determine if a new row should really be saved.
  8  * 
  9  * Caution: TableField relies on {@FormResponse} to reload the field after it is saved.
 10  * A TableField-instance should never be saved twice without reloading, because otherwise it 
 11  * can't determine if a field is new (=create) or existing (=update), and will produce duplicates.
 12  * 
 13  * @param $name string The fieldname
 14  * @param $sourceClass string The source class of this field
 15  * @param $fieldList array An array of field headings of Fieldname => Heading Text (eg. heading1)
 16  * @param $fieldTypes array An array of field types of fieldname => fieldType (eg. formfield). Do not use for extra data/hiddenfields.
 17  * @param $filterField string The field to filter by.  Give the filter value in $sourceFilter.  The value will automatically be set on new records.
 18  * @param $sourceFilter string If $filterField has a value, then this is the value to filter by.  Otherwise, it is a SQL filter expression.
 19  * @param $editExisting boolean (Note: Has to stay on this position for legacy reasons)
 20  * @param $sourceSort string
 21  * @param $sourceJoin string
 22  * 
 23  * @todo We should refactor this to support a single FieldSet instead of evaluated Strings for building FormFields
 24  * 
 25  * @package forms
 26  * @subpackage fields-relational
 27  */
 28  
 29 class TableField extends TableListField {
 30     
 31     protected $sourceClass;
 32     
 33     protected $sourceFilter;
 34     
 35     protected $fieldList;
 36     
 37     /**
 38      * A "Field = Value" filter can be specified by setting $this->filterField and $this->filterValue.  This has the advantage of auto-populating
 39      * new records
 40      */
 41     protected $filterField = null;
 42 
 43     /**
 44      * A "Field = Value" filter can be specified by setting $this->filterField and $this->filterValue.  This has the advantage of auto-populating
 45      * new records
 46      */
 47     protected $filterValue = null;
 48     
 49     /**
 50      * @var $fieldTypes FieldSet
 51      * Caution: Use {@setExtraData()} instead of manually adding HiddenFields if you want to 
 52      * preset relations or other default data.
 53      */
 54     protected $fieldTypes;
 55     
 56     protected $sourceSort;
 57     
 58     protected $sourceJoin;
 59 
 60     /**
 61      * @var $template string Template-Overrides
 62      */
 63     protected $template = "TableField";
 64     
 65     /**
 66      * @var $extraData array Any extra data that need to be included, e.g. to retain
 67      * has-many relations. Format: array('FieldName' => 'Value')
 68      */
 69     protected $extraData;
 70     
 71     protected $tempForm;
 72     
 73     /**
 74      * Influence output without having to subclass the template.
 75      */
 76     protected $permissions = array(
 77         "edit",
 78         "delete",
 79         "add",
 80         //"export",
 81     );
 82     
 83     public $transformationConditions = array();
 84     
 85     /**
 86      * @var $requiredFields array Required fields as a numerical array.
 87      * Please use an instance of Validator on the including
 88      * form.
 89      */
 90     protected $requiredFields = null;
 91     
 92     /**
 93      * Shows a row of empty fields for adding a new record
 94      * (turned on by default). 
 95      * Please use {@link TableField::$permissions} to control
 96      * if the "add"-functionality incl. button is shown at all.
 97      * 
 98      * @param boolean $showAddRow
 99      */
100     public $showAddRow = true;
101     
102     /**
103      * Automatically detect a has-one relationship
104      * in the popup (=child-class) and save the relation ID.
105      *
106      * @var boolean
107      */
108     protected $relationAutoSetting = true;
109 
110     function __construct($name, $sourceClass, $fieldList = null, $fieldTypes, $filterField = null, 
111                         $sourceFilter = null, $editExisting = true, $sourceSort = null, $sourceJoin = null) {
112         
113         $this->fieldTypes = $fieldTypes;
114         $this->filterField = $filterField;
115         
116         $this->editExisting = $editExisting;
117 
118         // If we specify filterField, then an implicit source filter of "filterField = sourceFilter" is used.
119         if($filterField) {
120             $this->filterValue = $sourceFilter;
121             $sourceFilter = "\"$filterField\" = '" . Convert::raw2sql($sourceFilter) . "'";
122         }
123         parent::__construct($name, $sourceClass, $fieldList, $sourceFilter, $sourceSort, $sourceJoin);
124     }
125     
126     /** 
127      * Displays the headings on the template
128      * 
129      * @return DataObjectSet
130      */
131     function Headings() {
132         $i=0;
133         foreach($this->fieldList as $fieldName => $fieldTitle) {
134             $extraClass = "col".$i;
135             $class = $this->fieldTypes[$fieldName];
136             if(is_object($class)) $class = "";
137             $class = $class." ".$extraClass;
138             $headings[] = new ArrayData(array("Name" => $fieldName, "Title" => $fieldTitle, "Class" => $class));
139             $i++;
140         }
141         return new DataObjectSet($headings);
142     }
143     
144     /**
145      * Calculates the number of columns needed for colspans
146      * used in template
147      * 
148      * @return int
149      */
150     function ItemCount() {
151         return count($this->fieldList);
152     }
153     
154     /**
155      * Returns the databased saved items, from DataObjects
156      * 
157      * @return DataObjectSet
158      */
159      /* 
160         by menedem:
161             без этой функции корректно работает паджинация для TableField. Ее нет в TableField версии 3.1.5 (единственное отличие)
162             без паджинации большой список в TableField не занееш - всегда сохраняет всю портянку
163             оставляю пока так, если вылезут глюки - нужно вернуть
164     function sourceItems() {
165         if($this->customSourceItems) {
166             $items = $this->customSourceItems;
167         } elseif($this->cachedSourceItems) {
168             $items = $this->cachedSourceItems;
169         } else {
170             // get query
171             $dataQuery = $this->getQuery();
172             // get data
173             $records = $dataQuery->execute();
174             $items = singleton($this->sourceClass)->buildDataObjectSet($records);
175         }
176 
177         return $items;
178     }
179     */
180     /**
181      * Displays the items from {@link sourceItems()} using the encapsulation object.
182      * If the field value has been set as an array (e.g. after a failed validation),
183      * it generates the rows from array data instead.
184      * Used in the formfield template to iterate over each row.
185      * 
186      * @return DataObjectSet Collection of {@link TableField_Item}
187      */
188     function Items() {
189         // holds TableField_Item instances
190         $items = new DataObjectSet();
191 
192         $sourceItems = $this->sourceItems();
193 
194         // either load all rows from the field value,
195         // (e.g. when validation failed), or from sourceItems()
196         if($this->value) {
197             if(!$sourceItems) $sourceItems = new DataObjectSet();
198 
199             // get an array keyed by rows, rather than values
200             $rows = $this->sortData(ArrayLib::invert($this->value));
201             // ignore all rows which are already saved
202             if(isset($rows['new'])) {
203                 $newRows = $this->sortData($rows['new']);
204                 // iterate over each value (not each row)
205                 $i = 0;
206                 foreach($newRows as $idx => $newRow){
207                     // set a pseudo-ID
208                     $newRow['ID'] = "new";
209 
210                     // unset any extradata
211                     foreach($newRow as $k => $v){
212                         if($this->extraData && array_key_exists($k, $this->extraData)){
213                             unset($newRow[$k]);
214                         }
215                     }
216 
217                     // generate a temporary DataObject container (not saved in the database)
218                     $sourceClass = $this->sourceClass;
219                     $sourceItems->push(new $sourceClass($newRow));
220 
221                     $i++;
222                 }
223             }
224         } 
225 
226         // generate a new TableField_Item instance from each collected item
227         if($sourceItems) foreach($sourceItems as $sourceItem) {
228             $items->push($this->generateTableFieldItem($sourceItem));
229         }
230 
231         // add an empty TableField_Item for a single "add row"
232         if($this->showAddRow && $this->Can('add')) {
233             $items->push(new TableField_Item(null, $this, null, $this->fieldTypes, true));
234         }
235 
236         return $items;
237     }
238 
239     /**
240      * Generates a new {@link TableField} instance
241      * by loading a fieldset for this row into a temporary form.
242      * 
243      * @param DataObject $dataObj
244      * @return TableField_Item
245      */
246     protected function generateTableFieldItem($dataObj) {
247         // Load the data in to a temporary form (for correct field types)
248         $form = new Form(
249             $this, 
250             null, 
251             $this->FieldSetForRow(), 
252             new FieldSet()
253         );
254         $form->loadDataFrom($dataObj);
255 
256         // Add the item to our new DataObjectSet, with a wrapper class.
257         return new TableField_Item($dataObj, $this, $form, $this->fieldTypes);
258     }
259     
260     /**
261      * @return array
262      */
263     function FieldList() {
264         return $this->fieldList;
265     }
266     
267     /** 
268      * Saves the Dataobjects contained in the field
269      */
270     function saveInto(DataObject $record) {
271         // CMS sometimes tries to set the value to one.
272         if(is_array($this->value)){
273             $newFields = array();
274             
275             // Sort into proper array
276             $value = ArrayLib::invert($this->value);
277             $dataObjects = $this->sortData($value, $record->ID);
278             
279             // New fields are nested in their own sub-array, and need to be sorted separately
280             if(isset($dataObjects['new']) && $dataObjects['new']) {
281                 $newFields = $this->sortData($dataObjects['new'], $record->ID);
282             }
283 
284             // Update existing fields
285             // @todo Should this be in an else{} statement?
286             $savedObjIds = $this->saveData($dataObjects, $this->editExisting);
287             
288             // Save newly added record
289             if($savedObjIds || $newFields) {
290                 $savedObjIds = $this->saveData($newFields,false);
291             }
292 
293             // Optionally save the newly created records into a relationship
294             // on $record. This assumes the name of this formfield instance
295             // is set to a relationship name on $record.
296             if($this->relationAutoSetting) {
297                 $relationName = $this->Name();
298                 if($record->has_many($relationName) || $record->many_many($relationName)) {
299                     if($savedObjIds) foreach($savedObjIds as $id => $status) {
300                         $record->$relationName()->add($id);
301                     }   
302                 }
303             }
304 
305             // Update the internal source items cache
306             $this->value = null;
307             $items = $this->sourceItems();
308             
309             FormResponse::update_dom_id($this->id(), $this->FieldHolder());
310         }
311     }
312     
313     /**
314      * Get all {@link FormField} instances necessary for a single row,
315      * respecting the casting set in {@link $fieldTypes}.
316      * Doesn't populate with any data. Optionally performs a readonly
317      * transformation if {@link $IsReadonly} is set, or the current user
318      * doesn't have edit permissions.
319      * 
320      * @return FieldSet
321      */
322     function FieldSetForRow() {
323         $fieldset = new FieldSet();
324         if($this->fieldTypes){
325             foreach($this->fieldTypes as $key => $fieldType) {
326                 if(isset($fieldType->class) && is_subclass_of($fieldType, 'FormField')) {
327                     // using clone, otherwise we would just add stuff to the same field-instance
328                     $field = clone $fieldType;
329                 } elseif(strpos($fieldType, '(') === false) {
330                     $field = new $fieldType($key);
331                 } else {
332                     $fieldName = $key;
333                     $fieldTitle = "";
334                     $field = eval("return new $fieldType;");
335                 }
336                 if($this->IsReadOnly || !$this->Can('edit')) {
337                     $field = $field->performReadonlyTransformation();
338                 }
339                 $fieldset->push($field);
340             }
341         }else{
342             USER_ERROR("TableField::FieldSetForRow() - Fieldtypes were not specified",E_USER_WARNING);
343         }
344 
345         return $fieldset;
346     }
347     
348     function performReadonlyTransformation() {
349         $clone = clone $this;
350         $clone->permissions = array('show');
351         $clone->setReadonly(true);
352         return $clone;
353     }
354 
355     function performDisabledTransformation() {
356         $clone = clone $this;
357         $clone->setPermissions(array('show'));
358         $clone->setDisabled(true);
359         return $clone;
360     }
361     
362     /**
363      * Needed for Form->callfieldmethod.
364      */
365     public function getField($fieldName, $combinedFieldName = null) {
366         $fieldSet = $this->FieldSetForRow();
367         $field = $fieldSet->dataFieldByName($fieldName);
368         if(!$field) {
369             return false;
370         }
371         
372         if($combinedFieldName) {
373             $field->Name = $combinedFieldName;
374         }
375 
376         return $field;
377     }
378         
379     /**
380      * Called on save, it creates the appropriate objects and writes them
381      * to the database.
382      * 
383      * @param DataObjectSet $dataObjects
384      * @param boolean $existingValues If set to TRUE, it tries to find existing objects
385      *  based on the database IDs passed as array keys in $dataObjects parameter.
386      *  If set to FALSE, it will always create new object (default: TRUE)
387      * @return array Array of saved object IDs in the key, and the status ("Updated") in the value
388      */
389     function saveData($dataObjects, $existingValues = true) {
390         if(!$dataObjects) return false;
391 
392         $savedObjIds = array();
393         $fieldset = $this->FieldSetForRow();
394 
395         // add hiddenfields
396         if($this->extraData) {
397             foreach($this->extraData as $fieldName => $fieldValue) {
398                 $fieldset->push(new HiddenField($fieldName));
399             }
400         }
401 
402         $form = new Form($this, null, $fieldset, new FieldSet());
403 
404         foreach ($dataObjects as $objectid => $fieldValues) {
405             // 'new' counts as an empty column, don't save it
406             if($objectid === "new") continue;
407 
408             // extra data was creating fields, but
409             if($this->extraData) {
410                 $fieldValues = array_merge( $this->extraData, $fieldValues );
411             }
412 
413             // either look for an existing object, or create a new one
414             if($existingValues) {
415                 $obj = DataObject::get_by_id($this->sourceClass, $objectid);
416             } else {
417                 $sourceClass = $this->sourceClass;
418                 $obj = new $sourceClass();
419             }
420 
421             // Legacy: Use the filter as a predefined relationship-ID 
422             if($this->filterField && $this->filterValue) {
423                 $filterField = $this->filterField;
424                 $obj->$filterField = $this->filterValue;
425             }
426 
427             // Determine if there is changed data for saving
428             $dataFields = array();
429             foreach($fieldValues as $type => $value) {
430                 // if the field is an actual datafield (not a preset hiddenfield)
431                 if(is_array($this->extraData)) { 
432                     if(!in_array($type, array_keys($this->extraData))) {
433                         $dataFields[$type] = $value;
434                     }
435                 // all fields are real 
436                 } else {  
437                     $dataFields[$type] = $value;
438                 }
439             }
440             $dataValues = ArrayLib::array_values_recursive($dataFields);
441             // determine if any of the fields have a value (loose checking with empty())
442             $hasData = false;
443             foreach($dataValues as $value) {
444                 if(!empty($value)) $hasData = true;
445             }
446 
447             if($hasData) {
448                 $form->loadDataFrom($fieldValues, true);
449                 $form->saveInto($obj);
450 
451                 $objectid = $obj->write();
452 
453                 $savedObjIds[$objectid] = "Updated";
454             }
455 
456         }
457 
458         return $savedObjIds;
459    }
460     
461     /** 
462      * Organises the data in the appropriate manner for saving
463      * 
464      * @param array $data 
465      * @param int $recordID
466      * @return array Collection of maps suitable to construct DataObjects
467      */
468     function sortData($data, $recordID = null) {
469         if(!$data) return false;
470         
471         $sortedData = array();
472         
473         foreach($data as $field => $rowData) {
474             $i = 0;
475             if(!is_array($rowData)) continue;
476             
477             foreach($rowData as $id => $value) {
478                 if($value == '$recordID') $value = $recordID;
479                 
480                 if($value) $sortedData[$id][$field] = $value;
481 
482                 $i++;
483             }
484             
485             // TODO ADD stuff for removing rows with incomplete data
486         }
487         
488         return $sortedData;
489     }
490     
491     /**
492      * @param $extraData array
493      */
494     function setExtraData($extraData) {
495         $this->extraData = $extraData;
496     }
497     
498     /**
499      * @return array
500      */
501     function getExtraData() {
502         return $this->extraData;
503     }
504     
505     /**
506      * Sets the template to be rendered with
507      */
508     function FieldHolder() {
509         Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js');
510         Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js');
511         Requirements::javascript(SAPPHIRE_DIR . '/javascript/prototype_improvements.js');
512         Requirements::javascript(THIRDPARTY_DIR . '/scriptaculous/effects.js');
513         Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
514         Requirements::javascript(SAPPHIRE_DIR . '/javascript/TableListField.js');
515         Requirements::javascript(SAPPHIRE_DIR . '/javascript/TableField.js');
516         Requirements::css(SAPPHIRE_DIR . '/css/TableListField.css');
517         
518         return $this->renderWith($this->template);
519     }
520     
521     /**
522      * @return Int
523      */
524     function sourceID() {
525         return $this->filterField;
526     }
527         
528     function setTransformationConditions($conditions) {
529         $this->transformationConditions = $conditions;
530     }
531     
532     function jsValidation() {
533         $js = "";
534 
535         $items = $this->Items();
536         if($items) foreach($items as $item) {
537             foreach($item->Fields() as $field) {
538                 //if the field type has some special specific specification for validation of itself
539                 $js .= $field->jsValidation($this->form->class."_".$this->form->Name());
540             }
541         }
542         
543         // TODO Implement custom requiredFields
544         $items = $this->sourceItems(); 
545         if($items && $this->requiredFields && $items->count()) {
546             foreach ($this->requiredFields as $field) {
547                 foreach($items as $item){
548                     $cellName = $this->Name().'['.$item->ID.']['.$field.']';
549                     $js .= "\n";
550                     if($fields->dataFieldByName($cellName)) {
551                         $js .= <<<JS
552 if(typeof fromAnOnBlur != 'undefined'){
553     if(fromAnOnBlur.name == '$cellName')
554         require(fromAnOnBlur);
555 }else{
556     require('$cellName');
557 }
558 JS;
559                     }
560                 }
561             }
562         }
563 
564         return $js;
565     }
566     
567     function php($data) {
568         $valid = true;
569         
570         if($data['methodName'] != 'delete') {
571             $items = $this->Items();
572             if($items) foreach($items as $item) {
573                 foreach($item->Fields() as $field) {
574                     $valid = $field->validate($this) && $valid;
575                 }
576             }
577 
578             return $valid;
579         } else {
580             return $valid;
581         }
582     }
583     
584     function validate($validator) {
585         $errorMessage = '';
586         $valid = true;
587         
588         // @todo should only contain new elements
589         $items = $this->Items();
590         if($items) foreach($items as $item) {
591             foreach($item->Fields() as $field) {
592                 $valid = $field->validate($validator) && $valid;
593             }
594         }
595 
596         //debug::show($this->form->Message());
597         if($this->requiredFields&&$sourceItemsNew&&$sourceItemsNew->count()) {
598             foreach ($this->requiredFields as $field) {
599                 foreach($sourceItemsNew as $item){
600                     $cellName = $this->Name().'['.$item->ID.']['.$field.']';
601                     $cName =  $this->Name().'[new]['.$field.'][]';
602                     
603                     if($fieldObj = $fields->dataFieldByName($cellName)) {
604                         if(!trim($fieldObj->Value())){
605                             $title = $fieldObj->Title();
606                             $errorMessage .= sprintf(
607                                 _t('TableField.ISREQUIRED', "In %s '%s' is required."),
608                                 $this->name,
609                                 $title
610                             );
611                             $errorMessage .= "<br />";
612                         }
613                     }
614                 }
615             }
616         }
617 
618         if($errorMessage){
619             $messageType .= "validation";
620             $message .= "<br />".$errorMessage;
621         
622             $validator->validationError($this->name, $message, $messageType);
623         }
624 
625         return $valid;
626     }
627     
628     function setRequiredFields($fields) {
629         $this->requiredFields = $fields;
630     }
631     
632     /**
633      * @param boolean $value 
634      */
635     function setRelationAutoSetting($value) {
636         $this->relationAutoSetting = $value;
637     }
638     
639     /**
640      * @return boolean
641      */
642     function getRelationAutoSetting() {
643         return $this->relationAutoSetting;
644     }
645 }
646 
647 /**
648  * Single record in a TableField.
649  * @package forms
650  * @subpackage fields-relational
651  * @see TableField
652  */ 
653 class TableField_Item extends TableListField_Item {
654     
655     /**
656      * @var FieldSet $fields
657      */
658     protected $fields;
659     
660     protected $data;
661     
662     protected $fieldTypes;
663     
664     protected $isAddRow;
665     
666     protected $extraData;
667     
668     /** 
669      * Each row contains a dataobject with any number of attributes
670      * @param $ID int The ID of the record
671      * @param $form Form A Form object containing all of the fields for this item.  The data should be loaded in
672      * @param $fieldTypes array An array of name => fieldtype for use when creating a new field
673      * @param $parent TableListField The parent table for quick reference of names, and id's for storing values.
674      */
675     function __construct($item = null, $parent, $form, $fieldTypes, $isAddRow = false) {
676         $this->data = $form;
677         $this->fieldTypes = $fieldTypes;
678         $this->isAddRow = $isAddRow;
679         $this->item = $item;
680 
681         parent::__construct(($this->item) ? $this->item : new DataObject(), $parent);
682         
683         $this->fields = $this->createFields();
684     }
685     /** 
686      * Represents each cell of the table with an attribute.
687      *
688      * @return FieldSet
689      */
690     function createFields() {
691         // Existing record
692         if($this->item && $this->data) {
693             $form = $this->data;
694             $this->fieldset = $form->Fields();
695             $this->fieldset->removeByName('SecurityID');
696             if($this->fieldset) {
697                 $i=0;
698                 foreach($this->fieldset as $field) {
699                     $origFieldName = $field->Name();
700 
701                     // set unique fieldname with id
702                     $combinedFieldName = $this->parent->Name() . "[" . $this->ID() . "][" . $origFieldName . "]";
703                     // ensure to set field to nested array notation
704                     // if its an unsaved row, or the "add row" which is present by default
705                     if($this->isAddRow || $this->ID() == 'new') $combinedFieldName .= '[]';
706                     
707                     // get value
708                     if(strpos($origFieldName,'.') === false) {
709                         $value = $field->dataValue();
710                     } else {                    
711                         // this supports the syntax fieldName = Relation.RelatedField               
712                         $fieldNameParts = explode('.', $origFieldName)  ;
713                         $tmpItem = $this->item;
714                         for($j=0;$j<sizeof($fieldNameParts);$j++) {
715                             $relationMethod = $fieldNameParts[$j];
716                             $idField = $relationMethod . 'ID';
717                             if($j == sizeof($fieldNameParts)-1) {
718                                 $value = $tmpItem->$relationMethod;
719                             } else {
720                                 $tmpItem = $tmpItem->$relationMethod();
721                             }
722                         }
723                     }
724                     
725                     $field->Name = $combinedFieldName;
726                     $field->setValue($field->dataValue());
727                     $field->addExtraClass('col'.$i);
728                     $field->setForm($this->data); 
729 
730                     // transformation
731                     if(isset($this->parent->transformationConditions[$origFieldName])) {
732                         $transformation = $this->parent->transformationConditions[$origFieldName]['transformation'];
733                         $rule = str_replace("\$","\$this->item->", $this->parent->transformationConditions[$origFieldName]['rule']);
734                         $ruleApplies = null;
735                         eval('$ruleApplies = ('.$rule.');');
736                         if($ruleApplies) {
737                             $field = $field->$transformation();
738                         }
739                     }
740                     
741                     // formatting
742                     $item = $this->item;
743                     $value = $field->Value();
744                     if(array_key_exists($origFieldName, $this->parent->fieldFormatting)) {
745                         $format = str_replace('$value', "__VAL__", $this->parent->fieldFormatting[$origFieldName]);
746                         $format = preg_replace('/\$([A-Za-z0-9-_]+)/','$item->$1', $format);
747                         $format = str_replace('__VAL__', '$value', $format);
748                         eval('$value = "' . $format . '";');
749                         $field->dontEscape = true;
750                         $field->setValue($value);
751                     }
752                     
753                     $this->fields[] = $field;
754                     $i++;
755                 }
756             }
757         // New record
758         } else {
759             $list = $this->parent->FieldList();
760             $i=0;
761             foreach($list as $fieldName => $fieldTitle) {
762                 if(strpos($fieldName, ".")) {
763                     $shortFieldName = substr($fieldName, strpos($fieldName, ".")+1, strlen($fieldName));
764                 } else {
765                     $shortFieldName = $fieldName;
766                 }
767                 $combinedFieldName = $this->parent->Name() . "[new][" . $shortFieldName . "][]";
768                 $fieldType = $this->fieldTypes[$fieldName];
769                 if(isset($fieldType->class) && is_subclass_of($fieldType, 'FormField')) {
770                     $field = clone $fieldType; // we can't use the same instance all over, as we change names
771                     $field->Name = $combinedFieldName;
772                 } elseif(strpos($fieldType, '(') === false) {
773                     //echo ("<li>Type: ".$fieldType." fieldName: ". $filedName. " Title: ".$fieldTitle."</li>");
774                     $field = new $fieldType($combinedFieldName,$fieldTitle);
775                 } else {
776                     $field = eval("return new " . $fieldType . ";");
777                 }
778                 $field->addExtraClass('col'.$i);
779                 $this->fields[] = $field;
780                 $i++;
781             }
782         }
783         return new FieldSet($this->fields);
784     }
785     
786     function Fields() {
787         return $this->fields;
788     }
789     
790     function ExtraData() {
791         $content = ""; 
792         $id = ($this->item->ID) ? $this->item->ID : "new";
793         if($this->parent->getExtraData()) {
794             foreach($this->parent->getExtraData() as $fieldName=>$fieldValue) {
795                 $name = $this->parent->Name() . "[" . $id . "][" . $fieldName . "]";
796                 if($this->isAddRow) $name .= '[]';
797                 $field = new HiddenField($name, null, $fieldValue);
798                 $content .= $field->FieldHolder() . "\n";
799             }
800         }
801 
802         return $content;
803     }
804     
805     /**
806      * Get the flag isAddRow of this item, 
807      * to indicate if the item is that blank last row in the table which is not in the database
808      * 
809      * @return boolean
810      */
811     function IsAddRow(){
812         return $this->isAddRow;
813     }
814     
815 }
816 
817 ?>
[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. -
Webylon 3.2 API Docs API documentation generated by ApiGen 2.8.0