/** * @return MultiRecordFileAttachmentField */ public static function cast(FileAttachmentField $field) { $castCopy = MultiRecordFileAttachmentField::create($field->getName(), $field->Title(), $field->Value(), $field->getForm()); foreach (get_object_vars($field) as $property => $value) { $castCopy->{$property} = $value; } return $castCopy; }
/** * @return FieldList|null */ public function getRecordDataFields(DataObjectInterface $record) { $fieldsFunction = $this->getFieldsFunction(); if (!$fieldsFunction) { $fieldsFunction = $this->getDefaultFieldsFunction($record); } $fields = null; if (is_callable($fieldsFunction)) { $fields = $fieldsFunction($record); } else { if (method_exists($record, $fieldsFunction) || method_exists($record, 'hasMethod') && $record->hasMethod($fieldsFunction)) { $fields = $record->{$fieldsFunction}(); } else { if ($this->fieldsFunctionFallback) { $fieldsFunction = $this->getDefaultFieldsFunction($record); $fields = $record->{$fieldsFunction}(); } else { throw new Exception($record->class . '::' . $fieldsFunction . ' function does not exist.'); } } } if (!$fields || !$fields instanceof FieldList) { throw new Exception('Function callback on ' . __CLASS__ . ' must return a FieldList.'); } $record->extend('updateMultiEditFields', $fields); $fields = $fields->dataFields(); if (!$fields) { $errorMessage = __CLASS__ . ' is missing fields for record #' . $record->ID . ' on class "' . $record->class . '".'; if (is_callable($fieldsFunction)) { throw new Exception($errorMessage . '. This is due to the closure set with "setFieldsFunction" not returning a populated FieldList.'); } throw new Exception($errorMessage . '. This is due ' . $record->class . '::' . $fieldsFunction . ' not returning a populated FieldList.'); } // $recordExists = $record->exists(); // Set value from record if it exists or if re-loading data after failed form validation $recordShouldSetValue = $recordExists || $record->MultiRecordField_NewID; // Setup sort field $sortFieldName = $this->getSortFieldName(); if ($sortFieldName) { $sortField = isset($fields[$sortFieldName]) ? $fields[$sortFieldName] : null; if ($sortField && !$sortField instanceof HiddenField) { throw new Exception('Cannot utilize drag and drop sort functionality if the sort field is explicitly used on form. Suggestion: $fields->removeByName("' . $sortFieldName . '") in ' . $record->class . '::' . $fieldsFunction . '().'); } if (!$sortField) { $sortValue = $recordShouldSetValue ? $record->{$sortFieldName} : self::SORT_INVALID; $sortField = HiddenField::create($sortFieldName); if ($sortField instanceof HiddenField) { $sortField->setAttribute('value', $sortValue); } else { $sortField->setValue($sortValue); } $sortField->setAttribute('data-ignore-delete-check', 1); // NOTE(Jake): Uses array_merge() to prepend the sort field in the $fields associative array. // The sort field is prepended so jQuery.find('.js-multirecordfield-sort-field').first() // finds the related sort field to this, rather than a sort field nested deeply in other // MultiRecordField's. $fields = array_merge(array($sortFieldName => $sortField), $fields); } $sortField->addExtraClass('js-multirecordfield-sort-field'); } // Set heading (ie. 'My Record (Draft)') $titleFieldName = $this->getTitleField(); $status = ''; if (!$titleFieldName) { $recordSectionTitle = $record->MultiRecordEditingTitle; if (!$recordSectionTitle) { $recordSectionTitle = $record->Title; $status = $recordExists ? $record->CMSPublishedState : 'New'; } } else { $recordSectionTitle = $record->{$titleFieldName}; } if (!$recordSectionTitle) { // NOTE(Jake): Ensures no title'd ToggleCompositeField's have a proper height. $recordSectionTitle = ' '; } $recordSectionTitle .= ' <span class="js-multirecordfield-title-status">'; $recordSectionTitle .= $status ? '(' . $status . ')' : ''; $recordSectionTitle .= '</span>'; // Add heading field / Togglable composite field with heading $subRecordField = MultiRecordSubRecordField::create('', $recordSectionTitle, null); $subRecordField->setParent($this); $subRecordField->setRecord($record); if ($this->readonly) { $subRecordField = $subRecordField->performReadonlyTransformation(); } // Modify sub-fields to work properly with this field $currentFieldListModifying = $subRecordField; foreach ($fields as $field) { $fieldName = $field->getName(); if ($recordShouldSetValue) { if (isset($record->{$fieldName}) || $record->hasMethod($fieldName) || $record->hasMethod('hasField') && $record->hasField($fieldName)) { $val = $record->__get($fieldName); $field->setValue($val, $record); } } if ($field instanceof MultiRecordField) { $field->depth = $this->depth + 1; $action = $this->getActionURL($field, $record); $field->setAttribute('data-action', $action); // NOTE(Jake): Unclear at time of writing (17-06-2016) if nested MultiRecordField should // inherit certain settings or not. Might add flag like 'setRecursiveOptions' later // or something. $field->setFieldsFunction($this->getFieldsFunction(), $this->fieldsFunctionFallback); //$field->setTitleField($this->getTitleField()); } else { $config = $this->getConfig(); if ($config === null) { $config = $this->config()->default_config; } // todo(Jake): Make it walk class hierarchy so that things that extend say 'HtmlEditorField' // will also get the config. Make the '*HtmlEditorField' denote that it's only // for that class, sub-classes. if (isset($config[$field->class])) { $fieldConfig = $config[$field->class]; $functionCalls = isset($fieldConfig['functions']) ? $fieldConfig['functions'] : array(); if ($functionCalls) { foreach ($functionCalls as $methodName => $arguments) { $arguments = (array) $arguments; call_user_func_array(array($field, $methodName), $arguments); } } } if ($field instanceof FileAttachmentField) { // fix(Jake) // todo(Jake): Fix deletion // Support for Unclecheese's Dropzone module // @see: https://github.com/unclecheese/silverstripe-dropzone/tree/1.2.3 $action = $this->getActionURL($field, $record); $field = MultiRecordFileAttachmentField::cast($field); $field->multiRecordAction = $action; // Fix $field->Value() if ($recordShouldSetValue && !$val && isset($record->{$fieldName . 'ID'})) { // NOTE(Jake): This check was added for 'FileAttachmentField'. // Putting this outside of this 'instanceof' if-statement will break UploadField. $val = $record->__get($fieldName . 'ID'); if ($val) { $field->setValue($val, $record); } } } else { if (class_exists('MultiRecord' . $field->class)) { // Handle generic case (ie. UploadField) // Where we just want to override value returned from $field->Link() // so FormField actions work. $class = 'MultiRecord' . $field->class; $fieldCopy = $class::create($field->getName(), $field->Title()); foreach (get_object_vars($field) as $property => $value) { $fieldCopy->{$property} = $value; } $fieldCopy->multiRecordAction = $this->getActionURL($field, $record); $field = $fieldCopy; } } // NOTE(Jake): Should probably add an ->extend() so other modules can monkey patch fields. // Will wait to see if its needed. } // NOTE(Jake): Required to support UploadField. Generic so any field can utilize this functionality. if (method_exists($field, 'setRecord') || method_exists($field, 'hasMethod') && $field->hasMethod('setRecord')) { $field->setRecord($record); } $currentFieldListModifying->push($field); } $resultFieldList = new FieldList(); $resultFieldList->push($subRecordField); $resultFieldList->setForm($this->form); return $resultFieldList; }