Convert to psr-2

This commit is contained in:
Damian Mooyman 2016-07-21 17:53:59 +12:00
parent e620576e97
commit 57048fd901
56 changed files with 6119 additions and 5737 deletions

View File

@ -1,7 +1,7 @@
<?php
if(!defined('USERFORMS_DIR')) {
define('USERFORMS_DIR', basename(__DIR__));
if (!defined('USERFORMS_DIR')) {
define('USERFORMS_DIR', basename(__DIR__));
}
Deprecation::notification_version('3.0', 'userforms');

View File

@ -7,113 +7,118 @@
*
* @package userforms
*/
class UserFormsGridFieldFilterHeader extends GridFieldFilterHeader {
class UserFormsGridFieldFilterHeader extends GridFieldFilterHeader
{
/**
* A map of name => value of columns from all submissions
* @var array
*/
protected $columns;
/**
* A map of name => value of columns from all submissions
* @var array
*/
protected $columns;
public function setColumns($columns) {
$this->columns = $columns;
}
public function setColumns($columns)
{
$this->columns = $columns;
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
if(!$this->checkDataType($gridField->getList())) {
return;
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
{
if (!$this->checkDataType($gridField->getList())) {
return;
}
if($actionName === 'filter') {
$gridField->State->UserFormsGridField = array(
'filter' => isset($data['FieldNameFilter']) ? $data['FieldNameFilter'] : null,
'value' => isset($data['FieldValue']) ? $data['FieldValue'] : null,
'start' => isset($data['StartFilter']) ? $data['StartFilter'] : null,
'end' => isset($data['EndFilter']) ? $data['EndFilter'] : null
);
}
}
if ($actionName === 'filter') {
$gridField->State->UserFormsGridField = array(
'filter' => isset($data['FieldNameFilter']) ? $data['FieldNameFilter'] : null,
'value' => isset($data['FieldValue']) ? $data['FieldValue'] : null,
'start' => isset($data['StartFilter']) ? $data['StartFilter'] : null,
'end' => isset($data['EndFilter']) ? $data['EndFilter'] : null
);
}
}
public function getHTMLFragments($gridField) {
$fields = new ArrayList();
$state = $gridField->State->UserFormsGridField;
public function getHTMLFragments($gridField)
{
$fields = new ArrayList();
$state = $gridField->State->UserFormsGridField;
$selectedField = $state->filter;
$selectedValue = $state->value;
$selectedField = $state->filter;
$selectedValue = $state->value;
// show dropdown of all the fields available from the submitted form fields
// that have been saved. Takes the titles from the currently live form.
$columnField = new DropdownField('FieldNameFilter', '');
$columnField->setSource($this->columns);
$columnField->setEmptyString(_t('UserFormsGridFieldFilterHeader.FILTERSUBMISSIONS', 'Filter Submissions..'));
$columnField->setHasEmptyDefault(true);
$columnField->setValue($selectedField);
// show dropdown of all the fields available from the submitted form fields
// that have been saved. Takes the titles from the currently live form.
$columnField = new DropdownField('FieldNameFilter', '');
$columnField->setSource($this->columns);
$columnField->setEmptyString(_t('UserFormsGridFieldFilterHeader.FILTERSUBMISSIONS', 'Filter Submissions..'));
$columnField->setHasEmptyDefault(true);
$columnField->setValue($selectedField);
$valueField = new TextField('FieldValue', '', $selectedValue);
$valueField = new TextField('FieldValue', '', $selectedValue);
$columnField->addExtraClass('ss-gridfield-sort');
$columnField->addExtraClass('no-change-track');
$columnField->addExtraClass('ss-gridfield-sort');
$columnField->addExtraClass('no-change-track');
$valueField->addExtraClass('ss-gridfield-sort');
$valueField->addExtraClass('no-change-track');
$valueField->setAttribute(
'placeholder',
_t('UserFormsGridFieldFilterHeader.WHEREVALUEIS', 'where value is..'
));
$valueField->addExtraClass('ss-gridfield-sort');
$valueField->addExtraClass('no-change-track');
$valueField->setAttribute(
'placeholder',
_t('UserFormsGridFieldFilterHeader.WHEREVALUEIS', 'where value is..'
));
$fields->push(new FieldGroup(new CompositeField(
$columnField,
$valueField
)));
$fields->push(new FieldGroup(new CompositeField(
$columnField,
$valueField
)));
$fields->push(new FieldGroup(new CompositeField(
$start = new DateField('StartFilter', _t('UserFormsGridFieldFilterHeader.FROM', 'From')),
$end = new DateField('EndFilter', _t('UserFormsGridFieldFilterHeader.TILL', 'Till'))
)));
$fields->push(new FieldGroup(new CompositeField(
$start = new DateField('StartFilter', _t('UserFormsGridFieldFilterHeader.FROM', 'From')),
$end = new DateField('EndFilter', _t('UserFormsGridFieldFilterHeader.TILL', 'Till'))
)));
foreach(array($start, $end) as $date) {
$date->setConfig('showcalendar', true);
$date->setConfig('dateformat', 'y-mm-dd');
$date->setConfig('datavalueformat', 'y-mm-dd');
$date->addExtraClass('no-change-track');
}
foreach (array($start, $end) as $date) {
$date->setConfig('showcalendar', true);
$date->setConfig('dateformat', 'y-mm-dd');
$date->setConfig('datavalueformat', 'y-mm-dd');
$date->addExtraClass('no-change-track');
}
$end->setValue($state->end);
$start->setValue($state->start);
$end->setValue($state->end);
$start->setValue($state->start);
$fields->push($actions = new FieldGroup(
GridField_FormAction::create($gridField, 'filter', false, 'filter', null)
->addExtraClass('ss-gridfield-button-filter')
->setAttribute('title', _t('GridField.Filter', "Filter"))
->setAttribute('id', 'action_filter_' . $gridField->getModelClass() . '_' . $columnField),
GridField_FormAction::create($gridField, 'reset', false, 'reset', null)
->addExtraClass('ss-gridfield-button-close')
->setAttribute('title', _t('GridField.ResetFilter', "Reset"))
->setAttribute('id', 'action_reset_' . $gridField->getModelClass() . '_' . $columnField)
)
);
$fields->push($actions = new FieldGroup(
GridField_FormAction::create($gridField, 'filter', false, 'filter', null)
->addExtraClass('ss-gridfield-button-filter')
->setAttribute('title', _t('GridField.Filter', "Filter"))
->setAttribute('id', 'action_filter_' . $gridField->getModelClass() . '_' . $columnField),
GridField_FormAction::create($gridField, 'reset', false, 'reset', null)
->addExtraClass('ss-gridfield-button-close')
->setAttribute('title', _t('GridField.ResetFilter', "Reset"))
->setAttribute('id', 'action_reset_' . $gridField->getModelClass() . '_' . $columnField)
)
);
$actions->addExtraClass('filter-buttons');
$actions->addExtraClass('no-change-track');
$actions->addExtraClass('filter-buttons');
$actions->addExtraClass('no-change-track');
$forTemplate = new ArrayData(array(
'Fields' => $fields
));
$forTemplate = new ArrayData(array(
'Fields' => $fields
));
return array(
'header' => $forTemplate->renderWith('GridFieldFilterHeader_Row')
);
}
return array(
'header' => $forTemplate->renderWith('GridFieldFilterHeader_Row')
);
}
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
$state = $gridField->State;
public function getManipulatedData(GridField $gridField, SS_List $dataList)
{
$state = $gridField->State;
if($filter = $state->UserFormsGridField->toArray()) {
if(isset($filter['filter']) && $filter['filter'] && isset($filter['value']) && $filter['value']) {
$dataList = $dataList->where(sprintf("
if ($filter = $state->UserFormsGridField->toArray()) {
if (isset($filter['filter']) && $filter['filter'] && isset($filter['value']) && $filter['value']) {
$dataList = $dataList->where(sprintf("
SELECT COUNT(*) FROM SubmittedFormField
WHERE (
ParentID = SubmittedForm.ID AND
@ -121,24 +126,24 @@ class UserFormsGridFieldFilterHeader extends GridFieldFilterHeader {
Value LIKE '%s'
) > 0",
Convert::raw2sql($filter['filter']),
Convert::raw2sql($filter['value'])
));
}
Convert::raw2sql($filter['filter']),
Convert::raw2sql($filter['value'])
));
}
if(isset($filter['start']) && $filter['start']) {
$dataList = $dataList->filter(array(
'Created:GreaterThan' => $filter['start']
));
}
if (isset($filter['start']) && $filter['start']) {
$dataList = $dataList->filter(array(
'Created:GreaterThan' => $filter['start']
));
}
if(isset($filter['end']) && $filter['end']) {
$dataList = $dataList->filter(array(
'Created:LessThan' => $filter['end']
));
}
}
if (isset($filter['end']) && $filter['end']) {
$dataList = $dataList->filter(array(
'Created:LessThan' => $filter['end']
));
}
}
return $dataList;
}
return $dataList;
}
}

View File

@ -5,140 +5,147 @@
*
* {@see EditableFileField}
*/
class SecureEditableFileField extends DataExtension {
class SecureEditableFileField extends DataExtension
{
/**
* Path to secure files location under assets
*
* @config
* @var type
*/
private static $secure_folder_name = 'SecureUploads';
/**
* Path to secure files location under assets
*
* @config
* @var type
*/
private static $secure_folder_name = 'SecureUploads';
/**
* Disable file security if a user-defined mechanism is in place
*
* @config
* @var bool
*/
private static $disable_security = false;
/**
* Disable file security if a user-defined mechanism is in place
*
* @config
* @var bool
*/
private static $disable_security = false;
/*
* Check if file security is enabled
*
* @return bool
*/
public function getIsSecurityEnabled() {
// Skip if requested
if($this->owner->config()->disable_security) {
return false;
}
/*
* Check if file security is enabled
*
* @return bool
*/
public function getIsSecurityEnabled()
{
// Skip if requested
if ($this->owner->config()->disable_security) {
return false;
}
// Check for necessary security module
if(!class_exists('SecureFileExtension')) {
trigger_error('SecureEditableFileField requires secureassets module', E_USER_WARNING);
return false;
}
// Check for necessary security module
if (!class_exists('SecureFileExtension')) {
trigger_error('SecureEditableFileField requires secureassets module', E_USER_WARNING);
return false;
}
return true;
}
return true;
}
public function requireDefaultRecords() {
// Skip if disabled
if(!$this->getIsSecurityEnabled()) {
return;
}
public function requireDefaultRecords()
{
// Skip if disabled
if (!$this->getIsSecurityEnabled()) {
return;
}
// Update all instances of editablefilefield which do NOT have a secure folder assigned
foreach(EditableFileField::get() as $fileField) {
// Skip if secured
if($fileField->getIsSecure()) {
continue;
}
// Update all instances of editablefilefield which do NOT have a secure folder assigned
foreach (EditableFileField::get() as $fileField) {
// Skip if secured
if ($fileField->getIsSecure()) {
continue;
}
// Force this field to secure itself on write
$fileField->write(false, false, true);
DB::alteration_message(
"Restricting editable file field \"{$fileField->Title}\" to secure folder",
"changed"
);
}
}
// Force this field to secure itself on write
$fileField->write(false, false, true);
DB::alteration_message(
"Restricting editable file field \"{$fileField->Title}\" to secure folder",
"changed"
);
}
}
/**
* Secure this field before saving
*/
public function onBeforeWrite() {
$this->makeSecure();
}
/**
* Secure this field before saving
*/
public function onBeforeWrite()
{
$this->makeSecure();
}
/**
* Ensure this field is secured, but does not write changes to the database
*/
public function makeSecure() {
// Skip if disabled or already secure
if(!$this->getIsSecurityEnabled() || $this->owner->getIsSecure()) {
return;
}
/**
* Ensure this field is secured, but does not write changes to the database
*/
public function makeSecure()
{
// Skip if disabled or already secure
if (!$this->getIsSecurityEnabled() || $this->owner->getIsSecure()) {
return;
}
// Ensure folder exists
$folder = $this->owner->Folder();
if(!$folder || !$folder->exists()) {
// Create new folder in default location
$folder = Folder::find_or_make($this->owner->config()->secure_folder_name);
$this->owner->FolderID = $folder->ID;
// Ensure folder exists
$folder = $this->owner->Folder();
if (!$folder || !$folder->exists()) {
// Create new folder in default location
$folder = Folder::find_or_make($this->owner->config()->secure_folder_name);
$this->owner->FolderID = $folder->ID;
} elseif ($this->isFolderSecured($folder)) {
// If folder exists and is secure stop
return;
}
} elseif($this->isFolderSecured($folder)) {
// If folder exists and is secure stop
return;
}
// Make secure
$folder->CanViewType = 'OnlyTheseUsers';
$folder->ViewerGroups()->add($this->findAdminGroup());
$folder->write();
}
// Make secure
$folder->CanViewType = 'OnlyTheseUsers';
$folder->ViewerGroups()->add($this->findAdminGroup());
$folder->write();
}
/**
* Find target group to record
*
* @return Group
*/
protected function findAdminGroup()
{
singleton('Group')->requireDefaultRecords();
return Permission::get_groups_by_permission('ADMIN')->First();
}
/**
* Find target group to record
*
* @return Group
*/
protected function findAdminGroup() {
singleton('Group')->requireDefaultRecords();
return Permission::get_groups_by_permission('ADMIN')->First();
}
/**
* Determine if the field is secure
*
* @return bool
*/
public function getIsSecure()
{
return $this->isFolderSecured($this->owner->Folder());
}
/**
* Determine if the field is secure
*
* @return bool
*/
public function getIsSecure() {
return $this->isFolderSecured($this->owner->Folder());
}
/**
* Check if a Folder object is secure
*
* @param Folder $folder
* @return boolean
*/
protected function isFolderSecured($folder)
{
if (! ($folder instanceof Folder) || !$folder->exists()) {
return false;
}
/**
* Check if a Folder object is secure
*
* @param Folder $folder
* @return boolean
*/
protected function isFolderSecured($folder) {
if(! ($folder instanceof Folder) || !$folder->exists()) {
return false;
}
switch($folder->CanViewType) {
case 'OnlyTheseUsers':
return true;
case 'Inherit':
$parent = $folder->Parent();
return $parent && $parent->exists() && $this->isFolderSecured($parent);
case 'Anyone':
case 'LoggedInUsers':
default:
return false;
}
}
switch ($folder->CanViewType) {
case 'OnlyTheseUsers':
return true;
case 'Inherit':
$parent = $folder->Parent();
return $parent && $parent->exists() && $this->isFolderSecured($parent);
case 'Anyone':
case 'LoggedInUsers':
default:
return false;
}
}
}

View File

@ -3,235 +3,245 @@
/**
* @package userforms
*/
class UserFormFieldEditorExtension extends DataExtension {
class UserFormFieldEditorExtension extends DataExtension
{
/**
* @var array
*/
private static $has_many = array(
'Fields' => 'EditableFormField'
);
/**
* @var array
*/
private static $has_many = array(
'Fields' => 'EditableFormField'
);
/**
* Adds the field editor to the page.
*
* @return FieldList
*/
public function updateCMSFields(FieldList $fields) {
$fieldEditor = $this->getFieldEditorGrid();
/**
* Adds the field editor to the page.
*
* @return FieldList
*/
public function updateCMSFields(FieldList $fields)
{
$fieldEditor = $this->getFieldEditorGrid();
$fields->insertAfter(new Tab('FormFields', _t('UserFormFieldEditorExtension.FORMFIELDS', 'Form Fields')), 'Main');
$fields->addFieldToTab('Root.FormFields', $fieldEditor);
$fields->insertAfter(new Tab('FormFields', _t('UserFormFieldEditorExtension.FORMFIELDS', 'Form Fields')), 'Main');
$fields->addFieldToTab('Root.FormFields', $fieldEditor);
return $fields;
}
return $fields;
}
/**
* Gets the field editor, for adding and removing EditableFormFields.
*
* @return GridField
*/
public function getFieldEditorGrid() {
Requirements::javascript(USERFORMS_DIR . '/javascript/FieldEditor.js');
/**
* Gets the field editor, for adding and removing EditableFormFields.
*
* @return GridField
*/
public function getFieldEditorGrid()
{
Requirements::javascript(USERFORMS_DIR . '/javascript/FieldEditor.js');
$fields = $this->owner->Fields();
$fields = $this->owner->Fields();
$this->createInitialFormStep(true);
$this->createInitialFormStep(true);
$editableColumns = new GridFieldEditableColumns();
$fieldClasses = singleton('EditableFormField')->getEditableFieldClasses();
$editableColumns->setDisplayFields(array(
'ClassName' => function($record, $column, $grid) use ($fieldClasses) {
if($record instanceof EditableFormField) {
return $record->getInlineClassnameField($column, $fieldClasses);
}
},
'Title' => function($record, $column, $grid) {
if($record instanceof EditableFormField) {
return $record->getInlineTitleField($column);
}
}
));
$editableColumns = new GridFieldEditableColumns();
$fieldClasses = singleton('EditableFormField')->getEditableFieldClasses();
$editableColumns->setDisplayFields(array(
'ClassName' => function ($record, $column, $grid) use ($fieldClasses) {
if ($record instanceof EditableFormField) {
return $record->getInlineClassnameField($column, $fieldClasses);
}
},
'Title' => function ($record, $column, $grid) {
if ($record instanceof EditableFormField) {
return $record->getInlineTitleField($column);
}
}
));
$config = GridFieldConfig::create()
->addComponents(
$editableColumns,
new GridFieldButtonRow(),
GridFieldAddClassesButton::create('EditableTextField')
->setButtonName(_t('UserFormFieldEditorExtension.ADD_FIELD', 'Add Field'))
->setButtonClass('ss-ui-action-constructive'),
GridFieldAddClassesButton::create('EditableFormStep')
->setButtonName(_t('UserFormFieldEditorExtension.ADD_PAGE_BREAK', 'Add Page Break')),
GridFieldAddClassesButton::create(array('EditableFieldGroup', 'EditableFieldGroupEnd'))
->setButtonName(_t('UserFormFieldEditorExtension.ADD_FIELD_GROUP', 'Add Field Group')),
new GridFieldEditButton(),
new GridFieldDeleteAction(),
new GridFieldToolbarHeader(),
new GridFieldOrderableRows('Sort'),
new GridFieldDetailForm()
);
$config = GridFieldConfig::create()
->addComponents(
$editableColumns,
new GridFieldButtonRow(),
GridFieldAddClassesButton::create('EditableTextField')
->setButtonName(_t('UserFormFieldEditorExtension.ADD_FIELD', 'Add Field'))
->setButtonClass('ss-ui-action-constructive'),
GridFieldAddClassesButton::create('EditableFormStep')
->setButtonName(_t('UserFormFieldEditorExtension.ADD_PAGE_BREAK', 'Add Page Break')),
GridFieldAddClassesButton::create(array('EditableFieldGroup', 'EditableFieldGroupEnd'))
->setButtonName(_t('UserFormFieldEditorExtension.ADD_FIELD_GROUP', 'Add Field Group')),
new GridFieldEditButton(),
new GridFieldDeleteAction(),
new GridFieldToolbarHeader(),
new GridFieldOrderableRows('Sort'),
new GridFieldDetailForm()
);
$fieldEditor = GridField::create(
'Fields',
_t('UserDefinedForm.FIELDS', 'Fields'),
$fields,
$config
)->addExtraClass('uf-field-editor');
$fieldEditor = GridField::create(
'Fields',
_t('UserDefinedForm.FIELDS', 'Fields'),
$fields,
$config
)->addExtraClass('uf-field-editor');
return $fieldEditor;
}
return $fieldEditor;
}
/**
* A UserForm must have at least one step.
* If no steps exist, create an initial step, and put all fields inside it.
*
* @param bool $force
* @return void
*/
public function createInitialFormStep($force = false) {
// Only invoke once saved
if(!$this->owner->exists()) {
return;
}
/**
* A UserForm must have at least one step.
* If no steps exist, create an initial step, and put all fields inside it.
*
* @param bool $force
* @return void
*/
public function createInitialFormStep($force = false)
{
// Only invoke once saved
if (!$this->owner->exists()) {
return;
}
// Check if first field is a step
$fields = $this->owner->Fields();
$firstField = $fields->first();
if($firstField instanceof EditableFormStep) {
return;
}
// Check if first field is a step
$fields = $this->owner->Fields();
$firstField = $fields->first();
if ($firstField instanceof EditableFormStep) {
return;
}
// Don't create steps on write if there are no formfields, as this
// can create duplicate first steps during publish of new records
if(!$force && !$firstField) {
return;
}
// Don't create steps on write if there are no formfields, as this
// can create duplicate first steps during publish of new records
if (!$force && !$firstField) {
return;
}
// Re-apply sort to each field starting at 2
$next = 2;
foreach($fields as $field) {
$field->Sort = $next++;
$field->write();
}
// Re-apply sort to each field starting at 2
$next = 2;
foreach ($fields as $field) {
$field->Sort = $next++;
$field->write();
}
// Add step
$step = EditableFormStep::create();
$step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Page');
$step->Sort = 1;
$step->write();
$fields->add($step);
}
// Add step
$step = EditableFormStep::create();
$step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Page');
$step->Sort = 1;
$step->write();
$fields->add($step);
}
/**
* Ensure that at least one page exists at the start
*/
public function onAfterWrite() {
$this->createInitialFormStep();
}
/**
* Ensure that at least one page exists at the start
*/
public function onAfterWrite()
{
$this->createInitialFormStep();
}
/**
* @see SiteTree::doPublish
* @param Page $original
*
* @return void
*/
public function onAfterPublish($original) {
// Remove fields on the live table which could have been orphaned.
$live = Versioned::get_by_stage("EditableFormField", "Live")
->filter('ParentID', $original->ID);
/**
* @see SiteTree::doPublish
* @param Page $original
*
* @return void
*/
public function onAfterPublish($original)
{
// Remove fields on the live table which could have been orphaned.
$live = Versioned::get_by_stage("EditableFormField", "Live")
->filter('ParentID', $original->ID);
if($live) {
foreach($live as $field) {
$field->doDeleteFromStage('Live');
}
}
if ($live) {
foreach ($live as $field) {
$field->doDeleteFromStage('Live');
}
}
foreach($this->owner->Fields() as $field) {
$field->doPublish('Stage', 'Live');
}
}
foreach ($this->owner->Fields() as $field) {
$field->doPublish('Stage', 'Live');
}
}
/**
* @see SiteTree::doUnpublish
* @param Page $page
*
* @return void
*/
public function onAfterUnpublish($page) {
foreach($page->Fields() as $field) {
$field->doDeleteFromStage('Live');
}
}
/**
* @see SiteTree::doUnpublish
* @param Page $page
*
* @return void
*/
public function onAfterUnpublish($page)
{
foreach ($page->Fields() as $field) {
$field->doDeleteFromStage('Live');
}
}
/**
* @see SiteTree::duplicate
* @param DataObject $newPage
*
* @return DataObject
*/
public function onAfterDuplicate($newPage) {
// List of EditableFieldGroups, where the
// key of the array is the ID of the old end group
$fieldGroups = array();
foreach($this->owner->Fields() as $field) {
$newField = $field->duplicate(false);
$newField->ParentID = $newPage->ID;
$newField->ParentClass = $newPage->ClassName;
$newField->Version = 0;
$newField->write();
/**
* @see SiteTree::duplicate
* @param DataObject $newPage
*
* @return DataObject
*/
public function onAfterDuplicate($newPage)
{
// List of EditableFieldGroups, where the
// key of the array is the ID of the old end group
$fieldGroups = array();
foreach ($this->owner->Fields() as $field) {
$newField = $field->duplicate(false);
$newField->ParentID = $newPage->ID;
$newField->ParentClass = $newPage->ClassName;
$newField->Version = 0;
$newField->write();
// If we encounter a group start, record it for later use
if($field instanceof EditableFieldGroup) {
$fieldGroups[$field->EndID] = $newField;
}
// If we encounter a group start, record it for later use
if ($field instanceof EditableFieldGroup) {
$fieldGroups[$field->EndID] = $newField;
}
// If we encounter an end group, link it back to the group start
if($field instanceof EditableFieldGroupEnd && isset($fieldGroups[$field->ID])) {
$groupStart = $fieldGroups[$field->ID];
$groupStart->EndID = $newField->ID;
$groupStart->write();
}
// If we encounter an end group, link it back to the group start
if ($field instanceof EditableFieldGroupEnd && isset($fieldGroups[$field->ID])) {
$groupStart = $fieldGroups[$field->ID];
$groupStart->EndID = $newField->ID;
$groupStart->write();
}
foreach ($field->DisplayRules() as $customRule) {
$newRule = $customRule->duplicate(false);
$newRule->ParentID = $newField->ID;
$newRule->Version = 0;
$newRule->write();
}
}
foreach ($field->DisplayRules() as $customRule) {
$newRule = $customRule->duplicate(false);
$newRule->ParentID = $newField->ID;
$newRule->Version = 0;
$newRule->write();
}
}
return $newPage;
}
return $newPage;
}
/**
* @see SiteTree::getIsModifiedOnStage
* @param boolean $isModified
*
* @return boolean
*/
public function getIsModifiedOnStage($isModified) {
if(!$isModified) {
foreach($this->owner->Fields() as $field) {
if($field->getIsModifiedOnStage()) {
$isModified = true;
break;
}
}
}
/**
* @see SiteTree::getIsModifiedOnStage
* @param boolean $isModified
*
* @return boolean
*/
public function getIsModifiedOnStage($isModified)
{
if (!$isModified) {
foreach ($this->owner->Fields() as $field) {
if ($field->getIsModifiedOnStage()) {
$isModified = true;
break;
}
}
}
return $isModified;
}
return $isModified;
}
/**
* @see SiteTree::doRevertToLive
* @param Page $page
*
* @return void
*/
public function onAfterRevertToLive($page) {
foreach($page->Fields() as $field) {
$field->publish('Live', 'Stage', false);
$field->writeWithoutVersion();
}
}
/**
* @see SiteTree::doRevertToLive
* @param Page $page
*
* @return void
*/
public function onAfterRevertToLive($page)
{
foreach ($page->Fields() as $field) {
$field->publish('Live', 'Stage', false);
$field->writeWithoutVersion();
}
}
}

View File

@ -1,126 +1,128 @@
<?php
class UserFormValidator extends RequiredFields {
public function php($data) {
if(!parent::php($data)) {
return false;
}
class UserFormValidator extends RequiredFields
{
public function php($data)
{
if (!parent::php($data)) {
return false;
}
// Skip unsaved records
if(empty($data['ID']) || !is_numeric($data['ID'])) {
return true;
}
// Skip unsaved records
if (empty($data['ID']) || !is_numeric($data['ID'])) {
return true;
}
$fields = EditableFormField::get()->filter('ParentID', $data['ID'])->sort('"Sort" ASC');
$fields = EditableFormField::get()->filter('ParentID', $data['ID'])->sort('"Sort" ASC');
// Current nesting
$stack = array();
$conditionalStep = false; // Is the current step conditional?
foreach($fields as $field) {
if($field instanceof EditableFormStep) {
// Page at top level, or after another page is ok
if(empty($stack) || (count($stack) === 1 && $stack[0] instanceof EditableFormStep)) {
$stack = array($field);
$conditionalStep = $field->EffectiveDisplayRules()->count() > 0;
continue;
}
// Current nesting
$stack = array();
$conditionalStep = false; // Is the current step conditional?
foreach ($fields as $field) {
if ($field instanceof EditableFormStep) {
// Page at top level, or after another page is ok
if (empty($stack) || (count($stack) === 1 && $stack[0] instanceof EditableFormStep)) {
$stack = array($field);
$conditionalStep = $field->EffectiveDisplayRules()->count() > 0;
continue;
}
$this->validationError(
'FormFields',
_t(
"UserFormValidator.UNEXPECTED_BREAK",
"Unexpected page break '{name}' inside nested field '{group}'",
array(
'name' => $field->CMSTitle,
'group' => end($stack)->CMSTitle
)
),
'error'
);
return false;
}
$this->validationError(
'FormFields',
_t(
"UserFormValidator.UNEXPECTED_BREAK",
"Unexpected page break '{name}' inside nested field '{group}'",
array(
'name' => $field->CMSTitle,
'group' => end($stack)->CMSTitle
)
),
'error'
);
return false;
}
// Validate no pages
if(empty($stack)) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.NO_PAGE",
"Field '{name}' found before any pages",
array(
'name' => $field->CMSTitle
)
),
'error'
);
return false;
}
// Validate no pages
if (empty($stack)) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.NO_PAGE",
"Field '{name}' found before any pages",
array(
'name' => $field->CMSTitle
)
),
'error'
);
return false;
}
// Nest field group
if($field instanceof EditableFieldGroup) {
$stack[] = $field;
continue;
}
// Nest field group
if ($field instanceof EditableFieldGroup) {
$stack[] = $field;
continue;
}
// Unnest field group
if($field instanceof EditableFieldGroupEnd) {
$top = end($stack);
// Unnest field group
if ($field instanceof EditableFieldGroupEnd) {
$top = end($stack);
// Check that the top is a group at all
if(!$top instanceof EditableFieldGroup) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.UNEXPECTED_GROUP_END",
"'{name}' found without a matching group",
array(
'name' => $field->CMSTitle
)
),
'error'
);
return false;
}
// Check that the top is a group at all
if (!$top instanceof EditableFieldGroup) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.UNEXPECTED_GROUP_END",
"'{name}' found without a matching group",
array(
'name' => $field->CMSTitle
)
),
'error'
);
return false;
}
// Check that the top is the right group
if($top->EndID != $field->ID) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.WRONG_GROUP_END",
"'{name}' found closes the wrong group '{group}'",
array(
'name' => $field->CMSTitle,
'group' => $top->CMSTitle
)
),
'error'
);
return false;
}
// Check that the top is the right group
if ($top->EndID != $field->ID) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.WRONG_GROUP_END",
"'{name}' found closes the wrong group '{group}'",
array(
'name' => $field->CMSTitle,
'group' => $top->CMSTitle
)
),
'error'
);
return false;
}
// Unnest group
array_pop($stack);
}
// Unnest group
array_pop($stack);
}
// Normal field type
if($conditionalStep && $field->Required) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.CONDITIONAL_REQUIRED",
"Required field '{name}' cannot be placed within a conditional page",
array(
'name' => $field->CMSTitle
)
),
'error'
);
return false;
}
}
// Normal field type
if ($conditionalStep && $field->Required) {
$this->validationError(
'FormFields',
_t(
"UserFormValidator.CONDITIONAL_REQUIRED",
"Required field '{name}' cannot be placed within a conditional page",
array(
'name' => $field->CMSTitle
)
),
'error'
);
return false;
}
}
return true;
}
return true;
}
}

View File

@ -3,63 +3,65 @@
/**
* @package userforms
*/
class UserFormsCheckboxSetField extends CheckboxSetField {
class UserFormsCheckboxSetField extends CheckboxSetField
{
/**
* jQuery validate requires that the value of the option does not contain
* the actual value of the input.
*
* @return ArrayList
*/
public function getOptions() {
$options = parent::getOptions();
/**
* jQuery validate requires that the value of the option does not contain
* the actual value of the input.
*
* @return ArrayList
*/
public function getOptions()
{
$options = parent::getOptions();
foreach($options as $option) {
$option->Name = "{$this->name}[]";
}
foreach ($options as $option) {
$option->Name = "{$this->name}[]";
}
return $options;
}
return $options;
}
/**
* @inheritdoc
*
* @return array
*/
public function getSourceAsArray()
{
$array = parent::getSourceAsArray();
/**
* @inheritdoc
*
* @return array
*/
public function getSourceAsArray()
{
$array = parent::getSourceAsArray();
return array_values($array);
}
return array_values($array);
}
/**
* @inheritdoc
*
* @param Validator $validator
*
* @return bool
*/
public function validate($validator)
{
// get the previous values (could contain comma-delimited list)
/**
* @inheritdoc
*
* @param Validator $validator
*
* @return bool
*/
public function validate($validator)
{
// get the previous values (could contain comma-delimited list)
$previous = $value = $this->Value();
$previous = $value = $this->Value();
if (is_string($value) && strstr($value, ",")) {
$value = explode(",", $value);
}
if (is_string($value) && strstr($value, ",")) {
$value = explode(",", $value);
}
// set the value as an array for parent validation
// set the value as an array for parent validation
$this->setValue($value);
$this->setValue($value);
$validated = parent::validate($validator);
$validated = parent::validate($validator);
// restore previous value after validation
// restore previous value after validation
$this->setValue($previous);
$this->setValue($previous);
return $validated;
}
return $validated;
}
}

View File

@ -3,45 +3,49 @@
/**
* Represents a composite field group, which may contain other groups
*/
abstract class UserFormsCompositeField extends CompositeField implements UserFormsFieldContainer {
abstract class UserFormsCompositeField extends CompositeField implements UserFormsFieldContainer
{
/**
* Parent field
*
* @var UserFormsFieldContainer
*/
protected $parent = null;
/**
* Parent field
*
* @var UserFormsFieldContainer
*/
protected $parent = null;
public function getParent() {
return $this->parent;
}
public function getParent()
{
return $this->parent;
}
public function setParent(UserFormsFieldContainer $parent) {
$this->parent = $parent;
return $this;
}
public function setParent(UserFormsFieldContainer $parent)
{
$this->parent = $parent;
return $this;
}
public function processNext(EditableFormField $field) {
// When we find a step, bubble up to the top
if($field instanceof EditableFormStep) {
return $this->getParent()->processNext($field);
}
public function processNext(EditableFormField $field)
{
// When we find a step, bubble up to the top
if ($field instanceof EditableFormStep) {
return $this->getParent()->processNext($field);
}
// Skip over fields that don't generate formfields
$formField = $field->getFormField();
if(!$formField) {
return $this;
}
// Skip over fields that don't generate formfields
$formField = $field->getFormField();
if (!$formField) {
return $this;
}
// Save this field
$this->push($formField);
// Save this field
$this->push($formField);
// Nest fields that are containers
if($formField instanceof UserFormsFieldContainer) {
return $formField->setParent($this);
}
// Nest fields that are containers
if ($formField instanceof UserFormsFieldContainer) {
return $formField->setParent($this);
}
// Add any subsequent fields to this
return $this;
}
// Add any subsequent fields to this
return $this;
}
}

View File

@ -3,28 +3,29 @@
/**
* Represents a field container which can iteratively process nested fields, converting it into a fieldset
*/
interface UserFormsFieldContainer {
interface UserFormsFieldContainer
{
/**
* Process the next field in the list, returning the container to add the next field to.
*
* @param EditableFormField $field
* @return EditableContainerField
*/
public function processNext(EditableFormField $field);
/**
* Process the next field in the list, returning the container to add the next field to.
*
* @param EditableFormField $field
* @return EditableContainerField
*/
public function processNext(EditableFormField $field);
/**
* Set the parent
*
* @param UserFormsFieldContainer $parent
* @return $this
*/
public function setParent(UserFormsFieldContainer $parent);
/**
* Set the parent
*
* @param UserFormsFieldContainer $parent
* @return $this
*/
public function setParent(UserFormsFieldContainer $parent);
/**
* Get the parent
*
* @return UserFormsFieldContainer
*/
public function getParent();
/**
* Get the parent
*
* @return UserFormsFieldContainer
*/
public function getParent();
}

View File

@ -3,41 +3,45 @@
/**
* A list of formfields which allows for iterative processing of nested composite fields
*/
class UserFormsFieldList extends FieldList implements UserFormsFieldContainer {
class UserFormsFieldList extends FieldList implements UserFormsFieldContainer
{
public function processNext(EditableFormField $field) {
$formField = $field->getFormField();
if(!$formField) {
return $this;
}
public function processNext(EditableFormField $field)
{
$formField = $field->getFormField();
if (!$formField) {
return $this;
}
$this->push($formField);
$this->push($formField);
if($formField instanceof UserFormsFieldContainer) {
return $formField->setParent($this);
}
if ($formField instanceof UserFormsFieldContainer) {
return $formField->setParent($this);
}
return $this;
}
return $this;
}
public function getParent() {
// Field list does not have a parent
return null;
}
public function getParent()
{
// Field list does not have a parent
return null;
}
public function setParent(UserFormsFieldContainer $parent) {
return $this;
}
/**
* Remove all empty steps
*/
public function clearEmptySteps() {
foreach($this as $field) {
if($field instanceof UserFormsStepField && count($field->getChildren()) === 0) {
$this->remove($field);
}
}
}
public function setParent(UserFormsFieldContainer $parent)
{
return $this;
}
/**
* Remove all empty steps
*/
public function clearEmptySteps()
{
foreach ($this as $field) {
if ($field instanceof UserFormsStepField && count($field->getChildren()) === 0) {
$this->remove($field);
}
}
}
}

View File

@ -3,25 +3,29 @@
/**
* Front end composite field for userforms
*/
class UserFormsGroupField extends UserFormsCompositeField {
class UserFormsGroupField extends UserFormsCompositeField
{
public function __construct($children = null) {
parent::__construct($children);
$this->setTag('fieldset');
}
public function __construct($children = null)
{
parent::__construct($children);
$this->setTag('fieldset');
}
public function getLegend() {
// Legend defaults to title
return parent::getLegend() ?: $this->Title();
}
public function getLegend()
{
// Legend defaults to title
return parent::getLegend() ?: $this->Title();
}
public function processNext(EditableFormField $field) {
// When ending a group, jump up one level
if($field instanceof EditableFieldGroupEnd) {
return $this->getParent();
}
public function processNext(EditableFormField $field)
{
// When ending a group, jump up one level
if ($field instanceof EditableFieldGroupEnd) {
return $this->getParent();
}
// Otherwise behave as per normal composite field
return parent::processNext($field);
}
// Otherwise behave as per normal composite field
return parent::processNext($field);
}
}

View File

@ -3,42 +3,46 @@
/**
* Represents a page step in a form, which may contain form fields or other groups
*/
class UserFormsStepField extends UserFormsCompositeField {
class UserFormsStepField extends UserFormsCompositeField
{
private static $casting = array(
'StepNumber' => 'Int'
);
private static $casting = array(
'StepNumber' => 'Int'
);
/**
* Numeric index (1 based) of this step
*
* Null if unassigned
*
* @var int|null
*/
protected $number = null;
/**
* Numeric index (1 based) of this step
*
* Null if unassigned
*
* @var int|null
*/
protected $number = null;
public function FieldHolder($properties = array()) {
return $this->Field($properties);
}
public function FieldHolder($properties = array())
{
return $this->Field($properties);
}
/**
* Get the step number
*
* @return int|null
*/
public function getStepNumber() {
return $this->number;
}
/**
* Get the step number
*
* @return int|null
*/
public function getStepNumber()
{
return $this->number;
}
/**
* Re-assign this step to another number
*
* @param type $number
* @return $this
*/
public function setStepNumber($number) {
$this->number = $number;
return $this;
}
/**
* Re-assign this step to another number
*
* @param type $number
* @return $this
*/
public function setStepNumber($number)
{
$this->number = $number;
return $this;
}
}

View File

@ -7,11 +7,13 @@
* @deprecated since version 4.0
* @package userforms
*/
class UserformsTreeDropdownField extends TreeDropdownField {
class UserformsTreeDropdownField extends TreeDropdownField
{
public function __construct($name, $title = null, $sourceObject = 'Group', $keyField = 'ID', $labelField = 'TreeTitle', $showSearch = true) {
parent::__construct($name, $title, $sourceObject, $keyField, $labelField, $showSearch);
public function __construct($name, $title = null, $sourceObject = 'Group', $keyField = 'ID', $labelField = 'TreeTitle', $showSearch = true)
{
parent::__construct($name, $title, $sourceObject, $keyField, $labelField, $showSearch);
Deprecation::notice('4.0', __CLASS__ . " is deprecated");
}
}
Deprecation::notice('4.0', __CLASS__ . " is deprecated");
}
}

View File

@ -3,230 +3,246 @@
/**
* A button which allows objects to be created with a specified classname(s)
*/
class GridFieldAddClassesButton extends Object implements GridField_HTMLProvider, GridField_ActionProvider {
class GridFieldAddClassesButton extends Object implements GridField_HTMLProvider, GridField_ActionProvider
{
/**
* Name of fragment to insert into
*
* @var string
*/
protected $targetFragment;
/**
* Name of fragment to insert into
*
* @var string
*/
protected $targetFragment;
/**
* Button title
*
* @var string
*/
protected $buttonName;
/**
* Button title
*
* @var string
*/
protected $buttonName;
/**
* Additonal CSS classes for the button
*
* @var string
*/
protected $buttonClass = null;
/**
* Additonal CSS classes for the button
*
* @var string
*/
protected $buttonClass = null;
/**
* Class names
*
* @var array
*/
protected $modelClasses = null;
/**
* Class names
*
* @var array
*/
protected $modelClasses = null;
/**
* @param array $classes Class or list of classes to create.
* If you enter more than one class, each click of the "add" button will create one of each
* @param string $targetFragment The fragment to render the button into
*/
public function __construct($classes, $targetFragment = 'buttons-before-left') {
parent::__construct();
$this->setClasses($classes);
$this->setFragment($targetFragment);
}
/**
* @param array $classes Class or list of classes to create.
* If you enter more than one class, each click of the "add" button will create one of each
* @param string $targetFragment The fragment to render the button into
*/
public function __construct($classes, $targetFragment = 'buttons-before-left')
{
parent::__construct();
$this->setClasses($classes);
$this->setFragment($targetFragment);
}
/**
* Change the button name
*
* @param string $name
* @return $this
*/
public function setButtonName($name) {
$this->buttonName = $name;
return $this;
}
/**
* Change the button name
*
* @param string $name
* @return $this
*/
public function setButtonName($name)
{
$this->buttonName = $name;
return $this;
}
/**
* Get the button name
*
* @return string
*/
public function getButtonName() {
return $this->buttonName;
}
/**
* Get the button name
*
* @return string
*/
public function getButtonName()
{
return $this->buttonName;
}
/**
* Gets the fragment name this button is rendered into.
*
* @return string
*/
public function getFragment() {
return $this->targetFragment;
}
/**
* Gets the fragment name this button is rendered into.
*
* @return string
*/
public function getFragment()
{
return $this->targetFragment;
}
/**
* Sets the fragment name this button is rendered into.
*
* @param string $fragment
* @return GridFieldAddNewInlineButton $this
*/
public function setFragment($fragment) {
$this->targetFragment = $fragment;
return $this;
}
/**
* Sets the fragment name this button is rendered into.
*
* @param string $fragment
* @return GridFieldAddNewInlineButton $this
*/
public function setFragment($fragment)
{
$this->targetFragment = $fragment;
return $this;
}
/**
* Get extra button class
*
* @return string
*/
public function getButtonClass() {
return $this->buttonClass;
}
/**
* Get extra button class
*
* @return string
*/
public function getButtonClass()
{
return $this->buttonClass;
}
/**
* Sets extra CSS classes for this button
*
* @param string $buttonClass
* @return $this
*/
public function setButtonClass($buttonClass) {
$this->buttonClass = $buttonClass;
return $this;
}
/**
* Sets extra CSS classes for this button
*
* @param string $buttonClass
* @return $this
*/
public function setButtonClass($buttonClass)
{
$this->buttonClass = $buttonClass;
return $this;
}
/**
* Get the classes of the objects to create
*
* @return array
*/
public function getClasses() {
return $this->modelClasses;
}
/**
* Get the classes of the objects to create
*
* @return array
*/
public function getClasses()
{
return $this->modelClasses;
}
/**
* Gets the list of classes which can be created, with checks for permissions.
* Will fallback to the default model class for the given DataGrid
*
* @param DataGrid $grid
* @return array
*/
public function getClassesCreate($grid) {
// Get explicit or fallback class list
$classes = $this->getClasses();
if(empty($classes) && $grid) {
$classes = array($grid->getModelClass());
}
/**
* Gets the list of classes which can be created, with checks for permissions.
* Will fallback to the default model class for the given DataGrid
*
* @param DataGrid $grid
* @return array
*/
public function getClassesCreate($grid)
{
// Get explicit or fallback class list
$classes = $this->getClasses();
if (empty($classes) && $grid) {
$classes = array($grid->getModelClass());
}
// Filter out classes without permission
return array_filter($classes, function($class) {
return singleton($class)->canCreate();
});
}
// Filter out classes without permission
return array_filter($classes, function ($class) {
return singleton($class)->canCreate();
});
}
/**
* Specify the classes to create
*
* @param array $classes
*/
public function setClasses($classes) {
if(!is_array($classes)) {
$classes = $classes ? array($classes) : array();
}
$this->modelClasses = $classes;
}
/**
* Specify the classes to create
*
* @param array $classes
*/
public function setClasses($classes)
{
if (!is_array($classes)) {
$classes = $classes ? array($classes) : array();
}
$this->modelClasses = $classes;
}
public function getHTMLFragments($grid) {
// Check create permission
$singleton = singleton($grid->getModelClass());
if(!$singleton->canCreate()) {
return array();
}
public function getHTMLFragments($grid)
{
// Check create permission
$singleton = singleton($grid->getModelClass());
if (!$singleton->canCreate()) {
return array();
}
// Get button name
$buttonName = $this->getButtonName();
if(!$buttonName) {
// provide a default button name, can be changed by calling {@link setButtonName()} on this component
$objectName = $singleton->i18n_singular_name();
$buttonName = _t('GridField.Add', 'Add {name}', array('name' => $objectName));
}
// Get button name
$buttonName = $this->getButtonName();
if (!$buttonName) {
// provide a default button name, can be changed by calling {@link setButtonName()} on this component
$objectName = $singleton->i18n_singular_name();
$buttonName = _t('GridField.Add', 'Add {name}', array('name' => $objectName));
}
$addAction = new GridField_FormAction(
$grid,
$this->getAction(),
$buttonName,
$this->getAction(),
array()
);
$addAction->setAttribute('data-icon', 'add');
$addAction = new GridField_FormAction(
$grid,
$this->getAction(),
$buttonName,
$this->getAction(),
array()
);
$addAction->setAttribute('data-icon', 'add');
if($this->getButtonClass()) {
$addAction->addExtraClass($this->getButtonClass());
}
if ($this->getButtonClass()) {
$addAction->addExtraClass($this->getButtonClass());
}
return array(
$this->targetFragment => $addAction->forTemplate()
);
}
return array(
$this->targetFragment => $addAction->forTemplate()
);
}
/**
* {@inheritDoc}
*/
public function getActions($gridField) {
return array(
$this->getAction()
);
}
/**
* {@inheritDoc}
*/
public function getActions($gridField)
{
return array(
$this->getAction()
);
}
/**
* Get the action suburl for this component
*
* @return string
*/
protected function getAction() {
return 'add-classes-' . strtolower(implode('-', $this->getClasses()));
}
/**
* Get the action suburl for this component
*
* @return string
*/
protected function getAction()
{
return 'add-classes-' . strtolower(implode('-', $this->getClasses()));
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
switch(strtolower($actionName)) {
case $this->getAction():
return $this->handleAdd($gridField);
default:
return null;
}
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
{
switch (strtolower($actionName)) {
case $this->getAction():
return $this->handleAdd($gridField);
default:
return null;
}
}
/**
* Handles adding a new instance of a selected class.
*
* @param GridField $grid
* @return null
*/
public function handleAdd($grid) {
$classes = $this->getClassesCreate($grid);
if(empty($classes)) {
throw new SS_HTTPResponse_Exception(400);
}
/**
* Handles adding a new instance of a selected class.
*
* @param GridField $grid
* @return null
*/
public function handleAdd($grid)
{
$classes = $this->getClassesCreate($grid);
if (empty($classes)) {
throw new SS_HTTPResponse_Exception(400);
}
// Add item to gridfield
$list = $grid->getList();
foreach($classes as $class) {
$item = $class::create();
$item->write();
$list->add($item);
}
// Add item to gridfield
$list = $grid->getList();
foreach ($classes as $class) {
$item = $class::create();
$item->write();
$list->add($item);
}
// Should trigger a simple reload
return null;
}
// Should trigger a simple reload
return null;
}
}

View File

@ -3,167 +3,175 @@
/**
* @package userforms
*/
class UserForm extends Form {
class UserForm extends Form
{
/**
* @param Controller $controller
* @param string $name
*/
public function __construct(Controller $controller, $name = 'Form') {
/**
* @param Controller $controller
* @param string $name
*/
public function __construct(Controller $controller, $name = 'Form')
{
$this->controller = $controller;
$this->setRedirectToFormOnValidationError(true);
$this->controller = $controller;
$this->setRedirectToFormOnValidationError(true);
parent::__construct(
$controller,
$name,
new FieldList(),
new FieldList()
);
parent::__construct(
$controller,
$name,
new FieldList(),
new FieldList()
);
$this->setFields($fields = $this->getFormFields());
$fields->setForm($this);
$this->setActions($actions = $this->getFormActions());
$actions->setForm($this);
$this->setValidator($this->getRequiredFields());
$this->setFields($fields = $this->getFormFields());
$fields->setForm($this);
$this->setActions($actions = $this->getFormActions());
$actions->setForm($this);
$this->setValidator($this->getRequiredFields());
// This needs to be re-evaluated since fields have been assigned
$this->setupFormErrors();
// This needs to be re-evaluated since fields have been assigned
$this->setupFormErrors();
// Number each page
$stepNumber = 1;
foreach ($this->getSteps() as $step) {
$step->setStepNumber($stepNumber++);
}
// Number each page
$stepNumber = 1;
foreach($this->getSteps() as $step) {
$step->setStepNumber($stepNumber++);
}
if ($controller->DisableCsrfSecurityToken) {
$this->disableSecurityToken();
}
if($controller->DisableCsrfSecurityToken) {
$this->disableSecurityToken();
}
$data = Session::get("FormInfo.{$this->FormName()}.data");
$data = Session::get("FormInfo.{$this->FormName()}.data");
if (is_array($data)) {
$this->loadDataFrom($data);
}
if(is_array($data)) {
$this->loadDataFrom($data);
}
$this->extend('updateForm');
}
$this->extend('updateForm');
}
public function setupFormErrors()
{
// Suppress setupFormErrors if fields haven't been bootstrapped
if ($this->fields && $this->fields->exists()) {
return parent::setupFormErrors();
}
public function setupFormErrors()
{
// Suppress setupFormErrors if fields haven't been bootstrapped
if($this->fields && $this->fields->exists()) {
return parent::setupFormErrors();
}
return $this;
}
return $this;
}
/**
* Used for partial caching in the template.
*
* @return string
*/
public function getLastEdited()
{
return $this->controller->LastEdited;
}
/**
* Used for partial caching in the template.
*
* @return string
*/
public function getLastEdited() {
return $this->controller->LastEdited;
}
/**
* @return bool
*/
public function getDisplayErrorMessagesAtTop()
{
return (bool)$this->controller->DisplayErrorMessagesAtTop;
}
/**
* @return bool
*/
public function getDisplayErrorMessagesAtTop() {
return (bool)$this->controller->DisplayErrorMessagesAtTop;
}
/**
* Return the fieldlist, filtered to only contain steps
*
* @return ArrayList
*/
public function getSteps()
{
return $this->Fields()->filterByCallback(function ($field) {
return $field instanceof UserFormsStepField;
});
}
/**
* Return the fieldlist, filtered to only contain steps
*
* @return ArrayList
*/
public function getSteps() {
return $this->Fields()->filterByCallback(function($field) {
return $field instanceof UserFormsStepField;
});
}
/**
* Get the form fields for the form on this page. Can modify this FieldSet
* by using {@link updateFormFields()} on an {@link Extension} subclass which
* is applied to this controller.
*
* This will be a list of top level composite steps
*
* @return FieldList
*/
public function getFormFields()
{
$fields = new UserFormsFieldList();
$target = $fields;
foreach ($this->controller->Fields() as $field) {
$target = $target->processNext($field);
}
$fields->clearEmptySteps();
$this->extend('updateFormFields', $fields);
$fields->setForm($this);
return $fields;
}
/**
* Get the form fields for the form on this page. Can modify this FieldSet
* by using {@link updateFormFields()} on an {@link Extension} subclass which
* is applied to this controller.
*
* This will be a list of top level composite steps
*
* @return FieldList
*/
public function getFormFields() {
$fields = new UserFormsFieldList();
$target = $fields;
foreach ($this->controller->Fields() as $field) {
$target = $target->processNext($field);
}
$fields->clearEmptySteps();
$this->extend('updateFormFields', $fields);
$fields->setForm($this);
return $fields;
}
/**
* Generate the form actions for the UserDefinedForm. You
* can manipulate these by using {@link updateFormActions()} on
* a decorator.
*
* @todo Make form actions editable via their own field editor.
*
* @return FieldList
*/
public function getFormActions()
{
$submitText = ($this->controller->SubmitButtonText) ? $this->controller->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
$clearText = ($this->controller->ClearButtonText) ? $this->controller->ClearButtonText : _t('UserDefinedForm.CLEARBUTTON', 'Clear');
/**
* Generate the form actions for the UserDefinedForm. You
* can manipulate these by using {@link updateFormActions()} on
* a decorator.
*
* @todo Make form actions editable via their own field editor.
*
* @return FieldList
*/
public function getFormActions() {
$submitText = ($this->controller->SubmitButtonText) ? $this->controller->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
$clearText = ($this->controller->ClearButtonText) ? $this->controller->ClearButtonText : _t('UserDefinedForm.CLEARBUTTON', 'Clear');
$actions = new FieldList(
new FormAction("process", $submitText)
);
$actions = new FieldList(
new FormAction("process", $submitText)
);
if ($this->controller->ShowClearButton) {
$actions->push(new ResetFormAction("clearForm", $clearText));
}
if($this->controller->ShowClearButton) {
$actions->push(new ResetFormAction("clearForm", $clearText));
}
$this->extend('updateFormActions', $actions);
$actions->setForm($this);
return $actions;
}
$this->extend('updateFormActions', $actions);
$actions->setForm($this);
return $actions;
}
/**
* Get the required form fields for this form.
*
* @return RequiredFields
*/
public function getRequiredFields()
{
// Generate required field validator
$requiredNames = $this
->getController()
->Fields()
->filter('Required', true)
->column('Name');
$required = new RequiredFields($requiredNames);
$this->extend('updateRequiredFields', $required);
$required->setForm($this);
return $required;
}
/**
* Get the required form fields for this form.
*
* @return RequiredFields
*/
public function getRequiredFields() {
// Generate required field validator
$requiredNames = $this
->getController()
->Fields()
->filter('Required', true)
->column('Name');
$required = new RequiredFields($requiredNames);
$this->extend('updateRequiredFields', $required);
$required->setForm($this);
return $required;
}
/**
* Override some we can add UserForm specific attributes to the form.
*
* @return array
*/
public function getAttributes()
{
$attrs = parent::getAttributes();
/**
* Override some we can add UserForm specific attributes to the form.
*
* @return array
*/
public function getAttributes() {
$attrs = parent::getAttributes();
$attrs['class'] = $attrs['class'] . ' userform';
$attrs['data-livevalidation'] = (bool)$this->controller->EnableLiveValidation;
$attrs['data-toperrors'] = (bool)$this->controller->DisplayErrorMessagesAtTop;
$attrs['data-hidefieldlabels'] = (bool)$this->controller->HideFieldLabels;
$attrs['class'] = $attrs['class'] . ' userform';
$attrs['data-livevalidation'] = (bool)$this->controller->EnableLiveValidation;
$attrs['data-toperrors'] = (bool)$this->controller->DisplayErrorMessagesAtTop;
$attrs['data-hidefieldlabels'] = (bool)$this->controller->HideFieldLabels;
return $attrs;
}
return $attrs;
}
}

View File

@ -7,100 +7,107 @@
* @method EditableFormField Parent()
* @package userforms
*/
class EditableCustomRule extends DataObject {
class EditableCustomRule extends DataObject
{
private static $condition_options = array(
"IsBlank" => "Is blank",
"IsNotBlank" => "Is not blank",
"HasValue" => "Equals",
"ValueNot" => "Doesn't equal",
"ValueLessThan" => "Less than",
"ValueLessThanEqual" => "Less than or equal",
"ValueGreaterThan" => "Greater than",
"ValueGreaterThanEqual" => "Greater than or equal"
);
private static $condition_options = array(
"IsBlank" => "Is blank",
"IsNotBlank" => "Is not blank",
"HasValue" => "Equals",
"ValueNot" => "Doesn't equal",
"ValueLessThan" => "Less than",
"ValueLessThanEqual" => "Less than or equal",
"ValueGreaterThan" => "Greater than",
"ValueGreaterThanEqual" => "Greater than or equal"
);
private static $db = array(
'Display' => 'Enum("Show,Hide")',
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,HasValue,ValueNot,ValueLessThan,ValueLessThanEqual,ValueGreaterThan,ValueGreaterThanEqual")',
'FieldValue' => 'Varchar(255)'
);
private static $db = array(
'Display' => 'Enum("Show,Hide")',
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,HasValue,ValueNot,ValueLessThan,ValueLessThanEqual,ValueGreaterThan,ValueGreaterThanEqual")',
'FieldValue' => 'Varchar(255)'
);
private static $has_one = array(
'Parent' => 'EditableFormField',
'ConditionField' => 'EditableFormField'
);
private static $has_one = array(
'Parent' => 'EditableFormField',
'ConditionField' => 'EditableFormField'
);
/**
* Built in extensions required
*
* @config
* @var array
*/
private static $extensions = array(
"Versioned('Stage', 'Live')"
);
/**
* Built in extensions required
*
* @config
* @var array
*/
private static $extensions = array(
"Versioned('Stage', 'Live')"
);
/**
* Publish this custom rule to the live site
*
* Wrapper for the {@link Versioned} publish function
*/
public function doPublish($fromStage, $toStage, $createNewVersion = false) {
$this->publish($fromStage, $toStage, $createNewVersion);
}
/**
* Publish this custom rule 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 custom rule from a given stage
*
* Wrapper for the {@link Versioned} deleteFromStage function
*/
public function doDeleteFromStage($stage) {
$this->deleteFromStage($stage);
}
/**
* Delete this custom rule from a given stage
*
* Wrapper for the {@link Versioned} deleteFromStage function
*/
public function doDeleteFromStage($stage)
{
$this->deleteFromStage($stage);
}
/**
* @param Member $member
* @return bool
*/
public function canDelete($member = null) {
return $this->canEdit($member);
}
public function canDelete($member = null)
{
return $this->canEdit($member);
}
/**
* @param Member $member
* @return bool
*/
public function canEdit($member = null) {
public function canEdit($member = null)
{
return $this->Parent()->canEdit($member);
}
}
/**
* @param Member $member
* @return bool
*/
public function canView($member = null) {
return $this->Parent()->canView($member);
}
public function canView($member = null)
{
return $this->Parent()->canView($member);
}
/**
* Return whether a user can create an object of this type
*
/**
* Return whether a user can create an object of this type
*
* @param Member $member
* @param array $context Virtual parameter to allow context to be passed in to check
* @return bool
*/
public function canCreate($member = null) {
// Check parent page
* @return bool
*/
public function canCreate($member = null)
{
// Check parent page
$parent = $this->getCanCreateContext(func_get_args());
if($parent) {
if ($parent) {
return $parent->canEdit($member);
}
// Fall back to secure admin permissions
return parent::canCreate($member);
}
}
/**
* Helper method to check the parent for this object
@ -108,13 +115,14 @@ class EditableCustomRule extends DataObject {
* @param array $args List of arguments passed to canCreate
* @return DataObject Some parent dataobject to inherit permissions from
*/
protected function getCanCreateContext($args) {
protected function getCanCreateContext($args)
{
// Inspect second parameter to canCreate for a 'Parent' context
if(isset($args[1]['Parent'])) {
if (isset($args[1]['Parent'])) {
return $args[1]['Parent'];
}
// Hack in currently edited page if context is missing
if(Controller::has_curr() && Controller::curr() instanceof CMSMain) {
if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
return Controller::curr()->currentPage();
}
@ -126,7 +134,8 @@ class EditableCustomRule extends DataObject {
* @param Member $member
* @return bool
*/
public function canPublish($member = null) {
public function canPublish($member = null)
{
return $this->canEdit($member);
}
@ -134,7 +143,8 @@ class EditableCustomRule extends DataObject {
* @param Member $member
* @return bool
*/
public function canUnpublish($member = null) {
public function canUnpublish($member = null)
{
return $this->canDelete($member);
}
}

View File

@ -4,178 +4,180 @@
* @package userforms
*/
class UserDefinedForm extends Page {
class UserDefinedForm extends Page
{
/**
* @var string
*/
private static $icon = 'userforms/images/sitetree_icon.png';
/**
* @var string
*/
private static $icon = 'userforms/images/sitetree_icon.png';
/**
* @var string
*/
private static $description = 'Adds a customizable form.';
/**
* @var string
*/
private static $description = 'Adds a customizable form.';
/**
* @var string Required Identifier
*/
private static $required_identifier = null;
/**
* @var string Required Identifier
*/
private static $required_identifier = null;
/**
* @var string
*/
private static $email_template_directory = 'userforms/templates/email/';
/**
* @var string
*/
private static $email_template_directory = 'userforms/templates/email/';
/**
* Should this module automatically upgrade on dev/build?
*
* @config
* @var bool
*/
private static $upgrade_on_build = true;
/**
* Built in extensions required by this page
* @config
* @var array
*/
private static $extensions = array(
'UserFormFieldEditorExtension'
);
/**
* @var array Fields on the user defined form page.
*/
private static $db = array(
"SubmitButtonText" => "Varchar",
"ClearButtonText" => "Varchar",
"OnCompleteMessage" => "HTMLText",
"ShowClearButton" => "Boolean",
'DisableSaveSubmissions' => 'Boolean',
'EnableLiveValidation' => 'Boolean',
'HideFieldLabels' => 'Boolean',
'DisplayErrorMessagesAtTop' => 'Boolean',
'DisableAuthenicatedFinishAction' => 'Boolean',
'DisableCsrfSecurityToken' => 'Boolean'
);
/**
* @var array Default values of variables when this page is created
*/
private static $defaults = array(
'Content' => '$UserDefinedForm',
'DisableSaveSubmissions' => 0,
'OnCompleteMessage' => '<p>Thanks, we\'ve received your submission.</p>'
);
/**
* @var array
*/
private static $has_many = array(
"Submissions" => "SubmittedForm",
"EmailRecipients" => "UserDefinedForm_EmailRecipient"
);
/**
* @var array
* @config
*/
private static $casting = array(
'ErrorContainerID' => 'Text'
);
/**
* Error container selector which matches the element for grouped messages
*
* @var string
* @config
*/
private static $error_container_id = 'error-container';
/**
* The configuration used to determine whether a confirmation message is to
* appear when navigating away from a partially completed form.
*
* @var boolean
* @config
*/
private static $enable_are_you_sure = true;
/**
* @var bool
/**
* Should this module automatically upgrade on dev/build?
*
* @config
*/
private static $recipients_warning_enabled = false;
* @var bool
*/
private static $upgrade_on_build = true;
/**
* Temporary storage of field ids when the form is duplicated.
* Example layout: array('EditableCheckbox3' => 'EditableCheckbox14')
* @var array
*/
protected $fieldsFromTo = array();
/**
* Built in extensions required by this page
* @config
* @var array
*/
private static $extensions = array(
'UserFormFieldEditorExtension'
);
/**
* @return FieldList
*/
public function getCMSFields() {
Requirements::css(USERFORMS_DIR . '/css/UserForm_cms.css');
/**
* @var array Fields on the user defined form page.
*/
private static $db = array(
"SubmitButtonText" => "Varchar",
"ClearButtonText" => "Varchar",
"OnCompleteMessage" => "HTMLText",
"ShowClearButton" => "Boolean",
'DisableSaveSubmissions' => 'Boolean',
'EnableLiveValidation' => 'Boolean',
'HideFieldLabels' => 'Boolean',
'DisplayErrorMessagesAtTop' => 'Boolean',
'DisableAuthenicatedFinishAction' => 'Boolean',
'DisableCsrfSecurityToken' => 'Boolean'
);
$self = $this;
/**
* @var array Default values of variables when this page is created
*/
private static $defaults = array(
'Content' => '$UserDefinedForm',
'DisableSaveSubmissions' => 0,
'OnCompleteMessage' => '<p>Thanks, we\'ve received your submission.</p>'
);
$this->beforeUpdateCMSFields(function($fields) use ($self) {
/**
* @var array
*/
private static $has_many = array(
"Submissions" => "SubmittedForm",
"EmailRecipients" => "UserDefinedForm_EmailRecipient"
);
// define tabs
$fields->findOrMakeTab('Root.FormOptions', _t('UserDefinedForm.CONFIGURATION', 'Configuration'));
$fields->findOrMakeTab('Root.Recipients', _t('UserDefinedForm.RECIPIENTS', 'Recipients'));
$fields->findOrMakeTab('Root.Submissions', _t('UserDefinedForm.SUBMISSIONS', 'Submissions'));
/**
* @var array
* @config
*/
private static $casting = array(
'ErrorContainerID' => 'Text'
);
// text to show on complete
$onCompleteFieldSet = new CompositeField(
$label = new LabelField('OnCompleteMessageLabel',_t('UserDefinedForm.ONCOMPLETELABEL', 'Show on completion')),
$editor = new HtmlEditorField( 'OnCompleteMessage', '', _t('UserDefinedForm.ONCOMPLETEMESSAGE', $self->OnCompleteMessage))
);
/**
* Error container selector which matches the element for grouped messages
*
* @var string
* @config
*/
private static $error_container_id = 'error-container';
$onCompleteFieldSet->addExtraClass('field');
/**
* The configuration used to determine whether a confirmation message is to
* appear when navigating away from a partially completed form.
*
* @var boolean
* @config
*/
private static $enable_are_you_sure = true;
$editor->setRows(3);
$label->addExtraClass('left');
/**
* @var bool
* @config
*/
private static $recipients_warning_enabled = false;
// Define config for email recipients
$emailRecipientsConfig = GridFieldConfig_RecordEditor::create(10);
$emailRecipientsConfig->getComponentByType('GridFieldAddNewButton')
->setButtonName(
_t('UserDefinedForm.ADDEMAILRECIPIENT', 'Add Email Recipient')
);
/**
* Temporary storage of field ids when the form is duplicated.
* Example layout: array('EditableCheckbox3' => 'EditableCheckbox14')
* @var array
*/
protected $fieldsFromTo = array();
// who do we email on submission
$emailRecipients = new GridField(
'EmailRecipients',
_t('UserDefinedForm.EMAILRECIPIENTS', 'Email Recipients'),
$self->EmailRecipients(),
$emailRecipientsConfig
);
$emailRecipients
->getConfig()
->getComponentByType('GridFieldDetailForm')
->setItemRequestClass('UserFormRecipientItemRequest');
/**
* @return FieldList
*/
public function getCMSFields()
{
Requirements::css(USERFORMS_DIR . '/css/UserForm_cms.css');
$fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet);
$fields->addFieldToTab('Root.Recipients', $emailRecipients);
$fields->addFieldsToTab('Root.FormOptions', $self->getFormOptions());
$self = $this;
$this->beforeUpdateCMSFields(function ($fields) use ($self) {
// define tabs
$fields->findOrMakeTab('Root.FormOptions', _t('UserDefinedForm.CONFIGURATION', 'Configuration'));
$fields->findOrMakeTab('Root.Recipients', _t('UserDefinedForm.RECIPIENTS', 'Recipients'));
$fields->findOrMakeTab('Root.Submissions', _t('UserDefinedForm.SUBMISSIONS', 'Submissions'));
// text to show on complete
$onCompleteFieldSet = new CompositeField(
$label = new LabelField('OnCompleteMessageLabel', _t('UserDefinedForm.ONCOMPLETELABEL', 'Show on completion')),
$editor = new HtmlEditorField('OnCompleteMessage', '', _t('UserDefinedForm.ONCOMPLETEMESSAGE', $self->OnCompleteMessage))
);
$onCompleteFieldSet->addExtraClass('field');
$editor->setRows(3);
$label->addExtraClass('left');
// Define config for email recipients
$emailRecipientsConfig = GridFieldConfig_RecordEditor::create(10);
$emailRecipientsConfig->getComponentByType('GridFieldAddNewButton')
->setButtonName(
_t('UserDefinedForm.ADDEMAILRECIPIENT', 'Add Email Recipient')
);
// who do we email on submission
$emailRecipients = new GridField(
'EmailRecipients',
_t('UserDefinedForm.EMAILRECIPIENTS', 'Email Recipients'),
$self->EmailRecipients(),
$emailRecipientsConfig
);
$emailRecipients
->getConfig()
->getComponentByType('GridFieldDetailForm')
->setItemRequestClass('UserFormRecipientItemRequest');
$fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet);
$fields->addFieldToTab('Root.Recipients', $emailRecipients);
$fields->addFieldsToTab('Root.FormOptions', $self->getFormOptions());
// view the submissions
$submissions = new GridField(
'Submissions',
_t('UserDefinedForm.SUBMISSIONS', 'Submissions'),
$self->Submissions()->sort('Created', 'DESC')
);
// view the submissions
$submissions = new GridField(
'Submissions',
_t('UserDefinedForm.SUBMISSIONS', 'Submissions'),
$self->Submissions()->sort('Created', 'DESC')
);
// make sure a numeric not a empty string is checked against this int column for SQL server
$parentID = (!empty($self->ID)) ? (int) $self->ID : 0;
// make sure a numeric not a empty string is checked against this int column for SQL server
$parentID = (!empty($self->ID)) ? (int) $self->ID : 0;
// get a list of all field names and values used for print and export CSV views of the GridField below.
$columnSQL = <<<SQL
// get a list of all field names and values used for print and export CSV views of the GridField below.
$columnSQL = <<<SQL
SELECT "SubmittedFormField"."Name" as "Name", "SubmittedFormField"."Title" as "Title", COALESCE("EditableFormField"."Sort", 999) AS "Sort"
FROM "SubmittedFormField"
LEFT JOIN "SubmittedForm" ON "SubmittedForm"."ID" = "SubmittedFormField"."ParentID"
@ -183,147 +185,152 @@ LEFT JOIN "EditableFormField" ON "EditableFormField"."Title" = "SubmittedFormFie
WHERE "SubmittedForm"."ParentID" = '$parentID'
ORDER BY "Sort", "Title"
SQL;
// Sanitise periods in title
$columns = array();
foreach(DB::query($columnSQL)->map() as $name => $title) {
$columns[$name] = trim(strtr($title, '.', ' '));
}
// Sanitise periods in title
$columns = array();
foreach (DB::query($columnSQL)->map() as $name => $title) {
$columns[$name] = trim(strtr($title, '.', ' '));
}
$config = new GridFieldConfig();
$config->addComponent(new GridFieldToolbarHeader());
$config->addComponent($sort = new GridFieldSortableHeader());
$config->addComponent($filter = new UserFormsGridFieldFilterHeader());
$config->addComponent(new GridFieldDataColumns());
$config->addComponent(new GridFieldEditButton());
$config->addComponent(new GridFieldDeleteAction());
$config->addComponent(new GridFieldPageCount('toolbar-header-right'));
$config->addComponent($pagination = new GridFieldPaginator(25));
$config->addComponent(new GridFieldDetailForm());
$config->addComponent(new GridFieldButtonRow('after'));
$config->addComponent($export = new GridFieldExportButton('buttons-after-left'));
$config->addComponent($print = new GridFieldPrintButton('buttons-after-left'));
$config = new GridFieldConfig();
$config->addComponent(new GridFieldToolbarHeader());
$config->addComponent($sort = new GridFieldSortableHeader());
$config->addComponent($filter = new UserFormsGridFieldFilterHeader());
$config->addComponent(new GridFieldDataColumns());
$config->addComponent(new GridFieldEditButton());
$config->addComponent(new GridFieldDeleteAction());
$config->addComponent(new GridFieldPageCount('toolbar-header-right'));
$config->addComponent($pagination = new GridFieldPaginator(25));
$config->addComponent(new GridFieldDetailForm());
$config->addComponent(new GridFieldButtonRow('after'));
$config->addComponent($export = new GridFieldExportButton('buttons-after-left'));
$config->addComponent($print = new GridFieldPrintButton('buttons-after-left'));
/**
* Support for {@link https://github.com/colymba/GridFieldBulkEditingTools}
*/
if(class_exists('GridFieldBulkManager')) {
$config->addComponent(new GridFieldBulkManager());
}
/**
* Support for {@link https://github.com/colymba/GridFieldBulkEditingTools}
*/
if (class_exists('GridFieldBulkManager')) {
$config->addComponent(new GridFieldBulkManager());
}
$sort->setThrowExceptionOnBadDataType(false);
$filter->setThrowExceptionOnBadDataType(false);
$pagination->setThrowExceptionOnBadDataType(false);
$sort->setThrowExceptionOnBadDataType(false);
$filter->setThrowExceptionOnBadDataType(false);
$pagination->setThrowExceptionOnBadDataType(false);
// attach every column to the print view form
$columns['Created'] = 'Created';
$filter->setColumns($columns);
// attach every column to the print view form
$columns['Created'] = 'Created';
$filter->setColumns($columns);
// print configuration
// print configuration
$print->setPrintHasHeader(true);
$print->setPrintColumns($columns);
$print->setPrintHasHeader(true);
$print->setPrintColumns($columns);
// export configuration
$export->setCsvHasHeader(true);
$export->setExportColumns($columns);
// export configuration
$export->setCsvHasHeader(true);
$export->setExportColumns($columns);
$submissions->setConfig($config);
$fields->addFieldToTab('Root.Submissions', $submissions);
$fields->addFieldToTab('Root.FormOptions', new CheckboxField('DisableSaveSubmissions', _t('UserDefinedForm.SAVESUBMISSIONS', 'Disable Saving Submissions to Server')));
$submissions->setConfig($config);
$fields->addFieldToTab('Root.Submissions', $submissions);
$fields->addFieldToTab('Root.FormOptions', new CheckboxField('DisableSaveSubmissions', _t('UserDefinedForm.SAVESUBMISSIONS', 'Disable Saving Submissions to Server')));
});
});
$fields = parent::getCMSFields();
$fields = parent::getCMSFields();
if($this->EmailRecipients()->Count() == 0 && static::config()->recipients_warning_enabled) {
$fields->addFieldToTab("Root.Main", new LiteralField("EmailRecipientsWarning",
"<p class=\"message warning\">" . _t("UserDefinedForm.NORECIPIENTS",
"Warning: You have not configured any recipients. Form submissions may be missed.")
. "</p>"), "Title");
}
if ($this->EmailRecipients()->Count() == 0 && static::config()->recipients_warning_enabled) {
$fields->addFieldToTab("Root.Main", new LiteralField("EmailRecipientsWarning",
"<p class=\"message warning\">" . _t("UserDefinedForm.NORECIPIENTS",
"Warning: You have not configured any recipients. Form submissions may be missed.")
. "</p>"), "Title");
}
return $fields;
}
return $fields;
}
/**
* Allow overriding the EmailRecipients on a {@link DataExtension}
* so you can customise who receives an email.
* Converts the RelationList to an ArrayList so that manipulation
* of the original source data isn't possible.
*
* @return ArrayList
*/
public function FilteredEmailRecipients($data = null, $form = null) {
$recipients = new ArrayList($this->EmailRecipients()->toArray());
/**
* Allow overriding the EmailRecipients on a {@link DataExtension}
* so you can customise who receives an email.
* Converts the RelationList to an ArrayList so that manipulation
* of the original source data isn't possible.
*
* @return ArrayList
*/
public function FilteredEmailRecipients($data = null, $form = null)
{
$recipients = new ArrayList($this->EmailRecipients()->toArray());
// Filter by rules
$recipients = $recipients->filterByCallback(function($recipient) use ($data, $form) {
return $recipient->canSend($data, $form);
});
// Filter by rules
$recipients = $recipients->filterByCallback(function ($recipient) use ($data, $form) {
return $recipient->canSend($data, $form);
});
$this->extend('updateFilteredEmailRecipients', $recipients, $data, $form);
$this->extend('updateFilteredEmailRecipients', $recipients, $data, $form);
return $recipients;
}
return $recipients;
}
/**
* Custom options for the form. You can extend the built in options by
* using {@link updateFormOptions()}
*
* @return FieldList
*/
public function getFormOptions() {
$submit = ($this->SubmitButtonText) ? $this->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
$clear = ($this->ClearButtonText) ? $this->ClearButtonText : _t('UserDefinedForm.CLEARBUTTON', 'Clear');
/**
* Custom options for the form. You can extend the built in options by
* using {@link updateFormOptions()}
*
* @return FieldList
*/
public function getFormOptions()
{
$submit = ($this->SubmitButtonText) ? $this->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
$clear = ($this->ClearButtonText) ? $this->ClearButtonText : _t('UserDefinedForm.CLEARBUTTON', 'Clear');
$options = new FieldList(
new TextField("SubmitButtonText", _t('UserDefinedForm.TEXTONSUBMIT', 'Text on submit button:'), $submit),
new TextField("ClearButtonText", _t('UserDefinedForm.TEXTONCLEAR', 'Text on clear button:'), $clear),
new CheckboxField("ShowClearButton", _t('UserDefinedForm.SHOWCLEARFORM', 'Show Clear Form Button'), $this->ShowClearButton),
new CheckboxField("EnableLiveValidation", _t('UserDefinedForm.ENABLELIVEVALIDATION', 'Enable live validation')),
new CheckboxField("HideFieldLabels", _t('UserDefinedForm.HIDEFIELDLABELS', 'Hide field labels')),
new CheckboxField("DisplayErrorMessagesAtTop", _t('UserDefinedForm.DISPLAYERRORMESSAGESATTOP', 'Display error messages above the form?')),
new CheckboxField('DisableCsrfSecurityToken', _t('UserDefinedForm.DISABLECSRFSECURITYTOKEN', 'Disable CSRF Token')),
new CheckboxField('DisableAuthenicatedFinishAction', _t('UserDefinedForm.DISABLEAUTHENICATEDFINISHACTION', 'Disable Authentication on finish action'))
);
$options = new FieldList(
new TextField("SubmitButtonText", _t('UserDefinedForm.TEXTONSUBMIT', 'Text on submit button:'), $submit),
new TextField("ClearButtonText", _t('UserDefinedForm.TEXTONCLEAR', 'Text on clear button:'), $clear),
new CheckboxField("ShowClearButton", _t('UserDefinedForm.SHOWCLEARFORM', 'Show Clear Form Button'), $this->ShowClearButton),
new CheckboxField("EnableLiveValidation", _t('UserDefinedForm.ENABLELIVEVALIDATION', 'Enable live validation')),
new CheckboxField("HideFieldLabels", _t('UserDefinedForm.HIDEFIELDLABELS', 'Hide field labels')),
new CheckboxField("DisplayErrorMessagesAtTop", _t('UserDefinedForm.DISPLAYERRORMESSAGESATTOP', 'Display error messages above the form?')),
new CheckboxField('DisableCsrfSecurityToken', _t('UserDefinedForm.DISABLECSRFSECURITYTOKEN', 'Disable CSRF Token')),
new CheckboxField('DisableAuthenicatedFinishAction', _t('UserDefinedForm.DISABLEAUTHENICATEDFINISHACTION', 'Disable Authentication on finish action'))
);
$this->extend('updateFormOptions', $options);
$this->extend('updateFormOptions', $options);
return $options;
}
return $options;
}
/**
* Get the HTML id of the error container displayed above the form.
*
* @return string
*/
public function getErrorContainerID() {
return $this->config()->error_container_id;
}
/**
* Get the HTML id of the error container displayed above the form.
*
* @return string
*/
public function getErrorContainerID()
{
return $this->config()->error_container_id;
}
public function requireDefaultRecords() {
parent::requireDefaultRecords();
public function requireDefaultRecords()
{
parent::requireDefaultRecords();
if(!$this->config()->upgrade_on_build) {
return;
}
if (!$this->config()->upgrade_on_build) {
return;
}
// Perform migrations
Injector::inst()
->create('UserFormsUpgradeService')
->setQuiet(true)
->run();
// Perform migrations
Injector::inst()
->create('UserFormsUpgradeService')
->setQuiet(true)
->run();
DB::alteration_message('Migrated userforms', 'changed');
}
DB::alteration_message('Migrated userforms', 'changed');
}
/**
* Validate formfields
*/
public function getCMSValidator() {
return new UserFormValidator();
}
/**
* Validate formfields
*/
public function getCMSValidator()
{
return new UserFormValidator();
}
}
/**
@ -332,232 +339,238 @@ SQL;
* @package userforms
*/
class UserDefinedForm_Controller extends Page_Controller {
class UserDefinedForm_Controller extends Page_Controller
{
private static $finished_anchor = '#uff';
private static $finished_anchor = '#uff';
private static $allowed_actions = array(
'index',
'ping',
'Form',
'finished'
);
private static $allowed_actions = array(
'index',
'ping',
'Form',
'finished'
);
public function init() {
parent::init();
public function init()
{
parent::init();
// load the jquery
$lang = i18n::get_lang_from_locale(i18n::get_locale());
Requirements::css(USERFORMS_DIR . '/css/UserForm.css');
Requirements::javascript(FRAMEWORK_DIR .'/thirdparty/jquery/jquery.js');
Requirements::javascript(USERFORMS_DIR . '/thirdparty/jquery-validate/jquery.validate.min.js');
Requirements::add_i18n_javascript(USERFORMS_DIR . '/javascript/lang');
Requirements::javascript(USERFORMS_DIR . '/javascript/UserForm.js');
// load the jquery
$lang = i18n::get_lang_from_locale(i18n::get_locale());
Requirements::css(USERFORMS_DIR . '/css/UserForm.css');
Requirements::javascript(FRAMEWORK_DIR .'/thirdparty/jquery/jquery.js');
Requirements::javascript(USERFORMS_DIR . '/thirdparty/jquery-validate/jquery.validate.min.js');
Requirements::add_i18n_javascript(USERFORMS_DIR . '/javascript/lang');
Requirements::javascript(USERFORMS_DIR . '/javascript/UserForm.js');
Requirements::javascript(
USERFORMS_DIR . "/thirdparty/jquery-validate/localization/messages_{$lang}.min.js"
);
Requirements::javascript(
USERFORMS_DIR . "/thirdparty/jquery-validate/localization/methods_{$lang}.min.js"
);
if($this->HideFieldLabels) {
Requirements::javascript(USERFORMS_DIR . '/thirdparty/Placeholders.js/Placeholders.min.js');
}
Requirements::javascript(
USERFORMS_DIR . "/thirdparty/jquery-validate/localization/messages_{$lang}.min.js"
);
Requirements::javascript(
USERFORMS_DIR . "/thirdparty/jquery-validate/localization/methods_{$lang}.min.js"
);
if ($this->HideFieldLabels) {
Requirements::javascript(USERFORMS_DIR . '/thirdparty/Placeholders.js/Placeholders.min.js');
}
// Bind a confirmation message when navigating away from a partially completed form.
$page = $this->data();
if($page::config()->enable_are_you_sure) {
Requirements::javascript(USERFORMS_DIR . '/thirdparty/jquery.are-you-sure/jquery.are-you-sure.js');
}
}
// Bind a confirmation message when navigating away from a partially completed form.
$page = $this->data();
if ($page::config()->enable_are_you_sure) {
Requirements::javascript(USERFORMS_DIR . '/thirdparty/jquery.are-you-sure/jquery.are-you-sure.js');
}
}
/**
* Using $UserDefinedForm in the Content area of the page shows
* where the form should be rendered into. If it does not exist
* then default back to $Form.
*
* @return array
*/
public function index() {
if($this->Content && $form = $this->Form()) {
$hasLocation = stristr($this->Content, '$UserDefinedForm');
if($hasLocation) {
$content = preg_replace('/(<p[^>]*>)?\\$UserDefinedForm(<\\/p>)?/i', $form->forTemplate(), $this->Content);
return array(
'Content' => DBField::create_field('HTMLText', $content),
'Form' => ""
);
}
}
/**
* Using $UserDefinedForm in the Content area of the page shows
* where the form should be rendered into. If it does not exist
* then default back to $Form.
*
* @return array
*/
public function index()
{
if ($this->Content && $form = $this->Form()) {
$hasLocation = stristr($this->Content, '$UserDefinedForm');
if ($hasLocation) {
$content = preg_replace('/(<p[^>]*>)?\\$UserDefinedForm(<\\/p>)?/i', $form->forTemplate(), $this->Content);
return array(
'Content' => DBField::create_field('HTMLText', $content),
'Form' => ""
);
}
}
return array(
'Content' => DBField::create_field('HTMLText', $this->Content),
'Form' => $this->Form()
);
}
return array(
'Content' => DBField::create_field('HTMLText', $this->Content),
'Form' => $this->Form()
);
}
/**
* Keep the session alive for the user.
*
* @return int
*/
public function ping() {
return 1;
}
/**
* Keep the session alive for the user.
*
* @return int
*/
public function ping()
{
return 1;
}
/**
* Get the form for the page. Form can be modified by calling {@link updateForm()}
* on a UserDefinedForm extension.
*
* @return Forms
*/
public function Form() {
$form = UserForm::create($this);
$this->generateConditionalJavascript();
return $form;
}
/**
* Get the form for the page. Form can be modified by calling {@link updateForm()}
* on a UserDefinedForm extension.
*
* @return Forms
*/
public function Form()
{
$form = UserForm::create($this);
$this->generateConditionalJavascript();
return $form;
}
/**
* Generate the javascript for the conditional field show / hiding logic.
*
* @return void
*/
public function generateConditionalJavascript() {
$default = "";
$rules = "";
/**
* Generate the javascript for the conditional field show / hiding logic.
*
* @return void
*/
public function generateConditionalJavascript()
{
$default = "";
$rules = "";
$watch = array();
$watchLoad = array();
$watch = array();
$watchLoad = array();
if($this->Fields()) {
foreach($this->Fields() as $field) {
$holderSelector = $field->getSelectorHolder();
if ($this->Fields()) {
foreach ($this->Fields() as $field) {
$holderSelector = $field->getSelectorHolder();
// Is this Field Show by Default
if(!$field->ShowOnLoad) {
$default .= "{$holderSelector}.hide().trigger('userform.field.hide');\n";
}
// Is this Field Show by Default
if (!$field->ShowOnLoad) {
$default .= "{$holderSelector}.hide().trigger('userform.field.hide');\n";
}
// Check for field dependencies / default
foreach($field->EffectiveDisplayRules() as $rule) {
// Check for field dependencies / default
foreach ($field->EffectiveDisplayRules() as $rule) {
// Get the field which is effected
$formFieldWatch = EditableFormField::get()->byId($rule->ConditionFieldID);
// Get the field which is effected
$formFieldWatch = EditableFormField::get()->byId($rule->ConditionFieldID);
// Skip deleted fields
if(!$formFieldWatch) {
continue;
}
// Skip deleted fields
if (!$formFieldWatch) {
continue;
}
$fieldToWatch = $formFieldWatch->getSelectorField($rule);
$fieldToWatchOnLoad = $formFieldWatch->getSelectorField($rule, true);
$fieldToWatch = $formFieldWatch->getSelectorField($rule);
$fieldToWatchOnLoad = $formFieldWatch->getSelectorField($rule, true);
// show or hide?
$view = ($rule->Display == 'Hide') ? 'hide' : 'show';
$opposite = ($view == "show") ? "hide" : "show";
// show or hide?
$view = ($rule->Display == 'Hide') ? 'hide' : 'show';
$opposite = ($view == "show") ? "hide" : "show";
// what action do we need to keep track of. Something nicer here maybe?
// @todo encapulsation
$action = "change";
// what action do we need to keep track of. Something nicer here maybe?
// @todo encapulsation
$action = "change";
if($formFieldWatch instanceof EditableTextField) {
$action = "keyup";
}
if ($formFieldWatch instanceof EditableTextField) {
$action = "keyup";
}
// is this field a special option field
$checkboxField = false;
$radioField = false;
// is this field a special option field
$checkboxField = false;
$radioField = false;
if(in_array($formFieldWatch->ClassName, array('EditableCheckboxGroupField', 'EditableCheckbox'))) {
$action = "click";
$checkboxField = true;
} else if ($formFieldWatch->ClassName == "EditableRadioField") {
$radioField = true;
}
if (in_array($formFieldWatch->ClassName, array('EditableCheckboxGroupField', 'EditableCheckbox'))) {
$action = "click";
$checkboxField = true;
} elseif ($formFieldWatch->ClassName == "EditableRadioField") {
$radioField = true;
}
// and what should we evaluate
switch($rule->ConditionOption) {
case 'IsNotBlank':
$expression = ($checkboxField || $radioField) ? '$(this).is(":checked")' :'$(this).val() != ""';
// and what should we evaluate
switch ($rule->ConditionOption) {
case 'IsNotBlank':
$expression = ($checkboxField || $radioField) ? '$(this).is(":checked")' :'$(this).val() != ""';
break;
case 'IsBlank':
$expression = ($checkboxField || $radioField) ? '!($(this).is(":checked"))' : '$(this).val() == ""';
break;
case 'IsBlank':
$expression = ($checkboxField || $radioField) ? '!($(this).is(":checked"))' : '$(this).val() == ""';
break;
case 'HasValue':
if ($checkboxField) {
$expression = '$(this).prop("checked")';
} else if ($radioField) {
// We cannot simply get the value of the radio group, we need to find the checked option first.
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()=="'. $rule->FieldValue .'"';
} else {
$expression = '$(this).val() == "'. $rule->FieldValue .'"';
}
break;
case 'HasValue':
if ($checkboxField) {
$expression = '$(this).prop("checked")';
} elseif ($radioField) {
// We cannot simply get the value of the radio group, we need to find the checked option first.
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()=="'. $rule->FieldValue .'"';
} else {
$expression = '$(this).val() == "'. $rule->FieldValue .'"';
}
break;
case 'ValueLessThan':
$expression = '$(this).val() < parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueLessThan':
$expression = '$(this).val() < parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueLessThanEqual':
$expression = '$(this).val() <= parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueLessThanEqual':
$expression = '$(this).val() <= parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueGreaterThan':
$expression = '$(this).val() > parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueGreaterThan':
$expression = '$(this).val() > parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueGreaterThanEqual':
$expression = '$(this).val() >= parseFloat("'. $rule->FieldValue .'")';
break;
case 'ValueGreaterThanEqual':
$expression = '$(this).val() >= parseFloat("'. $rule->FieldValue .'")';
break;
default: // ==HasNotValue
if ($checkboxField) {
$expression = '!$(this).prop("checked")';
} else if ($radioField) {
// We cannot simply get the value of the radio group, we need to find the checked option first.
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()!="'. $rule->FieldValue .'"';
} else {
$expression = '$(this).val() != "'. $rule->FieldValue .'"';
}
break;
default: // ==HasNotValue
if ($checkboxField) {
$expression = '!$(this).prop("checked")';
} elseif ($radioField) {
// We cannot simply get the value of the radio group, we need to find the checked option first.
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()!="'. $rule->FieldValue .'"';
} else {
$expression = '$(this).val() != "'. $rule->FieldValue .'"';
}
break;
}
break;
}
if(!isset($watch[$fieldToWatch])) {
$watch[$fieldToWatch] = array();
}
if (!isset($watch[$fieldToWatch])) {
$watch[$fieldToWatch] = array();
}
$watch[$fieldToWatch][] = array(
'expression' => $expression,
'holder_selector' => $holderSelector,
'view' => $view,
'opposite' => $opposite,
'action' => $action
);
$watch[$fieldToWatch][] = array(
'expression' => $expression,
'holder_selector' => $holderSelector,
'view' => $view,
'opposite' => $opposite,
'action' => $action
);
$watchLoad[$fieldToWatchOnLoad] = true;
}
}
}
$watchLoad[$fieldToWatchOnLoad] = true;
}
}
}
if($watch) {
foreach($watch as $key => $values) {
$logic = array();
$actions = array();
if ($watch) {
foreach ($watch as $key => $values) {
$logic = array();
$actions = array();
foreach($values as $rule) {
// Assign action
$actions[$rule['action']] = $rule['action'];
foreach ($values as $rule) {
// Assign action
$actions[$rule['action']] = $rule['action'];
// Assign behaviour
$expression = $rule['expression'];
$holder = $rule['holder_selector'];
$view = $rule['view']; // hide or show
$opposite = $rule['opposite'];
// Generated javascript for triggering visibility
$logic[] = <<<"EOS"
// Assign behaviour
$expression = $rule['expression'];
$holder = $rule['holder_selector'];
$view = $rule['view']; // hide or show
$opposite = $rule['opposite'];
// Generated javascript for triggering visibility
$logic[] = <<<"EOS"
if({$expression}) {
{$holder}
.{$view}()
@ -568,33 +581,33 @@ if({$expression}) {
.trigger('userform.field.{$opposite}');
}
EOS;
}
}
$logic = implode("\n", $logic);
$rules .= $key.".each(function() {\n
$logic = implode("\n", $logic);
$rules .= $key.".each(function() {\n
$(this).data('userformConditions', function() {\n
$logic\n
}); \n
});\n";
foreach($actions as $action) {
$rules .= $key.".$action(function() {
foreach ($actions as $action) {
$rules .= $key.".$action(function() {
$(this).data('userformConditions').call(this);\n
});\n";
}
}
}
}
}
}
if($watchLoad) {
foreach($watchLoad as $key => $value) {
$rules .= $key.".each(function() {
if ($watchLoad) {
foreach ($watchLoad as $key => $value) {
$rules .= $key.".each(function() {
$(this).data('userformConditions').call(this);\n
});\n";
}
}
}
}
// Only add customScript if $default or $rules is defined
if($default || $rules) {
Requirements::customScript(<<<JS
// Only add customScript if $default or $rules is defined
if ($default || $rules) {
Requirements::customScript(<<<JS
(function($) {
$(document).ready(function() {
$default
@ -604,265 +617,266 @@ EOS;
})(jQuery);
JS
, 'UserFormsConditional');
}
}
}
}
/**
* Process the form that is submitted through the site
*
* {@see UserForm::validate()} for validation step prior to processing
*
* @param array $data
* @param Form $form
*
* @return Redirection
*/
public function process($data, $form) {
$submittedForm = Object::create('SubmittedForm');
$submittedForm->SubmittedByID = ($id = Member::currentUserID()) ? $id : 0;
$submittedForm->ParentID = $this->ID;
/**
* Process the form that is submitted through the site
*
* {@see UserForm::validate()} for validation step prior to processing
*
* @param array $data
* @param Form $form
*
* @return Redirection
*/
public function process($data, $form)
{
$submittedForm = Object::create('SubmittedForm');
$submittedForm->SubmittedByID = ($id = Member::currentUserID()) ? $id : 0;
$submittedForm->ParentID = $this->ID;
// if saving is not disabled save now to generate the ID
if(!$this->DisableSaveSubmissions) {
$submittedForm->write();
}
// if saving is not disabled save now to generate the ID
if (!$this->DisableSaveSubmissions) {
$submittedForm->write();
}
$attachments = array();
$submittedFields = new ArrayList();
$attachments = array();
$submittedFields = new ArrayList();
foreach($this->Fields() as $field) {
if(!$field->showInReports()) {
continue;
}
foreach ($this->Fields() as $field) {
if (!$field->showInReports()) {
continue;
}
$submittedField = $field->getSubmittedFormField();
$submittedField->ParentID = $submittedForm->ID;
$submittedField->Name = $field->Name;
$submittedField->Title = $field->getField('Title');
$submittedField = $field->getSubmittedFormField();
$submittedField->ParentID = $submittedForm->ID;
$submittedField->Name = $field->Name;
$submittedField->Title = $field->getField('Title');
// save the value from the data
if($field->hasMethod('getValueFromData')) {
$submittedField->Value = $field->getValueFromData($data);
} else {
if(isset($data[$field->Name])) {
$submittedField->Value = $data[$field->Name];
}
}
// save the value from the data
if ($field->hasMethod('getValueFromData')) {
$submittedField->Value = $field->getValueFromData($data);
} else {
if (isset($data[$field->Name])) {
$submittedField->Value = $data[$field->Name];
}
}
if(!empty($data[$field->Name])) {
if(in_array("EditableFileField", $field->getClassAncestry())) {
if(isset($_FILES[$field->Name])) {
$foldername = $field->getFormField()->getFolderName();
if (!empty($data[$field->Name])) {
if (in_array("EditableFileField", $field->getClassAncestry())) {
if (isset($_FILES[$field->Name])) {
$foldername = $field->getFormField()->getFolderName();
// create the file from post data
$upload = new Upload();
$file = new File();
$file->ShowInSearch = 0;
try {
$upload->loadIntoFile($_FILES[$field->Name], $file, $foldername);
} catch( ValidationException $e ) {
$validationResult = $e->getResult();
$form->addErrorMessage($field->Name, $validationResult->message(), 'bad');
Controller::curr()->redirectBack();
return;
}
// create the file from post data
$upload = new Upload();
$file = new File();
$file->ShowInSearch = 0;
try {
$upload->loadIntoFile($_FILES[$field->Name], $file, $foldername);
} catch (ValidationException $e) {
$validationResult = $e->getResult();
$form->addErrorMessage($field->Name, $validationResult->message(), 'bad');
Controller::curr()->redirectBack();
return;
}
// write file to form field
$submittedField->UploadedFileID = $file->ID;
// write file to form field
$submittedField->UploadedFileID = $file->ID;
// attach a file only if lower than 1MB
if($file->getAbsoluteSize() < 1024*1024*1) {
$attachments[] = $file;
}
}
}
}
// attach a file only if lower than 1MB
if ($file->getAbsoluteSize() < 1024*1024*1) {
$attachments[] = $file;
}
}
}
}
$submittedField->extend('onPopulationFromField', $field);
$submittedField->extend('onPopulationFromField', $field);
if(!$this->DisableSaveSubmissions) {
$submittedField->write();
}
if (!$this->DisableSaveSubmissions) {
$submittedField->write();
}
$submittedFields->push($submittedField);
}
$submittedFields->push($submittedField);
}
$emailData = array(
"Sender" => Member::currentUser(),
"Fields" => $submittedFields
);
$emailData = array(
"Sender" => Member::currentUser(),
"Fields" => $submittedFields
);
$this->extend('updateEmailData', $emailData, $attachments);
$this->extend('updateEmailData', $emailData, $attachments);
// email users on submit.
if($recipients = $this->FilteredEmailRecipients($data, $form)) {
// email users on submit.
if ($recipients = $this->FilteredEmailRecipients($data, $form)) {
foreach ($recipients as $recipient) {
$email = new UserFormRecipientEmail($submittedFields);
$mergeFields = $this->getMergeFieldsMap($emailData['Fields']);
if ($attachments) {
foreach ($attachments as $file) {
if ($file->ID != 0) {
$email->attachFile(
$file->Filename,
$file->Filename,
HTTP::get_mime_type($file->Filename)
);
}
}
}
$parsedBody = SSViewer::execute_string($recipient->getEmailBodyContent(), $mergeFields);
foreach($recipients as $recipient) {
$email = new UserFormRecipientEmail($submittedFields);
$mergeFields = $this->getMergeFieldsMap($emailData['Fields']);
if (!$recipient->SendPlain && $recipient->emailTemplateExists()) {
$email->setTemplate($recipient->EmailTemplate);
}
if($attachments) {
foreach($attachments as $file) {
if($file->ID != 0) {
$email->attachFile(
$file->Filename,
$file->Filename,
HTTP::get_mime_type($file->Filename)
);
}
}
}
$email->populateTemplate($recipient);
$email->populateTemplate($emailData);
$email->setFrom($recipient->EmailFrom);
$email->setBody($parsedBody);
$email->setTo($recipient->EmailAddress);
$email->setSubject($recipient->EmailSubject);
$parsedBody = SSViewer::execute_string($recipient->getEmailBodyContent(), $mergeFields);
if ($recipient->EmailReplyTo) {
$email->setReplyTo($recipient->EmailReplyTo);
}
if (!$recipient->SendPlain && $recipient->emailTemplateExists()) {
$email->setTemplate($recipient->EmailTemplate);
}
// check to see if they are a dynamic reply to. eg based on a email field a user selected
if ($recipient->SendEmailFromField()) {
$submittedFormField = $submittedFields->find('Name', $recipient->SendEmailFromField()->Name);
$email->populateTemplate($recipient);
$email->populateTemplate($emailData);
$email->setFrom($recipient->EmailFrom);
$email->setBody($parsedBody);
$email->setTo($recipient->EmailAddress);
$email->setSubject($recipient->EmailSubject);
if ($submittedFormField && is_string($submittedFormField->Value)) {
$email->setReplyTo($submittedFormField->Value);
}
}
// check to see if they are a dynamic reciever eg based on a dropdown field a user selected
if ($recipient->SendEmailToField()) {
$submittedFormField = $submittedFields->find('Name', $recipient->SendEmailToField()->Name);
if($recipient->EmailReplyTo) {
$email->setReplyTo($recipient->EmailReplyTo);
}
if ($submittedFormField && is_string($submittedFormField->Value)) {
$email->setTo($submittedFormField->Value);
}
}
// check to see if they are a dynamic reply to. eg based on a email field a user selected
if($recipient->SendEmailFromField()) {
$submittedFormField = $submittedFields->find('Name', $recipient->SendEmailFromField()->Name);
// check to see if there is a dynamic subject
if ($recipient->SendEmailSubjectField()) {
$submittedFormField = $submittedFields->find('Name', $recipient->SendEmailSubjectField()->Name);
if($submittedFormField && is_string($submittedFormField->Value)) {
$email->setReplyTo($submittedFormField->Value);
}
}
// check to see if they are a dynamic reciever eg based on a dropdown field a user selected
if($recipient->SendEmailToField()) {
$submittedFormField = $submittedFields->find('Name', $recipient->SendEmailToField()->Name);
if ($submittedFormField && trim($submittedFormField->Value)) {
$email->setSubject($submittedFormField->Value);
}
}
if($submittedFormField && is_string($submittedFormField->Value)) {
$email->setTo($submittedFormField->Value);
}
}
$this->extend('updateEmail', $email, $recipient, $emailData);
// check to see if there is a dynamic subject
if($recipient->SendEmailSubjectField()) {
$submittedFormField = $submittedFields->find('Name', $recipient->SendEmailSubjectField()->Name);
if ($recipient->SendPlain) {
$body = strip_tags($recipient->getEmailBodyContent()) . "\n";
if (isset($emailData['Fields']) && !$recipient->HideFormData) {
foreach ($emailData['Fields'] as $Field) {
$body .= $Field->Title .': '. $Field->Value ." \n";
}
}
if($submittedFormField && trim($submittedFormField->Value)) {
$email->setSubject($submittedFormField->Value);
}
}
$email->setBody($body);
$email->sendPlain();
} else {
$email->send();
}
}
}
$this->extend('updateEmail', $email, $recipient, $emailData);
$submittedForm->extend('updateAfterProcess');
if($recipient->SendPlain) {
$body = strip_tags($recipient->getEmailBodyContent()) . "\n";
if(isset($emailData['Fields']) && !$recipient->HideFormData) {
foreach($emailData['Fields'] as $Field) {
$body .= $Field->Title .': '. $Field->Value ." \n";
}
}
Session::clear("FormInfo.{$form->FormName()}.errors");
Session::clear("FormInfo.{$form->FormName()}.data");
$email->setBody($body);
$email->sendPlain();
}
else {
$email->send();
}
}
}
$referrer = (isset($data['Referrer'])) ? '?referrer=' . urlencode($data['Referrer']) : "";
$submittedForm->extend('updateAfterProcess');
// set a session variable from the security ID to stop people accessing
// the finished method directly.
if (!$this->DisableAuthenicatedFinishAction) {
if (isset($data['SecurityID'])) {
Session::set('FormProcessed', $data['SecurityID']);
} else {
// if the form has had tokens disabled we still need to set FormProcessed
// to allow us to get through the finshed method
if (!$this->Form()->getSecurityToken()->isEnabled()) {
$randNum = rand(1, 1000);
$randHash = md5($randNum);
Session::set('FormProcessed', $randHash);
Session::set('FormProcessedNum', $randNum);
}
}
}
Session::clear("FormInfo.{$form->FormName()}.errors");
Session::clear("FormInfo.{$form->FormName()}.data");
if (!$this->DisableSaveSubmissions) {
Session::set('userformssubmission'. $this->ID, $submittedForm->ID);
}
$referrer = (isset($data['Referrer'])) ? '?referrer=' . urlencode($data['Referrer']) : "";
return $this->redirect($this->Link('finished') . $referrer . $this->config()->finished_anchor);
}
// set a session variable from the security ID to stop people accessing
// the finished method directly.
if(!$this->DisableAuthenicatedFinishAction) {
if (isset($data['SecurityID'])) {
Session::set('FormProcessed',$data['SecurityID']);
} else {
// if the form has had tokens disabled we still need to set FormProcessed
// to allow us to get through the finshed method
if (!$this->Form()->getSecurityToken()->isEnabled()) {
$randNum = rand(1, 1000);
$randHash = md5($randNum);
Session::set('FormProcessed',$randHash);
Session::set('FormProcessedNum',$randNum);
}
}
}
/**
* Allows the use of field values in email body.
*
* @param ArrayList fields
* @return ArrayData
*/
private function getMergeFieldsMap($fields = array())
{
$data = new ArrayData(array());
if(!$this->DisableSaveSubmissions) {
Session::set('userformssubmission'. $this->ID, $submittedForm->ID);
}
foreach ($fields as $field) {
$data->setField($field->Name, DBField::create_field('Text', $field->Value));
}
return $this->redirect($this->Link('finished') . $referrer . $this->config()->finished_anchor);
}
return $data;
}
/**
* Allows the use of field values in email body.
*
* @param ArrayList fields
* @return ArrayData
*/
private function getMergeFieldsMap($fields = array()) {
$data = new ArrayData(array());
/**
* This action handles rendering the "finished" message, which is
* customizable by editing the ReceivedFormSubmission template.
*
* @return ViewableData
*/
public function finished()
{
$submission = Session::get('userformssubmission'. $this->ID);
foreach ($fields as $field) {
$data->setField($field->Name, DBField::create_field('Text', $field->Value));
}
if ($submission) {
$submission = SubmittedForm::get()->byId($submission);
}
return $data;
}
$referrer = isset($_GET['referrer']) ? urldecode($_GET['referrer']) : null;
/**
* This action handles rendering the "finished" message, which is
* customizable by editing the ReceivedFormSubmission template.
*
* @return ViewableData
*/
public function finished() {
$submission = Session::get('userformssubmission'. $this->ID);
if (!$this->DisableAuthenicatedFinishAction) {
$formProcessed = Session::get('FormProcessed');
if($submission) {
$submission = SubmittedForm::get()->byId($submission);
}
if (!isset($formProcessed)) {
return $this->redirect($this->Link() . $referrer);
} else {
$securityID = Session::get('SecurityID');
// make sure the session matches the SecurityID and is not left over from another form
if ($formProcessed != $securityID) {
// they may have disabled tokens on the form
$securityID = md5(Session::get('FormProcessedNum'));
if ($formProcessed != $securityID) {
return $this->redirect($this->Link() . $referrer);
}
}
}
$referrer = isset($_GET['referrer']) ? urldecode($_GET['referrer']) : null;
Session::clear('FormProcessed');
}
if(!$this->DisableAuthenicatedFinishAction) {
$formProcessed = Session::get('FormProcessed');
if (!isset($formProcessed)) {
return $this->redirect($this->Link() . $referrer);
} else {
$securityID = Session::get('SecurityID');
// make sure the session matches the SecurityID and is not left over from another form
if ($formProcessed != $securityID) {
// they may have disabled tokens on the form
$securityID = md5(Session::get('FormProcessedNum'));
if ($formProcessed != $securityID) {
return $this->redirect($this->Link() . $referrer);
}
}
}
Session::clear('FormProcessed');
}
return $this->customise(array(
'Content' => $this->customise(array(
'Submission' => $submission,
'Link' => $referrer
))->renderWith('ReceivedFormSubmission'),
'Form' => '',
));
}
return $this->customise(array(
'Content' => $this->customise(array(
'Submission' => $submission,
'Link' => $referrer
))->renderWith('ReceivedFormSubmission'),
'Form' => '',
));
}
}

View File

@ -7,53 +7,58 @@
* @package userforms
*/
class EditableCheckbox extends EditableFormField {
class EditableCheckbox extends EditableFormField
{
private static $singular_name = 'Checkbox Field';
private static $singular_name = 'Checkbox Field';
private static $plural_name = 'Checkboxes';
private static $plural_name = 'Checkboxes';
private static $db = array(
'CheckedDefault' => 'Boolean' // from CustomSettings
);
private static $db = array(
'CheckedDefault' => 'Boolean' // from CustomSettings
);
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->replaceField('Default', CheckboxField::create(
"CheckedDefault",
_t('EditableFormField.CHECKEDBYDEFAULT', 'Checked by Default?')
));
$fields->replaceField('Default', CheckboxField::create(
"CheckedDefault",
_t('EditableFormField.CHECKEDBYDEFAULT', 'Checked by Default?')
));
return $fields;
}
return $fields;
}
public function getFormField() {
$field = CheckboxField::create($this->Name, $this->EscapedTitle, $this->CheckedDefault)
->setFieldHolderTemplate('UserFormsCheckboxField_holder')
->setTemplate('UserFormsCheckboxField');
public function getFormField()
{
$field = CheckboxField::create($this->Name, $this->EscapedTitle, $this->CheckedDefault)
->setFieldHolderTemplate('UserFormsCheckboxField_holder')
->setTemplate('UserFormsCheckboxField');
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
public function getValueFromData($data) {
$value = (isset($data[$this->Name])) ? $data[$this->Name] : false;
public function getValueFromData($data)
{
$value = (isset($data[$this->Name])) ? $data[$this->Name] : false;
return ($value) ? _t('EditableFormField.YES', 'Yes') : _t('EditableFormField.NO', 'No');
}
return ($value) ? _t('EditableFormField.YES', 'Yes') : _t('EditableFormField.NO', 'No');
}
public function migrateSettings($data) {
// Migrate 'Default' setting to 'CheckedDefault'
if(isset($data['Default'])) {
$this->CheckedDefault = (bool)$data['Default'];
unset($data['Default']);
}
public function migrateSettings($data)
{
// Migrate 'Default' setting to 'CheckedDefault'
if (isset($data['Default'])) {
$this->CheckedDefault = (bool)$data['Default'];
unset($data['Default']);
}
parent::migrateSettings($data);
}
parent::migrateSettings($data);
}
}

View File

@ -7,52 +7,56 @@
* @package userforms
*/
class EditableCheckboxGroupField extends EditableMultipleOptionField {
class EditableCheckboxGroupField extends EditableMultipleOptionField
{
private static $singular_name = "Checkbox Group";
private static $singular_name = "Checkbox Group";
private static $plural_name = "Checkbox Groups";
private static $plural_name = "Checkbox Groups";
public function getFormField() {
$field = new UserFormsCheckboxSetField($this->Name, $this->EscapedTitle, $this->getOptionsMap());
$field->setFieldHolderTemplate('UserFormsMultipleOptionField_holder');
public function getFormField()
{
$field = new UserFormsCheckboxSetField($this->Name, $this->EscapedTitle, $this->getOptionsMap());
$field->setFieldHolderTemplate('UserFormsMultipleOptionField_holder');
// Set the default checked items
$defaultCheckedItems = $this->getDefaultOptions();
if ($defaultCheckedItems->count()) {
$field->setDefaultItems($defaultCheckedItems->map('EscapedTitle')->keys());
}
// Set the default checked items
$defaultCheckedItems = $this->getDefaultOptions();
if ($defaultCheckedItems->count()) {
$field->setDefaultItems($defaultCheckedItems->map('EscapedTitle')->keys());
}
$this->doUpdateFormField($field);
return $field;
}
$this->doUpdateFormField($field);
return $field;
}
public function getValueFromData($data) {
$result = '';
$entries = (isset($data[$this->Name])) ? $data[$this->Name] : false;
public function getValueFromData($data)
{
$result = '';
$entries = (isset($data[$this->Name])) ? $data[$this->Name] : false;
if($entries) {
if(!is_array($data[$this->Name])) {
$entries = array($data[$this->Name]);
}
foreach($entries as $selected => $value) {
if(!$result) {
$result = $value;
} else {
$result .= ", " . $value;
}
}
}
return $result;
}
if ($entries) {
if (!is_array($data[$this->Name])) {
$entries = array($data[$this->Name]);
}
foreach ($entries as $selected => $value) {
if (!$result) {
$result = $value;
} else {
$result .= ", " . $value;
}
}
}
return $result;
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) {
// watch out for checkboxs as the inputs don't have values but are 'checked
// @todo - Test this
if($rule->FieldValue) {
return "$(\"input[name='{$this->Name}[]'][value='{$rule->FieldValue}']\")";
} else {
return "$(\"input[name='{$this->Name}[]']:first\")";
}
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
{
// watch out for checkboxs as the inputs don't have values but are 'checked
// @todo - Test this
if ($rule->FieldValue) {
return "$(\"input[name='{$this->Name}[]'][value='{$rule->FieldValue}']\")";
} else {
return "$(\"input[name='{$this->Name}[]']:first\")";
}
}
}

View File

@ -5,45 +5,51 @@
*
* @package userforms
*/
class EditableCountryDropdownField extends EditableFormField {
class EditableCountryDropdownField extends EditableFormField
{
private static $singular_name = 'Country Dropdown';
private static $singular_name = 'Country Dropdown';
private static $plural_name = 'Country Dropdowns';
private static $plural_name = 'Country Dropdowns';
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName('Default');
$fields->removeByName('Default');
return $fields;
}
return $fields;
}
public function getFormField() {
$field = CountryDropdownField::create($this->Name, $this->EscapedTitle)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsDropdownField');
public function getFormField()
{
$field = CountryDropdownField::create($this->Name, $this->EscapedTitle)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsDropdownField');
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
public function getValueFromData($data) {
if(isset($data[$this->Name])) {
$source = $this->getFormField()->getSource();
return $source[$data[$this->Name]];
}
}
public function getValueFromData($data)
{
if (isset($data[$this->Name])) {
$source = $this->getFormField()->getSource();
return $source[$data[$this->Name]];
}
}
public function getIcon() {
return USERFORMS_DIR . '/images/editabledropdown.png';
}
public function getIcon()
{
return USERFORMS_DIR . '/images/editabledropdown.png';
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) {
return "$(\"select[name='{$this->Name}']\")";
}
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
{
return "$(\"select[name='{$this->Name}']\")";
}
}

View File

@ -7,60 +7,65 @@
* @package userforms
*/
class EditableDateField extends EditableFormField {
class EditableDateField extends EditableFormField
{
private static $singular_name = 'Date Field';
private static $singular_name = 'Date Field';
private static $plural_name = 'Date Fields';
private static $plural_name = 'Date Fields';
private static $db = array(
'DefaultToToday' => 'Boolean' // From customsettings
);
private static $db = array(
'DefaultToToday' => 'Boolean' // From customsettings
);
/**
* @return FieldList
*/
public function getCMSFields() {
$this->beforeUpdateCMSFields(function(FieldList $fields) {
$fields->addFieldToTab(
'Root.Main',
CheckboxField::create(
'DefaultToToday',
_t('EditableFormField.DEFAULTTOTODAY', 'Default to Today?')
),
'RightTitle'
);
});
/**
* @return FieldList
*/
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->addFieldToTab(
'Root.Main',
CheckboxField::create(
'DefaultToToday',
_t('EditableFormField.DEFAULTTOTODAY', 'Default to Today?')
),
'RightTitle'
);
});
return parent::getCMSFields();
}
return parent::getCMSFields();
}
/**
* Return the form field
*
*/
public function getFormField() {
$defaultValue = $this->DefaultToToday
? SS_Datetime::now()->Format('Y-m-d')
: $this->Default;
/**
* Return the form field
*
*/
public function getFormField()
{
$defaultValue = $this->DefaultToToday
? SS_Datetime::now()->Format('Y-m-d')
: $this->Default;
$field = EditableDateField_FormField::create( $this->Name, $this->EscapedTitle, $defaultValue)
->setConfig('showcalendar', true)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField');
$field = EditableDateField_FormField::create($this->Name, $this->EscapedTitle, $defaultValue)
->setConfig('showcalendar', true)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField');
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
}
/**
* @package userforms
*/
class EditableDateField_FormField extends DateField {
class EditableDateField_FormField extends DateField
{
public function Type() {
return "date-alt text";
}
}
public function Type()
{
return "date-alt text";
}
}

View File

@ -7,41 +7,45 @@
* @package userforms
*/
class EditableDropdown extends EditableMultipleOptionField {
class EditableDropdown extends EditableMultipleOptionField
{
private static $singular_name = 'Dropdown Field';
private static $singular_name = 'Dropdown Field';
private static $plural_name = 'Dropdowns';
private static $plural_name = 'Dropdowns';
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName('Default');
$fields->removeByName('Default');
return $fields;
}
return $fields;
}
/**
* @return DropdownField
*/
public function getFormField() {
$field = DropdownField::create($this->Name, $this->EscapedTitle, $this->getOptionsMap())
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsDropdownField');
/**
* @return DropdownField
*/
public function getFormField()
{
$field = DropdownField::create($this->Name, $this->EscapedTitle, $this->getOptionsMap())
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsDropdownField');
// Set default
$defaultOption = $this->getDefaultOptions()->first();
if($defaultOption) {
$field->setValue($defaultOption->EscapedTitle);
}
$this->doUpdateFormField($field);
return $field;
}
// Set default
$defaultOption = $this->getDefaultOptions()->first();
if ($defaultOption) {
$field->setValue($defaultOption->EscapedTitle);
}
$this->doUpdateFormField($field);
return $field;
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) {
return "$(\"select[name='{$this->Name}']\")";
}
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
{
return "$(\"select[name='{$this->Name}']\")";
}
}

View File

@ -7,56 +7,61 @@
* @package userforms
*/
class EditableEmailField extends EditableFormField {
class EditableEmailField extends EditableFormField
{
private static $singular_name = 'Email Field';
private static $singular_name = 'Email Field';
private static $plural_name = 'Email Fields';
private static $plural_name = 'Email Fields';
private static $db = array(
'Placeholder' => 'Varchar(255)'
);
private static $db = array(
'Placeholder' => 'Varchar(255)'
);
public function getCMSFields() {
$this->beforeUpdateCMSFields(function($fields) {
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'Placeholder',
_t('EditableTextField.PLACEHOLDER', 'Placeholder')
)
);
});
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function ($fields) {
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'Placeholder',
_t('EditableTextField.PLACEHOLDER', 'Placeholder')
)
);
});
return parent::getCMSFields();
}
return parent::getCMSFields();
}
public function getSetsOwnError() {
return true;
}
public function getSetsOwnError()
{
return true;
}
public function getFormField() {
$field = EmailField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField');
public function getFormField()
{
$field = EmailField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField');
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field) {
parent::updateFormField($field);
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field)
{
parent::updateFormField($field);
$field->setAttribute('data-rule-email', true);
$field->setAttribute('data-rule-email', true);
if($this->Placeholder) {
$field->setAttribute('placeholder', $this->Placeholder);
}
}
}
if ($this->Placeholder) {
$field->setAttribute('placeholder', $this->Placeholder);
}
}
}

View File

@ -3,90 +3,98 @@
/**
* Specifies that this ends a group of fields
*/
class EditableFieldGroup extends EditableFormField {
class EditableFieldGroup extends EditableFormField
{
private static $has_one = array(
'End' => 'EditableFieldGroupEnd'
);
private static $has_one = array(
'End' => 'EditableFieldGroupEnd'
);
/**
* Disable selection of group class
*
* @config
* @var bool
*/
private static $hidden = true;
/**
* Disable selection of group class
*
* @config
* @var bool
*/
private static $hidden = true;
/**
* Non-data field type
*
* @var type
*/
private static $literal = true;
/**
* Non-data field type
*
* @var type
*/
private static $literal = true;
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
return $fields;
}
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
return $fields;
}
public function getCMSTitle() {
$title = $this->getFieldNumber()
?: $this->Title
?: 'group';
public function getCMSTitle()
{
$title = $this->getFieldNumber()
?: $this->Title
?: 'group';
return _t(
'EditableFieldGroupEnd.FIELD_GROUP_START',
'Group {group}',
array(
'group' => $title
)
);
}
return _t(
'EditableFieldGroupEnd.FIELD_GROUP_START',
'Group {group}',
array(
'group' => $title
)
);
}
public function getInlineClassnameField($column, $fieldClasses) {
return new LabelField($column, $this->CMSTitle);
}
public function getInlineClassnameField($column, $fieldClasses)
{
return new LabelField($column, $this->CMSTitle);
}
public function showInReports() {
return false;
}
public function showInReports()
{
return false;
}
public function getFormField() {
$field = UserFormsGroupField::create()
->setTitle($this->EscapedTitle ?: false)
->setName($this->Name);
$this->doUpdateFormField($field);
return $field;
}
public function getFormField()
{
$field = UserFormsGroupField::create()
->setTitle($this->EscapedTitle ?: false)
->setName($this->Name);
$this->doUpdateFormField($field);
return $field;
}
protected function updateFormField($field) {
// set the right title on this field
if($this->RightTitle) {
// Since this field expects raw html, safely escape the user data prior
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
}
protected function updateFormField($field)
{
// set the right title on this field
if ($this->RightTitle) {
// Since this field expects raw html, safely escape the user data prior
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
}
// if this field has an extra class
if($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
// if this field has an extra class
if ($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
protected function onBeforeDelete() {
parent::onBeforeDelete();
protected function onBeforeDelete()
{
parent::onBeforeDelete();
// Ensures EndID is lazy-loaded for onAfterDelete
$this->EndID;
}
// Ensures EndID is lazy-loaded for onAfterDelete
$this->EndID;
}
protected function onAfterDelete() {
parent::onAfterDelete();
// Delete end
if(($end = $this->End()) && $end->exists()) {
$end->delete();
}
}
protected function onAfterDelete()
{
parent::onAfterDelete();
// Delete end
if (($end = $this->End()) && $end->exists()) {
$end->delete();
}
}
}

View File

@ -3,92 +3,100 @@
/**
* Specifies that this ends a group of fields
*/
class EditableFieldGroupEnd extends EditableFormField {
class EditableFieldGroupEnd extends EditableFormField
{
private static $belongs_to = array(
'Group' => 'EditableFieldGroup'
);
private static $belongs_to = array(
'Group' => 'EditableFieldGroup'
);
/**
* Disable selection of group class
*
* @config
* @var bool
*/
private static $hidden = true;
/**
* Disable selection of group class
*
* @config
* @var bool
*/
private static $hidden = true;
/**
* Non-data type
*
* @config
* @var bool
*/
private static $literal = true;
/**
* Non-data type
*
* @config
* @var bool
*/
private static $literal = true;
public function getCMSTitle() {
$group = $this->Group();
return _t(
'EditableFieldGroupEnd.FIELD_GROUP_END',
'{group} end',
array(
'group' => ($group && $group->exists()) ? $group->CMSTitle : 'Group'
)
);
}
public function getCMSTitle()
{
$group = $this->Group();
return _t(
'EditableFieldGroupEnd.FIELD_GROUP_END',
'{group} end',
array(
'group' => ($group && $group->exists()) ? $group->CMSTitle : 'Group'
)
);
}
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
return $fields;
}
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
return $fields;
}
public function getInlineClassnameField($column, $fieldClasses) {
return new LabelField($column, $this->CMSTitle);
}
public function getInlineClassnameField($column, $fieldClasses)
{
return new LabelField($column, $this->CMSTitle);
}
public function getInlineTitleField($column) {
return HiddenField::create($column);
}
public function getInlineTitleField($column)
{
return HiddenField::create($column);
}
public function getFormField() {
return null;
}
public function getFormField()
{
return null;
}
public function showInReports() {
return false;
}
public function showInReports()
{
return false;
}
public function onAfterWrite() {
parent::onAfterWrite();
public function onAfterWrite()
{
parent::onAfterWrite();
// If this is not attached to a group, find the first group prior to this
// with no end attached
$group = $this->Group();
if(!($group && $group->exists()) && $this->ParentID) {
$group = EditableFieldGroup::get()
->filter(array(
'ParentID' => $this->ParentID,
'Sort:LessThanOrEqual' => $this->Sort
))
->where('"EditableFieldGroup"."EndID" IS NULL OR "EditableFieldGroup"."EndID" = 0')
->sort('"Sort" DESC')
->first();
// If this is not attached to a group, find the first group prior to this
// with no end attached
$group = $this->Group();
if (!($group && $group->exists()) && $this->ParentID) {
$group = EditableFieldGroup::get()
->filter(array(
'ParentID' => $this->ParentID,
'Sort:LessThanOrEqual' => $this->Sort
))
->where('"EditableFieldGroup"."EndID" IS NULL OR "EditableFieldGroup"."EndID" = 0')
->sort('"Sort" DESC')
->first();
// When a group is found, attach it to this end
if($group) {
$group->EndID = $this->ID;
$group->write();
}
}
}
// When a group is found, attach it to this end
if ($group) {
$group->EndID = $this->ID;
$group->write();
}
}
}
protected function onAfterDelete() {
parent::onAfterDelete();
// Delete group
if(($group = $this->Group()) && $group->exists()) {
$group->delete();
}
}
protected function onAfterDelete()
{
parent::onAfterDelete();
// Delete group
if (($group = $this->Group()) && $group->exists()) {
$group->delete();
}
}
}

View File

@ -6,99 +6,105 @@
* @package userforms
*/
class EditableFileField extends EditableFormField {
class EditableFileField extends EditableFormField
{
private static $singular_name = 'File Upload Field';
private static $singular_name = 'File Upload Field';
private static $plural_names = 'File Fields';
private static $plural_names = 'File Fields';
private static $has_one = array(
'Folder' => 'Folder' // From CustomFields
);
private static $has_one = array(
'Folder' => 'Folder' // From CustomFields
);
/**
* Further limit uploadable file extensions in addition to the restrictions
* imposed by the File.allowed_extensions global configuration.
* @config
*/
private static $allowed_extensions_blacklist = array(
'htm', 'html', 'xhtml', 'swf', 'xml'
);
/**
* Further limit uploadable file extensions in addition to the restrictions
* imposed by the File.allowed_extensions global configuration.
* @config
*/
private static $allowed_extensions_blacklist = array(
'htm', 'html', 'xhtml', 'swf', 'xml'
);
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab(
'Root.Main',
TreeDropdownField::create(
'FolderID',
_t('EditableUploadField.SELECTUPLOADFOLDER', 'Select upload folder'),
'Folder'
)
);
$fields->addFieldToTab(
'Root.Main',
TreeDropdownField::create(
'FolderID',
_t('EditableUploadField.SELECTUPLOADFOLDER', 'Select upload folder'),
'Folder'
)
);
$fields->addFieldToTab("Root.Main", new LiteralField("FileUploadWarning",
"<p class=\"message notice\">" . _t("UserDefinedForm.FileUploadWarning",
"Files uploaded through this field could be publicly accessible if the exact URL is known")
. "</p>"), "Type");
$fields->addFieldToTab("Root.Main", new LiteralField("FileUploadWarning",
"<p class=\"message notice\">" . _t("UserDefinedForm.FileUploadWarning",
"Files uploaded through this field could be publicly accessible if the exact URL is known")
. "</p>"), "Type");
return $fields;
}
return $fields;
}
public function getFormField() {
public function getFormField()
{
$field = FileField::create($this->Name, $this->EscapedTitle)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsFileField');
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsFileField');
$field->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsFileField');
$field->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsFileField');
$field->getValidator()->setAllowedExtensions(
array_diff(
// filter out '' since this would be a regex problem on JS end
array_filter(Config::inst()->get('File', 'allowed_extensions')),
$this->config()->allowed_extensions_blacklist
)
);
$field->getValidator()->setAllowedExtensions(
array_diff(
// filter out '' since this would be a regex problem on JS end
array_filter(Config::inst()->get('File', 'allowed_extensions')),
$this->config()->allowed_extensions_blacklist
)
);
$folder = $this->Folder();
if($folder && $folder->exists()) {
$field->setFolderName(
preg_replace("/^assets\//","", $folder->Filename)
);
}
$folder = $this->Folder();
if ($folder && $folder->exists()) {
$field->setFolderName(
preg_replace("/^assets\//", "", $folder->Filename)
);
}
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
/**
* Return the value for the database, link to the file is stored as a
* relation so value for the field can be null.
*
* @return string
*/
public function getValueFromData() {
return null;
}
/**
* Return the value for the database, link to the file is stored as a
* relation so value for the field can be null.
*
* @return string
*/
public function getValueFromData()
{
return null;
}
public function getSubmittedFormField() {
return new SubmittedFileField();
}
public function getSubmittedFormField()
{
return new SubmittedFileField();
}
public function migrateSettings($data) {
// Migrate 'Folder' setting to 'FolderID'
if(isset($data['Folder'])) {
$this->FolderID = $data['Folder'];
unset($data['Folder']);
}
public function migrateSettings($data)
{
// Migrate 'Folder' setting to 'FolderID'
if (isset($data['Folder'])) {
$this->FolderID = $data['Folder'];
unset($data['Folder']);
}
parent::migrateSettings($data);
}
parent::migrateSettings($data);
}
}

View File

@ -17,380 +17,387 @@ use SilverStripe\Forms\SegmentField;
* @method UserDefinedForm Parent() Parent page
* @method DataList DisplayRules() List of EditableCustomRule objects
*/
class EditableFormField extends DataObject {
class EditableFormField extends DataObject
{
/**
* Set to true to hide from class selector
*
* @config
* @var bool
*/
private static $hidden = false;
/**
* Set to true to hide from class selector
*
* @config
* @var bool
*/
private static $hidden = false;
/**
* Define this field as abstract (not inherited)
*
* @config
* @var bool
*/
private static $abstract = true;
/**
* Define this field as abstract (not inherited)
*
* @config
* @var bool
*/
private static $abstract = true;
/**
* Flag this field type as non-data (e.g. literal, header, html)
*
* @config
* @var bool
*/
private static $literal = false;
/**
* Flag this field type as non-data (e.g. literal, header, html)
*
* @config
* @var bool
*/
private static $literal = false;
/**
* Default sort order
*
* @config
* @var string
*/
private static $default_sort = '"Sort"';
/**
* Default sort order
*
* @config
* @var string
*/
private static $default_sort = '"Sort"';
/**
* A list of CSS classes that can be added
*
* @var array
*/
public static $allowed_css = array();
/**
* A list of CSS classes that can be added
*
* @var array
*/
public static $allowed_css = array();
/**
* @config
* @var array
*/
private static $summary_fields = array(
'Title'
);
/**
* @config
* @var array
*/
private static $summary_fields = array(
'Title'
);
/**
* @config
* @var array
*/
private static $db = array(
"Name" => "Varchar",
"Title" => "Varchar(255)",
"Default" => "Varchar(255)",
"Sort" => "Int",
"Required" => "Boolean",
"CustomErrorMessage" => "Varchar(255)",
/**
* @config
* @var array
*/
private static $db = array(
"Name" => "Varchar",
"Title" => "Varchar(255)",
"Default" => "Varchar(255)",
"Sort" => "Int",
"Required" => "Boolean",
"CustomErrorMessage" => "Varchar(255)",
"CustomRules" => "Text", // @deprecated from 2.0
"CustomSettings" => "Text", // @deprecated from 2.0
"Migrated" => "Boolean", // set to true when migrated
"CustomRules" => "Text", // @deprecated from 2.0
"CustomSettings" => "Text", // @deprecated from 2.0
"Migrated" => "Boolean", // set to true when migrated
"ExtraClass" => "Text", // from CustomSettings
"RightTitle" => "Varchar(255)", // from CustomSettings
"ShowOnLoad" => "Boolean(1)", // from CustomSettings
);
private static $defaults = array(
'ShowOnLoad' => true,
);
"ExtraClass" => "Text", // from CustomSettings
"RightTitle" => "Varchar(255)", // from CustomSettings
"ShowOnLoad" => "Boolean(1)", // from CustomSettings
);
private static $defaults = array(
'ShowOnLoad' => true,
);
/**
* @config
* @var array
*/
private static $has_one = array(
"Parent" => "UserDefinedForm",
);
/**
* @config
* @var array
*/
private static $has_one = array(
"Parent" => "UserDefinedForm",
);
/**
* Built in extensions required
*
* @config
* @var array
*/
private static $extensions = array(
"Versioned('Stage', 'Live')"
);
/**
* Built in extensions required
*
* @config
* @var array
*/
private static $extensions = array(
"Versioned('Stage', 'Live')"
);
/**
* @config
* @var array
*/
private static $has_many = array(
"DisplayRules" => "EditableCustomRule.Parent" // from CustomRules
);
/**
* @config
* @var array
*/
private static $has_many = array(
"DisplayRules" => "EditableCustomRule.Parent" // from CustomRules
);
/**
* @var bool
*/
protected $readonly;
/**
* @var bool
*/
protected $readonly;
/**
* Set the visibility of an individual form field
*
* @param bool
*/
public function setReadonly($readonly = true) {
$this->readonly = $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;
}
/**
* Returns whether this field is readonly
*
* @return bool
*/
private function isReadonly()
{
return $this->readonly;
}
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = new FieldList(new TabSet('Root'));
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = new FieldList(new TabSet('Root'));
// Main tab
$fields->addFieldsToTab(
'Root.Main',
array(
ReadonlyField::create(
'Type',
_t('EditableFormField.TYPE', 'Type'),
$this->i18n_singular_name()
),
LiteralField::create(
'MergeField',
_t(
'EditableFormField.MERGEFIELDNAME',
'<div class="field readonly">' .
'<label class="left">Merge field</label>' .
'<div class="middleColumn">' .
'<span class="readonly">$' . $this->Name . '</span>' .
'</div>' .
'</div>'
)
),
TextField::create('Title'),
TextField::create('Default', _t('EditableFormField.DEFAULT', 'Default value')),
TextField::create('RightTitle', _t('EditableFormField.RIGHTTITLE', 'Right title')),
SegmentField::create('Name')->setModifiers(array(
UnderscoreSegmentFieldModifier::create()->setDefault('FieldName'),
DisambiguationSegmentFieldModifier::create(),
))->setPreview($this->Name)
)
);
// Main tab
$fields->addFieldsToTab(
'Root.Main',
array(
ReadonlyField::create(
'Type',
_t('EditableFormField.TYPE', 'Type'),
$this->i18n_singular_name()
),
LiteralField::create(
'MergeField',
_t(
'EditableFormField.MERGEFIELDNAME',
'<div class="field readonly">' .
'<label class="left">Merge field</label>' .
'<div class="middleColumn">' .
'<span class="readonly">$' . $this->Name . '</span>' .
'</div>' .
'</div>'
)
),
TextField::create('Title'),
TextField::create('Default', _t('EditableFormField.DEFAULT', 'Default value')),
TextField::create('RightTitle', _t('EditableFormField.RIGHTTITLE', 'Right title')),
SegmentField::create('Name')->setModifiers(array(
UnderscoreSegmentFieldModifier::create()->setDefault('FieldName'),
DisambiguationSegmentFieldModifier::create(),
))->setPreview($this->Name)
)
);
// Custom settings
if (!empty(self::$allowed_css)) {
$cssList = array();
foreach(self::$allowed_css as $k => $v) {
if (!is_array($v)) {
$cssList[$k]=$v;
} elseif ($k === $this->ClassName) {
$cssList = array_merge($cssList, $v);
}
}
// Custom settings
if (!empty(self::$allowed_css)) {
$cssList = array();
foreach (self::$allowed_css as $k => $v) {
if (!is_array($v)) {
$cssList[$k]=$v;
} elseif ($k === $this->ClassName) {
$cssList = array_merge($cssList, $v);
}
}
$fields->addFieldToTab('Root.Main',
DropdownField::create(
'ExtraClass',
_t('EditableFormField.EXTRACLASS_TITLE', 'Extra Styling/Layout'),
$cssList
)->setDescription(_t(
'EditableFormField.EXTRACLASS_SELECT',
'Select from the list of allowed styles'
))
);
} else {
$fields->addFieldToTab('Root.Main',
TextField::create(
'ExtraClass',
_t('EditableFormField.EXTRACLASS_Title', 'Extra CSS classes')
)->setDescription(_t(
'EditableFormField.EXTRACLASS_MULTIPLE',
'Separate each CSS class with a single space'
))
);
}
$fields->addFieldToTab('Root.Main',
DropdownField::create(
'ExtraClass',
_t('EditableFormField.EXTRACLASS_TITLE', 'Extra Styling/Layout'),
$cssList
)->setDescription(_t(
'EditableFormField.EXTRACLASS_SELECT',
'Select from the list of allowed styles'
))
);
} else {
$fields->addFieldToTab('Root.Main',
TextField::create(
'ExtraClass',
_t('EditableFormField.EXTRACLASS_Title', 'Extra CSS classes')
)->setDescription(_t(
'EditableFormField.EXTRACLASS_MULTIPLE',
'Separate each CSS class with a single space'
))
);
}
// Validation
$validationFields = $this->getFieldValidationOptions();
if($validationFields && $validationFields->count()) {
$fields->addFieldsToTab('Root.Validation', $validationFields);
}
// Validation
$validationFields = $this->getFieldValidationOptions();
if ($validationFields && $validationFields->count()) {
$fields->addFieldsToTab('Root.Validation', $validationFields);
}
// Add display rule fields
$displayFields = $this->getDisplayRuleFields();
if($displayFields && $displayFields->count()) {
$fields->addFieldsToTab('Root.DisplayRules', $displayFields);
}
// Add display rule fields
$displayFields = $this->getDisplayRuleFields();
if ($displayFields && $displayFields->count()) {
$fields->addFieldsToTab('Root.DisplayRules', $displayFields);
}
$this->extend('updateCMSFields', $fields);
$this->extend('updateCMSFields', $fields);
return $fields;
}
return $fields;
}
/**
* Return fields to display on the 'Display Rules' tab
*
* @return FieldList
*/
protected function getDisplayRuleFields() {
// Check display rules
if($this->Required) {
return new FieldList(
LabelField::create(_t(
'EditableFormField.DISPLAY_RULES_DISABLED',
'Display rules are not enabled for required fields. ' .
'Please uncheck "Is this field Required?" under "Validation" to re-enable.'
))->addExtraClass('message warning')
);
}
$self = $this;
$allowedClasses = array_keys($this->getEditableFieldClasses(false));
$editableColumns = new GridFieldEditableColumns();
$editableColumns->setDisplayFields(array(
'Display' => '',
'ConditionFieldID' => function($record, $column, $grid) use ($allowedClasses, $self) {
return DropdownField::create(
$column,
'',
EditableFormField::get()
->filter(array(
'ParentID' => $self->ParentID,
'ClassName' => $allowedClasses
))
->exclude(array(
'ID' => $self->ID
))
->map('ID', 'Title')
);
},
'ConditionOption' => function($record, $column, $grid) {
$options = Config::inst()->get('EditableCustomRule', 'condition_options');
return DropdownField::create($column, '', $options);
},
'FieldValue' => function($record, $column, $grid) {
return TextField::create($column);
},
'ParentID' => function($record, $column, $grid) use ($self) {
return HiddenField::create($column, '', $self->ID);
}
));
/**
* Return fields to display on the 'Display Rules' tab
*
* @return FieldList
*/
protected function getDisplayRuleFields()
{
// Check display rules
if ($this->Required) {
return new FieldList(
LabelField::create(_t(
'EditableFormField.DISPLAY_RULES_DISABLED',
'Display rules are not enabled for required fields. ' .
'Please uncheck "Is this field Required?" under "Validation" to re-enable.'
))->addExtraClass('message warning')
);
}
$self = $this;
$allowedClasses = array_keys($this->getEditableFieldClasses(false));
$editableColumns = new GridFieldEditableColumns();
$editableColumns->setDisplayFields(array(
'Display' => '',
'ConditionFieldID' => function ($record, $column, $grid) use ($allowedClasses, $self) {
return DropdownField::create(
$column,
'',
EditableFormField::get()
->filter(array(
'ParentID' => $self->ParentID,
'ClassName' => $allowedClasses
))
->exclude(array(
'ID' => $self->ID
))
->map('ID', 'Title')
);
},
'ConditionOption' => function ($record, $column, $grid) {
$options = Config::inst()->get('EditableCustomRule', 'condition_options');
return DropdownField::create($column, '', $options);
},
'FieldValue' => function ($record, $column, $grid) {
return TextField::create($column);
},
'ParentID' => function ($record, $column, $grid) use ($self) {
return HiddenField::create($column, '', $self->ID);
}
));
// Custom rules
$customRulesConfig = GridFieldConfig::create()
->addComponents(
$editableColumns,
new GridFieldButtonRow(),
new GridFieldToolbarHeader(),
new GridFieldAddNewInlineButton(),
new GridFieldDeleteAction()
);
// Custom rules
$customRulesConfig = GridFieldConfig::create()
->addComponents(
$editableColumns,
new GridFieldButtonRow(),
new GridFieldToolbarHeader(),
new GridFieldAddNewInlineButton(),
new GridFieldDeleteAction()
);
return new FieldList(
CheckboxField::create('ShowOnLoad')
->setDescription(_t(
'EditableFormField.SHOWONLOAD',
'Initial visibility before processing these rules'
)),
GridField::create(
'DisplayRules',
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
$this->DisplayRules(),
$customRulesConfig
)
);
}
return new FieldList(
CheckboxField::create('ShowOnLoad')
->setDescription(_t(
'EditableFormField.SHOWONLOAD',
'Initial visibility before processing these rules'
)),
GridField::create(
'DisplayRules',
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
$this->DisplayRules(),
$customRulesConfig
)
);
}
public function onBeforeWrite() {
parent::onBeforeWrite();
public function onBeforeWrite()
{
parent::onBeforeWrite();
// Set a field name.
if(!$this->Name) {
// New random name
$this->Name = $this->generateName();
// Set a field name.
if (!$this->Name) {
// New random name
$this->Name = $this->generateName();
} elseif ($this->Name === 'Field') {
throw new ValidationException('Field name cannot be "Field"');
}
} elseif($this->Name === 'Field') {
throw new ValidationException('Field name cannot be "Field"');
}
if (!$this->Sort && $this->ParentID) {
$parentID = $this->ParentID;
$this->Sort = EditableFormField::get()
->filter('ParentID', $parentID)
->max('Sort') + 1;
}
}
if(!$this->Sort && $this->ParentID) {
$parentID = $this->ParentID;
$this->Sort = EditableFormField::get()
->filter('ParentID', $parentID)
->max('Sort') + 1;
}
}
/**
* Generate a new non-conflicting Name value
*
* @return string
*/
protected function generateName()
{
do {
// Generate a new random name after this class
$class = get_class($this);
$entropy = substr(sha1(uniqid()), 0, 5);
$name = "{$class}_{$entropy}";
/**
* Generate a new non-conflicting Name value
*
* @return string
*/
protected function generateName() {
do {
// Generate a new random name after this class
$class = get_class($this);
$entropy = substr(sha1(uniqid()), 0, 5);
$name = "{$class}_{$entropy}";
// Check if it conflicts
$exists = EditableFormField::get()->filter('Name', $name)->count() > 0;
} while ($exists);
return $name;
}
// Check if it conflicts
$exists = EditableFormField::get()->filter('Name', $name)->count() > 0;
} while($exists);
return $name;
}
/**
* Flag indicating that this field will set its own error message via data-msg='' attributes
*
* @return bool
*/
public function getSetsOwnError()
{
return false;
}
/**
* 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 whether a user can delete this form field
* based on whether they can edit the page
*
* @param Member $member
* @return bool
*/
public function canDelete($member = null) {
return $this->canEdit($member);
}
* @return bool
*/
public function canDelete($member = null)
{
return $this->canEdit($member);
}
/**
* Return whether a user can edit this form field
* based on whether they can edit the page
*
/**
* Return whether a user can edit this form field
* based on whether they can edit the page
*
* @param Member $member
* @return bool
*/
public function canEdit($member = null) {
* @return bool
*/
public function canEdit($member = null)
{
$parent = $this->Parent();
if($parent && $parent->exists()) {
return $parent->canEdit($member) && !$this->isReadonly();
} else if (!$this->exists() && Controller::has_curr()) {
// This is for GridFieldOrderableRows support as it checks edit permissions on
// singleton of the class. Allows editing of User Defined Form pages by
// 'Content Authors' and those with permission to edit the UDF page. (ie. CanEditType/EditorGroups)
// This is to restore User Forms 2.x backwards compatibility.
$controller = Controller::curr();
if ($controller && $controller instanceof CMSPageEditController)
{
$parent = $controller->getRecord($controller->currentPageID());
// Only allow this behaviour on pages using UserFormFieldEditorExtension, such
// as UserDefinedForm page type.
if ($parent && $parent->hasExtension('UserFormFieldEditorExtension'))
{
return $parent->canEdit($member);
}
}
}
if ($parent && $parent->exists()) {
return $parent->canEdit($member) && !$this->isReadonly();
} elseif (!$this->exists() && Controller::has_curr()) {
// This is for GridFieldOrderableRows support as it checks edit permissions on
// singleton of the class. Allows editing of User Defined Form pages by
// 'Content Authors' and those with permission to edit the UDF page. (ie. CanEditType/EditorGroups)
// This is to restore User Forms 2.x backwards compatibility.
$controller = Controller::curr();
if ($controller && $controller instanceof CMSPageEditController) {
$parent = $controller->getRecord($controller->currentPageID());
// Only allow this behaviour on pages using UserFormFieldEditorExtension, such
// as UserDefinedForm page type.
if ($parent && $parent->hasExtension('UserFormFieldEditorExtension')) {
return $parent->canEdit($member);
}
}
}
// Fallback to secure admin permissions
return parent::canEdit($member);
}
return parent::canEdit($member);
}
/**
* Return whether a user can view this form field
@ -399,32 +406,34 @@ class EditableFormField extends DataObject {
* @param Member $member
* @return bool
*/
public function canView($member = null) {
$parent = $this->Parent();
if($parent && $parent->exists()) {
return $parent->canView($member);
}
public function canView($member = null)
{
$parent = $this->Parent();
if ($parent && $parent->exists()) {
return $parent->canView($member);
}
return true;
}
return true;
}
/**
* Return whether a user can create an object of this type
*
/**
* Return whether a user can create an object of this type
*
* @param Member $member
* @param array $context Virtual parameter to allow context to be passed in to check
* @return bool
*/
public function canCreate($member = null) {
// Check parent page
* @return bool
*/
public function canCreate($member = null)
{
// Check parent page
$parent = $this->getCanCreateContext(func_get_args());
if($parent) {
if ($parent) {
return $parent->canEdit($member);
}
// Fall back to secure admin permissions
return parent::canCreate($member);
}
}
/**
* Helper method to check the parent for this object
@ -432,13 +441,14 @@ class EditableFormField extends DataObject {
* @param array $args List of arguments passed to canCreate
* @return SiteTree Parent page instance
*/
protected function getCanCreateContext($args) {
protected function getCanCreateContext($args)
{
// Inspect second parameter to canCreate for a 'Parent' context
if(isset($args[1]['Parent'])) {
if (isset($args[1]['Parent'])) {
return $args[1]['Parent'];
}
// Hack in currently edited page if context is missing
if(Controller::has_curr() && Controller::curr() instanceof CMSMain) {
if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
return Controller::curr()->currentPage();
}
@ -452,7 +462,8 @@ class EditableFormField extends DataObject {
* @param Member $member
* @return bool
*/
public function canPublish($member = null) {
public function canPublish($member = null)
{
return $this->canEdit($member);
}
@ -462,445 +473,483 @@ class EditableFormField extends DataObject {
* @param Member $member
* @return bool
*/
public function canUnpublish($member = null) {
public function canUnpublish($member = null)
{
return $this->canDelete($member);
}
/**
* 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);
/**
* 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);
// Don't forget to publish the related custom rules...
foreach ($this->DisplayRules() as $rule) {
$rule->doPublish($fromStage, $toStage, $createNewVersion);
}
}
// Don't forget to publish the related custom rules...
foreach ($this->DisplayRules() as $rule) {
$rule->doPublish($fromStage, $toStage, $createNewVersion);
}
}
/**
* Delete this field from a given stage
*
* Wrapper for the {@link Versioned} deleteFromStage function
*/
public function doDeleteFromStage($stage) {
// Remove custom rules in this stage
$rules = Versioned::get_by_stage('EditableCustomRule', $stage)
->filter('ParentID', $this->ID);
foreach ($rules as $rule) {
$rule->deleteFromStage($stage);
}
/**
* Delete this field from a given stage
*
* Wrapper for the {@link Versioned} deleteFromStage function
*/
public function doDeleteFromStage($stage)
{
// Remove custom rules in this stage
$rules = Versioned::get_by_stage('EditableCustomRule', $stage)
->filter('ParentID', $this->ID);
foreach ($rules as $rule) {
$rule->deleteFromStage($stage);
}
// Remove record
$this->deleteFromStage($stage);
}
// Remove record
$this->deleteFromStage($stage);
}
/**
* checks wether record is new, copied from Sitetree
*/
function isNew() {
if(empty($this->ID)) return true;
/**
* checks wether record is new, copied from Sitetree
*/
public function isNew()
{
if (empty($this->ID)) {
return true;
}
if(is_numeric($this->ID)) return false;
if (is_numeric($this->ID)) {
return false;
}
return stripos($this->ID, 'new') === 0;
}
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;
/**
* 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);
$stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID);
$liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID);
return ($stageVersion && $stageVersion != $liveVersion);
}
return ($stageVersion && $stageVersion != $liveVersion);
}
/**
* @deprecated since version 4.0
*/
public function getSettings() {
Deprecation::notice('4.0', 'getSettings is deprecated');
return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
}
/**
* @deprecated since version 4.0
*/
public function getSettings()
{
Deprecation::notice('4.0', 'getSettings is deprecated');
return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
}
/**
* @deprecated since version 4.0
*/
public function setSettings($settings = array()) {
Deprecation::notice('4.0', 'setSettings is deprecated');
$this->CustomSettings = serialize($settings);
}
/**
* @deprecated since version 4.0
*/
public function setSettings($settings = array())
{
Deprecation::notice('4.0', 'setSettings is deprecated');
$this->CustomSettings = serialize($settings);
}
/**
* @deprecated since version 4.0
*/
public function setSetting($key, $value) {
Deprecation::notice('4.0', "setSetting({$key}) is deprecated");
$settings = $this->getSettings();
$settings[$key] = $value;
/**
* @deprecated since version 4.0
*/
public function setSetting($key, $value)
{
Deprecation::notice('4.0', "setSetting({$key}) is deprecated");
$settings = $this->getSettings();
$settings[$key] = $value;
$this->setSettings($settings);
}
$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)) {
foreach ($allowed as $k => $v) {
self::$allowed_css[$k] = (!is_null($v)) ? $v : $k;
}
}
}
/**
* 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)) {
foreach ($allowed as $k => $v) {
self::$allowed_css[$k] = (!is_null($v)) ? $v : $k;
}
}
}
/**
* @deprecated since version 4.0
*/
public function getSetting($setting) {
Deprecation::notice("4.0", "getSetting({$setting}) is deprecated");
/**
* @deprecated since version 4.0
*/
public function getSetting($setting)
{
Deprecation::notice("4.0", "getSetting({$setting}) is deprecated");
$settings = $this->getSettings();
if(isset($settings) && count($settings) > 0) {
if(isset($settings[$setting])) {
return $settings[$setting];
}
}
return '';
}
$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';
}
/**
* 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 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 whether or not this field needs to show the extra
* options dropdown list
*
* @return bool
*/
public function showExtraOptions()
{
return true;
}
/**
* Returns the Title for rendering in the front-end (with XML values escaped)
*
* @return string
*/
public function getEscapedTitle() {
return Convert::raw2xml($this->Title);
}
/**
* Returns the Title for rendering in the front-end (with XML values escaped)
*
* @return string
*/
public function getEscapedTitle()
{
return Convert::raw2xml($this->Title);
}
/**
* Find the numeric indicator (1.1.2) that represents it's nesting value
*
* Only useful for fields attached to a current page, and that contain other fields such as pages
* or groups
*
* @return string
*/
public function getFieldNumber() {
// Check if exists
if(!$this->exists()) {
return null;
}
// Check parent
$form = $this->Parent();
if(!$form || !$form->exists() || !($fields = $form->Fields())) {
return null;
}
/**
* Find the numeric indicator (1.1.2) that represents it's nesting value
*
* Only useful for fields attached to a current page, and that contain other fields such as pages
* or groups
*
* @return string
*/
public function getFieldNumber()
{
// Check if exists
if (!$this->exists()) {
return null;
}
// Check parent
$form = $this->Parent();
if (!$form || !$form->exists() || !($fields = $form->Fields())) {
return null;
}
$prior = 0; // Number of prior group at this level
$stack = array(); // Current stack of nested groups, where the top level = the page
foreach($fields->map('ID', 'ClassName') as $id => $className) {
if($className === 'EditableFormStep') {
$priorPage = empty($stack) ? $prior : $stack[0];
$stack = array($priorPage + 1);
$prior = 0;
} elseif($className === 'EditableFieldGroup') {
$stack[] = $prior + 1;
$prior = 0;
} elseif($className === 'EditableFieldGroupEnd') {
$prior = array_pop($stack);
}
if($id == $this->ID) {
return implode('.', $stack);
}
}
return null;
}
$prior = 0; // Number of prior group at this level
$stack = array(); // Current stack of nested groups, where the top level = the page
foreach ($fields->map('ID', 'ClassName') as $id => $className) {
if ($className === 'EditableFormStep') {
$priorPage = empty($stack) ? $prior : $stack[0];
$stack = array($priorPage + 1);
$prior = 0;
} elseif ($className === 'EditableFieldGroup') {
$stack[] = $prior + 1;
$prior = 0;
} elseif ($className === 'EditableFieldGroupEnd') {
$prior = array_pop($stack);
}
if ($id == $this->ID) {
return implode('.', $stack);
}
}
return null;
}
public function getCMSTitle() {
return $this->i18n_singular_name() . ' (' . $this->Title . ')';
}
public function getCMSTitle()
{
return $this->i18n_singular_name() . ' (' . $this->Title . ')';
}
/**
* @deprecated since version 4.0
*/
public function getFieldName($field = false) {
Deprecation::notice('4.0', "getFieldName({$field}) is deprecated");
return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
}
/**
* @deprecated since version 4.0
*/
public function getFieldName($field = false)
{
Deprecation::notice('4.0', "getFieldName({$field}) is deprecated");
return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
}
/**
* @deprecated since version 4.0
*/
public function getSettingName($field) {
Deprecation::notice('4.0', "getSettingName({$field}) is deprecated");
$name = $this->getFieldName('CustomSettings');
/**
* @deprecated since version 4.0
*/
public function getSettingName($field)
{
Deprecation::notice('4.0', "getSettingName({$field}) is deprecated");
$name = $this->getFieldName('CustomSettings');
return $name . '[' . $field .']';
}
return $name . '[' . $field .']';
}
/**
* Append custom validation fields to the default 'Validation'
* section in the editable options view
*
* @return FieldList
*/
public function getFieldValidationOptions() {
$fields = new FieldList(
CheckboxField::create('Required', _t('EditableFormField.REQUIRED', 'Is this field Required?'))
->setDescription(_t('EditableFormField.REQUIRED_DESCRIPTION', 'Please note that conditional fields can\'t be required')),
TextField::create('CustomErrorMessage', _t('EditableFormField.CUSTOMERROR','Custom Error Message'))
);
/**
* Append custom validation fields to the default 'Validation'
* section in the editable options view
*
* @return FieldList
*/
public function getFieldValidationOptions()
{
$fields = new FieldList(
CheckboxField::create('Required', _t('EditableFormField.REQUIRED', 'Is this field Required?'))
->setDescription(_t('EditableFormField.REQUIRED_DESCRIPTION', 'Please note that conditional fields can\'t be required')),
TextField::create('CustomErrorMessage', _t('EditableFormField.CUSTOMERROR', 'Custom Error Message'))
);
$this->extend('updateFieldValidationOptions', $fields);
$this->extend('updateFieldValidationOptions', $fields);
return $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 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);
}
/**
* Updates a formfield with extensions
*
* @param FormField $field
*/
public function doUpdateFormField($field) {
$this->extend('beforeUpdateFormField', $field);
$this->updateFormField($field);
$this->extend('afterUpdateFormField', $field);
}
/**
* Updates a formfield with extensions
*
* @param FormField $field
*/
public function doUpdateFormField($field)
{
$this->extend('beforeUpdateFormField', $field);
$this->updateFormField($field);
$this->extend('afterUpdateFormField', $field);
}
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field) {
// set the error / formatting messages
$field->setCustomValidationMessage($this->getErrorMessage()->RAW());
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field)
{
// set the error / formatting messages
$field->setCustomValidationMessage($this->getErrorMessage()->RAW());
// set the right title on this field
if($this->RightTitle) {
// Since this field expects raw html, safely escape the user data prior
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
}
// set the right title on this field
if ($this->RightTitle) {
// Since this field expects raw html, safely escape the user data prior
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
}
// if this field is required add some
if($this->Required) {
// Required validation can conflict so add the Required validation messages as input attributes
$errorMessage = $this->getErrorMessage()->HTML();
$field->addExtraClass('requiredField');
$field->setAttribute('data-rule-required', 'true');
$field->setAttribute('data-msg-required', $errorMessage);
// if this field is required add some
if ($this->Required) {
// Required validation can conflict so add the Required validation messages as input attributes
$errorMessage = $this->getErrorMessage()->HTML();
$field->addExtraClass('requiredField');
$field->setAttribute('data-rule-required', 'true');
$field->setAttribute('data-msg-required', $errorMessage);
if($identifier = UserDefinedForm::config()->required_identifier) {
$title = $field->Title() . " <span class='required-identifier'>". $identifier . "</span>";
$field->setTitle($title);
}
}
if ($identifier = UserDefinedForm::config()->required_identifier) {
$title = $field->Title() . " <span class='required-identifier'>". $identifier . "</span>";
$field->setTitle($title);
}
}
// if this field has an extra class
if($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
// if this field has an extra class
if ($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
/**
* Return the instance of the submission field class
*
* @return SubmittedFormField
*/
public function getSubmittedFormField() {
return new SubmittedFormField();
}
/**
* 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;
}
/**
* Show this form field (and its related value) in the reports and in emails.
*
* @return bool
*/
public function showInReports()
{
return true;
}
/**
* 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);
/**
* 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;
// only use CustomErrorMessage if it has a non empty value
$errorMessage = (!empty($this->CustomErrorMessage)) ? $this->CustomErrorMessage : $standard;
return DBField::create_field('Varchar', $errorMessage);
}
return DBField::create_field('Varchar', $errorMessage);
}
/**
* Invoked by UserFormUpgradeService to migrate settings specific to this field from CustomSettings
* to the field proper
*
* @param array $data Unserialised data
*/
public function migrateSettings($data) {
// Map 'Show' / 'Hide' to boolean
if(isset($data['ShowOnLoad'])) {
$this->ShowOnLoad = $data['ShowOnLoad'] === '' || ($data['ShowOnLoad'] && $data['ShowOnLoad'] !== 'Hide');
unset($data['ShowOnLoad']);
}
/**
* Invoked by UserFormUpgradeService to migrate settings specific to this field from CustomSettings
* to the field proper
*
* @param array $data Unserialised data
*/
public function migrateSettings($data)
{
// Map 'Show' / 'Hide' to boolean
if (isset($data['ShowOnLoad'])) {
$this->ShowOnLoad = $data['ShowOnLoad'] === '' || ($data['ShowOnLoad'] && $data['ShowOnLoad'] !== 'Hide');
unset($data['ShowOnLoad']);
}
// Migrate all other settings
foreach($data as $key => $value) {
if($this->hasField($key)) {
$this->setField($key, $value);
}
}
}
// Migrate all other settings
foreach ($data as $key => $value) {
if ($this->hasField($key)) {
$this->setField($key, $value);
}
}
}
/**
* Get the formfield to use when editing this inline in gridfield
*
* @param string $column name of column
* @param array $fieldClasses List of allowed classnames if this formfield has a selectable class
* @return FormField
*/
public function getInlineClassnameField($column, $fieldClasses) {
return DropdownField::create($column, false, $fieldClasses);
}
/**
* Get the formfield to use when editing this inline in gridfield
*
* @param string $column name of column
* @param array $fieldClasses List of allowed classnames if this formfield has a selectable class
* @return FormField
*/
public function getInlineClassnameField($column, $fieldClasses)
{
return DropdownField::create($column, false, $fieldClasses);
}
/**
* Get the formfield to use when editing the title inline
*
* @param string $column
* @return FormField
*/
public function getInlineTitleField($column) {
return TextField::create($column, false)
->setAttribute('placeholder', _t('EditableFormField.TITLE', 'Title'))
->setAttribute('data-placeholder', _t('EditableFormField.TITLE', 'Title'));
}
/**
* Get the formfield to use when editing the title inline
*
* @param string $column
* @return FormField
*/
public function getInlineTitleField($column)
{
return TextField::create($column, false)
->setAttribute('placeholder', _t('EditableFormField.TITLE', 'Title'))
->setAttribute('data-placeholder', _t('EditableFormField.TITLE', 'Title'));
}
/**
* Get the JS expression for selecting the holder for this field
*
* @return string
*/
public function getSelectorHolder() {
return "$(\"#{$this->Name}\")";
}
/**
* Get the JS expression for selecting the holder for this field
*
* @return string
*/
public function getSelectorHolder()
{
return "$(\"#{$this->Name}\")";
}
/**
* Gets the JS expression for selecting the value for this field
*
* @param EditableCustomRule $rule Custom rule this selector will be used with
* @param bool $forOnLoad Set to true if this will be invoked on load
*/
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) {
return "$(\"input[name='{$this->Name}']\")";
}
/**
* Gets the JS expression for selecting the value for this field
*
* @param EditableCustomRule $rule Custom rule this selector will be used with
* @param bool $forOnLoad Set to true if this will be invoked on load
*/
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
{
return "$(\"input[name='{$this->Name}']\")";
}
/**
* Get the list of classes that can be selected and used as data-values
*
* @param $includeLiterals Set to false to exclude non-data fields
* @return array
*/
public function getEditableFieldClasses($includeLiterals = true) {
$classes = ClassInfo::getValidSubClasses('EditableFormField');
/**
* Get the list of classes that can be selected and used as data-values
*
* @param $includeLiterals Set to false to exclude non-data fields
* @return array
*/
public function getEditableFieldClasses($includeLiterals = true)
{
$classes = ClassInfo::getValidSubClasses('EditableFormField');
// Remove classes we don't want to display in the dropdown.
$editableFieldClasses = array();
foreach ($classes as $class) {
// Skip abstract / hidden classes
if(Config::inst()->get($class, 'abstract', Config::UNINHERITED) || Config::inst()->get($class, 'hidden')
) {
continue;
}
// Remove classes we don't want to display in the dropdown.
$editableFieldClasses = array();
foreach ($classes as $class) {
// Skip abstract / hidden classes
if (Config::inst()->get($class, 'abstract', Config::UNINHERITED) || Config::inst()->get($class, 'hidden')
) {
continue;
}
if(!$includeLiterals && Config::inst()->get($class, 'literal')) {
continue;
}
if (!$includeLiterals && Config::inst()->get($class, 'literal')) {
continue;
}
$singleton = singleton($class);
if(!$singleton->canCreate()) {
continue;
}
$singleton = singleton($class);
if (!$singleton->canCreate()) {
continue;
}
$editableFieldClasses[$class] = $singleton->i18n_singular_name();
}
$editableFieldClasses[$class] = $singleton->i18n_singular_name();
}
asort($editableFieldClasses);
return $editableFieldClasses;
}
asort($editableFieldClasses);
return $editableFieldClasses;
}
/**
* @return EditableFormFieldValidator
*/
public function getCMSValidator() {
return EditableFormFieldValidator::create()
->setRecord($this);
}
/**
* Determine effective display rules for this field.
*
* @return SS_List
*/
public function EffectiveDisplayRules() {
if($this->Required) {
return new ArrayList();
}
return $this->DisplayRules();
}
/**
* @return EditableFormFieldValidator
*/
public function getCMSValidator()
{
return EditableFormFieldValidator::create()
->setRecord($this);
}
/**
* Determine effective display rules for this field.
*
* @return SS_List
*/
public function EffectiveDisplayRules()
{
if ($this->Required) {
return new ArrayList();
}
return $this->DisplayRules();
}
}

View File

@ -1,61 +1,65 @@
<?php
class EditableFormFieldValidator extends RequiredFields {
class EditableFormFieldValidator extends RequiredFields
{
/**
*
* @var EditableFormField
*/
protected $record = null;
/**
*
* @var EditableFormField
*/
protected $record = null;
/**
*
* @param EditableFormField $record
* @return $this
*/
public function setRecord($record) {
$this->record = $record;
return $this;
}
/**
*
* @param EditableFormField $record
* @return $this
*/
public function setRecord($record)
{
$this->record = $record;
return $this;
}
/*
* @return EditableFormField
*/
public function getRecord() {
return $this->record;
}
/*
* @return EditableFormField
*/
public function getRecord()
{
return $this->record;
}
public function php($data) {
if(!parent::php($data)) {
return false;
}
public function php($data)
{
if (!parent::php($data)) {
return false;
}
// Skip unsaved records
if(!$this->record || !$this->record->exists()) {
return true;
}
// Skip unsaved records
if (!$this->record || !$this->record->exists()) {
return true;
}
// Skip validation if not required
if(empty($data['Required'])) {
return;
}
// Skip validation if not required
if (empty($data['Required'])) {
return;
}
// Skip validation if no rules
$count = EditableCustomRule::get()->filter('ParentID', $this->record->ID)->count();
if($count == 0) {
return true;
}
// Skip validation if no rules
$count = EditableCustomRule::get()->filter('ParentID', $this->record->ID)->count();
if ($count == 0) {
return true;
}
// Both required = true and rules > 0 should error
$this->validationError(
'Required_Error',
_t(
"EditableFormFieldValidator.REQUIRED_ERROR",
"Form fields cannot be required and have conditional display rules."
),
'error'
);
return false;
}
// Both required = true and rules > 0 should error
$this->validationError(
'Required_Error',
_t(
"EditableFormFieldValidator.REQUIRED_ERROR",
"Form fields cannot be required and have conditional display rules."
),
'error'
);
return false;
}
}

View File

@ -5,89 +5,97 @@
* @package userforms
*/
class EditableFormHeading extends EditableFormField {
class EditableFormHeading extends EditableFormField
{
private static $singular_name = 'Heading';
private static $singular_name = 'Heading';
private static $plural_name = 'Headings';
private static $plural_name = 'Headings';
private static $literal = true;
private static $literal = true;
private static $db = array(
'Level' => 'Int(3)', // From CustomSettings
'HideFromReports' => 'Boolean(0)' // from CustomSettings
);
private static $db = array(
'Level' => 'Int(3)', // From CustomSettings
'HideFromReports' => 'Boolean(0)' // from CustomSettings
);
private static $defaults = array(
'Level' => 3,
'HideFromReports' => false
);
private static $defaults = array(
'Level' => 3,
'HideFromReports' => false
);
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName(array('Default', 'Validation', 'RightTitle'));
$fields->removeByName(array('Default', 'Validation', 'RightTitle'));
$levels = array(
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6'
);
$levels = array(
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6'
);
$fields->addFieldsToTab('Root.Main', array(
DropdownField::create(
'Level',
_t('EditableFormHeading.LEVEL', 'Select Heading Level'),
$levels
),
CheckboxField::create(
'HideFromReports',
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?')
)
));
$fields->addFieldsToTab('Root.Main', array(
DropdownField::create(
'Level',
_t('EditableFormHeading.LEVEL', 'Select Heading Level'),
$levels
),
CheckboxField::create(
'HideFromReports',
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?')
)
));
return $fields;
}
return $fields;
}
public function getFormField() {
$labelField = new HeaderField($this->Name, $this->EscapedTitle, $this->Level);
$labelField->addExtraClass('FormHeading');
$labelField->setAttribute('data-id', $this->Name);
$this->doUpdateFormField($labelField);
return $labelField;
}
public function getFormField()
{
$labelField = new HeaderField($this->Name, $this->EscapedTitle, $this->Level);
$labelField->addExtraClass('FormHeading');
$labelField->setAttribute('data-id', $this->Name);
$this->doUpdateFormField($labelField);
return $labelField;
}
protected function updateFormField($field) {
// set the right title on this field
if($this->RightTitle) {
// Since this field expects raw html, safely escape the user data prior
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
}
// if this field has an extra class
if($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
protected function updateFormField($field)
{
// set the right title on this field
if ($this->RightTitle) {
// Since this field expects raw html, safely escape the user data prior
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
}
// if this field has an extra class
if ($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
public function showInReports() {
return !$this->HideFromReports;
}
public function showInReports()
{
return !$this->HideFromReports;
}
public function getFieldValidationOptions() {
return false;
}
public function getFieldValidationOptions()
{
return false;
}
public function getSelectorHolder() {
return "$(\":header[data-id='{$this->Name}']\")";
}
public function getSelectorHolder()
{
return "$(\":header[data-id='{$this->Name}']\")";
}
public function getLevel() {
return $this->getField('Level') ?: 3;
}
public function getLevel()
{
return $this->getField('Level') ?: 3;
}
}

View File

@ -4,83 +4,91 @@
*
* @package userforms
*/
class EditableFormStep extends EditableFormField {
class EditableFormStep extends EditableFormField
{
private static $singular_name = 'Page Break';
private static $singular_name = 'Page Break';
private static $plural_name = 'Page Breaks';
private static $plural_name = 'Page Breaks';
/**
* Disable selection of step class
*
* @config
* @var bool
*/
private static $hidden = true;
/**
* Disable selection of step class
*
* @config
* @var bool
*/
private static $hidden = true;
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'RightTitle'));
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'RightTitle'));
return $fields;
}
return $fields;
}
/**
* @return FormField
*/
public function getFormField() {
$field = UserFormsStepField::create()
->setName($this->Name)
->setTitle($this->EscapedTitle);
$this->doUpdateFormField($field);
return $field;
}
/**
* @return FormField
*/
public function getFormField()
{
$field = UserFormsStepField::create()
->setName($this->Name)
->setTitle($this->EscapedTitle);
$this->doUpdateFormField($field);
return $field;
}
protected function updateFormField($field) {
// if this field has an extra class
if($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
protected function updateFormField($field)
{
// if this field has an extra class
if ($this->ExtraClass) {
$field->addExtraClass($this->ExtraClass);
}
}
/**
* @return boolean
*/
public function showInReports() {
return false;
}
/**
* @return boolean
*/
public function showInReports()
{
return false;
}
public function getInlineClassnameField($column, $fieldClasses) {
return new LabelField(
$column,
$this->CMSTitle
);
}
public function getInlineClassnameField($column, $fieldClasses)
{
return new LabelField(
$column,
$this->CMSTitle
);
}
public function getCMSTitle() {
$title = $this->getFieldNumber()
?: $this->Title
?: '';
public function getCMSTitle()
{
$title = $this->getFieldNumber()
?: $this->Title
?: '';
return _t(
'EditableFormStep.STEP_TITLE',
'Page {page}',
array(
'page' => $title
)
);
}
return _t(
'EditableFormStep.STEP_TITLE',
'Page {page}',
array(
'page' => $title
)
);
}
/**
* Get the JS expression for selecting the holder for this field
*
* @return string
*/
public function getSelectorHolder() {
return "$(\".step-button-wrapper[data-for='{$this->Name}']\")";
}
/**
* Get the JS expression for selecting the holder for this field
*
* @return string
*/
public function getSelectorHolder()
{
return "$(\".step-button-wrapper[data-for='{$this->Name}']\")";
}
}

View File

@ -7,142 +7,154 @@
* @package userforms
*/
class EditableLiteralField extends EditableFormField {
class EditableLiteralField extends EditableFormField
{
private static $singular_name = 'HTML Block';
private static $singular_name = 'HTML Block';
private static $plural_name = 'HTML Blocks';
private static $plural_name = 'HTML Blocks';
/**
* Mark as literal only
*
* @config
* @var bool
*/
private static $literal = true;
/**
* Mark as literal only
*
* @config
* @var bool
*/
private static $literal = true;
/**
* Get the name of the editor config to use for HTML sanitisation. Defaults to the active config.
*
* @var string
* @config
*/
private static $editor_config = null;
/**
* Get the name of the editor config to use for HTML sanitisation. Defaults to the active config.
*
* @var string
* @config
*/
private static $editor_config = null;
private static $db = array(
'Content' => 'HTMLText', // From CustomSettings
'HideFromReports' => 'Boolean(0)', // from CustomSettings
'HideLabel' => 'Boolean(0)'
);
private static $db = array(
'Content' => 'HTMLText', // From CustomSettings
'HideFromReports' => 'Boolean(0)', // from CustomSettings
'HideLabel' => 'Boolean(0)'
);
private static $defaults = array(
'HideFromReports' => false
);
private static $defaults = array(
'HideFromReports' => false
);
/**
* Returns the {@see HtmlEditorConfig} instance to use for sanitisation
*
* @return HtmlEditorConfig
*/
protected function getEditorConfig() {
$editorConfig = $this->config()->editor_config;
if($editorConfig) return HtmlEditorConfig::get($editorConfig);
return HtmlEditorConfig::get_active();
}
/**
* Returns the {@see HtmlEditorConfig} instance to use for sanitisation
*
* @return HtmlEditorConfig
*/
protected function getEditorConfig()
{
$editorConfig = $this->config()->editor_config;
if ($editorConfig) {
return HtmlEditorConfig::get($editorConfig);
}
return HtmlEditorConfig::get_active();
}
/**
* Safely sanitise html content, if enabled
*
* @param string $content Raw html
* @return string Safely sanitised html
*/
protected function sanitiseContent($content) {
// Check if sanitisation is enabled
if(!HtmlEditorField::config()->sanitise_server_side) return $content;
/**
* Safely sanitise html content, if enabled
*
* @param string $content Raw html
* @return string Safely sanitised html
*/
protected function sanitiseContent($content)
{
// Check if sanitisation is enabled
if (!HtmlEditorField::config()->sanitise_server_side) {
return $content;
}
// Perform sanitisation
$htmlValue = Injector::inst()->create('HTMLValue', $content);
$santiser = Injector::inst()->create('HtmlEditorSanitiser', $this->getEditorConfig());
$santiser->sanitise($htmlValue);
return $htmlValue->getContent();
}
// Perform sanitisation
$htmlValue = Injector::inst()->create('HTMLValue', $content);
$santiser = Injector::inst()->create('HtmlEditorSanitiser', $this->getEditorConfig());
$santiser->sanitise($htmlValue);
return $htmlValue->getContent();
}
/**
* Get HTML Content of this literal field
*
* @return string
*/
public function getContent() {
// Apply html editor sanitisation rules
$content = $this->getField('Content');
return $this->sanitiseContent($content);
}
/**
* Get HTML Content of this literal field
*
* @return string
*/
public function getContent()
{
// Apply html editor sanitisation rules
$content = $this->getField('Content');
return $this->sanitiseContent($content);
}
/**
* Set the content with the given value
*
* @param string $content
*/
public function setContent($content) {
// Apply html editor sanitisation rules
$content = $this->sanitiseContent($content);
$this->setField('Content', $content);
}
/**
* Set the content with the given value
*
* @param string $content
*/
public function setContent($content)
{
// Apply html editor sanitisation rules
$content = $this->sanitiseContent($content);
$this->setField('Content', $content);
}
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName(array('Default', 'Validation', 'RightTitle'));
$fields->removeByName(array('Default', 'Validation', 'RightTitle'));
$fields->addFieldsToTab('Root.Main', array(
HTMLEditorField::create('Content', _t('EditableLiteralField.CONTENT', 'HTML'))
->setRows(4)
->setColumns(20),
CheckboxField::create(
'HideFromReports',
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?')
),
CheckboxField::create(
'HideLabel',
_t('EditableLiteralField.HIDELABEL', "Hide 'Title' label on frontend?")
)
));
$fields->addFieldsToTab('Root.Main', array(
HTMLEditorField::create('Content', _t('EditableLiteralField.CONTENT', 'HTML'))
->setRows(4)
->setColumns(20),
CheckboxField::create(
'HideFromReports',
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?')
),
CheckboxField::create(
'HideLabel',
_t('EditableLiteralField.HIDELABEL', "Hide 'Title' label on frontend?")
)
));
return $fields;
}
return $fields;
}
public function getFormField() {
// Build label and css classes
$label = '';
$classes = $this->ExtraClass;
if(empty($this->Title) || $this->HideLabel) {
$classes .= " nolabel";
} else {
$label = "<label class='left'>{$this->EscapedTitle}</label>";
}
public function getFormField()
{
// Build label and css classes
$label = '';
$classes = $this->ExtraClass;
if (empty($this->Title) || $this->HideLabel) {
$classes .= " nolabel";
} else {
$label = "<label class='left'>{$this->EscapedTitle}</label>";
}
$field = new LiteralField(
"LiteralField[{$this->ID}]",
sprintf(
"<div id='%s' class='field text %s'>
$field = new LiteralField(
"LiteralField[{$this->ID}]",
sprintf(
"<div id='%s' class='field text %s'>
%s
<div class='middleColumn literalFieldArea'>%s</div>".
"</div>",
Convert::raw2htmlname($this->Name),
Convert::raw2att($classes),
$label,
$this->Content
)
);
"</div>",
Convert::raw2htmlname($this->Name),
Convert::raw2att($classes),
$label,
$this->Content
)
);
// When dealing with literal fields there is no further customisation that can be added at this point
return $field;
}
// When dealing with literal fields there is no further customisation that can be added at this point
return $field;
}
public function showInReports() {
return ! $this->HideFromReports;
}
public function showInReports()
{
return ! $this->HideFromReports;
}
}

View File

@ -5,55 +5,59 @@
* @package userforms
*/
class EditableMemberListField extends EditableFormField {
class EditableMemberListField extends EditableFormField
{
private static $singular_name = 'Member List Field';
private static $singular_name = 'Member List Field';
private static $plural_name = 'Member List Fields';
private static $plural_name = 'Member List Fields';
private static $has_one = array(
'Group' => 'Group'
);
private static $has_one = array(
'Group' => 'Group'
);
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName('Default');
$fields->removeByName('Validation');
$fields->removeByName('Default');
$fields->removeByName('Validation');
$fields->addFieldToTab(
'Root.Main',
DropdownField::create(
"GroupID",
_t('EditableFormField.GROUP', 'Group'),
Group::get()->map()
)->setEmptyString(' ')
);
$fields->addFieldToTab(
'Root.Main',
DropdownField::create(
"GroupID",
_t('EditableFormField.GROUP', 'Group'),
Group::get()->map()
)->setEmptyString(' ')
);
return $fields;
}
return $fields;
}
public function getFormField() {
if(empty($this->GroupID)) {
return false;
}
public function getFormField()
{
if (empty($this->GroupID)) {
return false;
}
$members = Member::map_in_groups($this->GroupID);
$field = new DropdownField($this->Name, $this->EscapedTitle, $members);
$this->doUpdateFormField($field);
return $field;
}
$members = Member::map_in_groups($this->GroupID);
$field = new DropdownField($this->Name, $this->EscapedTitle, $members);
$this->doUpdateFormField($field);
return $field;
}
public function getValueFromData($data) {
if(isset($data[$this->Name])) {
$memberID = $data[$this->Name];
$member = Member::get()->byID($memberID);
return $member ? $member->getName() : "";
}
public function getValueFromData($data)
{
if (isset($data[$this->Name])) {
$memberID = $data[$this->Name];
$member = Member::get()->byID($memberID);
return $member ? $member->getName() : "";
}
return false;
}
}
return false;
}
}

View File

@ -13,183 +13,192 @@
* @package userforms
*/
class EditableMultipleOptionField extends EditableFormField {
class EditableMultipleOptionField extends EditableFormField
{
/**
* Define this field as abstract (not inherited)
*
* @config
* @var bool
*/
private static $abstract = true;
/**
* Define this field as abstract (not inherited)
*
* @config
* @var bool
*/
private static $abstract = true;
private static $has_many = array(
"Options" => "EditableOption"
);
private static $has_many = array(
"Options" => "EditableOption"
);
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$editableColumns = new GridFieldEditableColumns();
$editableColumns->setDisplayFields(array(
'Title' => array(
'title' => _t('EditableMultipleOptionField.TITLE', 'Title'),
'callback' => function($record, $column, $grid) {
return TextField::create($column);
}
),
'Value' => array(
'title' => _t('EditableMultipleOptionField.VALUE', 'Value'),
'callback' => function($record, $column, $grid) {
$editableColumns = new GridFieldEditableColumns();
$editableColumns->setDisplayFields(array(
'Title' => array(
'title' => _t('EditableMultipleOptionField.TITLE', 'Title'),
'callback' => function ($record, $column, $grid) {
return TextField::create($column);
}
),
'Default' => array(
'title' => _t('EditableMultipleOptionField.DEFAULT', 'Selected by default?'),
'callback' => function($record, $column, $grid) {
return CheckboxField::create($column);
}
)
));
'Value' => array(
'title' => _t('EditableMultipleOptionField.VALUE', 'Value'),
'callback' => function ($record, $column, $grid) {
return TextField::create($column);
}
),
'Default' => array(
'title' => _t('EditableMultipleOptionField.DEFAULT', 'Selected by default?'),
'callback' => function ($record, $column, $grid) {
return CheckboxField::create($column);
}
)
));
$optionsConfig = GridFieldConfig::create()
->addComponents(
new GridFieldToolbarHeader(),
new GridFieldTitleHeader(),
new GridFieldOrderableRows('Sort'),
$editableColumns,
new GridFieldButtonRow(),
new GridFieldAddNewInlineButton(),
new GridFieldDeleteAction()
);
$optionsConfig = GridFieldConfig::create()
->addComponents(
new GridFieldToolbarHeader(),
new GridFieldTitleHeader(),
new GridFieldOrderableRows('Sort'),
$editableColumns,
new GridFieldButtonRow(),
new GridFieldAddNewInlineButton(),
new GridFieldDeleteAction()
);
$optionsGrid = GridField::create(
'Options',
_t('EditableFormField.CUSTOMOPTIONS', 'Options'),
$this->Options(),
$optionsConfig
);
$optionsGrid = GridField::create(
'Options',
_t('EditableFormField.CUSTOMOPTIONS', 'Options'),
$this->Options(),
$optionsConfig
);
$fields->insertAfter(new Tab('Options', _t('EditableMultipleOptionField.OPTIONSTAB','Options')), 'Main');
$fields->addFieldToTab('Root.Options', $optionsGrid);
$fields->insertAfter(new Tab('Options', _t('EditableMultipleOptionField.OPTIONSTAB', 'Options')), 'Main');
$fields->addFieldToTab('Root.Options', $optionsGrid);
return $fields;
}
return $fields;
}
/**
* Publishing Versioning support.
*
* When publishing it needs to handle copying across / publishing
* each of the individual field options
*
* @return void
*/
public function doPublish($fromStage, $toStage, $createNewVersion = false) {
$live = Versioned::get_by_stage("EditableOption", "Live", "\"EditableOption\".\"ParentID\" = $this->ID");
/**
* Publishing Versioning support.
*
* When publishing it needs to handle copying across / publishing
* each of the individual field options
*
* @return void
*/
public function doPublish($fromStage, $toStage, $createNewVersion = false)
{
$live = Versioned::get_by_stage("EditableOption", "Live", "\"EditableOption\".\"ParentID\" = $this->ID");
if($live) {
foreach($live as $option) {
$option->delete();
}
}
if ($live) {
foreach ($live as $option) {
$option->delete();
}
}
if($this->Options()) {
foreach($this->Options() as $option) {
$option->publish($fromStage, $toStage, $createNewVersion);
}
}
if ($this->Options()) {
foreach ($this->Options() as $option) {
$option->publish($fromStage, $toStage, $createNewVersion);
}
}
parent::doPublish($fromStage, $toStage, $createNewVersion);
}
parent::doPublish($fromStage, $toStage, $createNewVersion);
}
/**
* Unpublishing Versioning support
*
* When unpublishing the field it has to remove all options attached
*
* @return void
*/
public function doDeleteFromStage($stage) {
// Remove options
$options = Versioned::get_by_stage('EditableOption', $stage)
->filter('ParentID', $this->ID);
foreach($options as $option) {
$option->deleteFromStage($stage);
}
/**
* Unpublishing Versioning support
*
* When unpublishing the field it has to remove all options attached
*
* @return void
*/
public function doDeleteFromStage($stage)
{
// Remove options
$options = Versioned::get_by_stage('EditableOption', $stage)
->filter('ParentID', $this->ID);
foreach ($options as $option) {
$option->deleteFromStage($stage);
}
parent::doDeleteFromStage($stage);
}
parent::doDeleteFromStage($stage);
}
/**
* Deletes all the options attached to this field before deleting the
* field. Keeps stray options from floating around
*
* @return void
*/
public function delete() {
$options = $this->Options();
/**
* Deletes all the options attached to this field before deleting the
* field. Keeps stray options from floating around
*
* @return void
*/
public function delete()
{
$options = $this->Options();
if($options) {
foreach($options as $option) {
$option->delete();
}
}
if ($options) {
foreach ($options as $option) {
$option->delete();
}
}
parent::delete();
}
parent::delete();
}
/**
* Duplicate a pages content. We need to make sure all the fields attached
* to that page go with it
*
* @return DataObject
*/
public function duplicate($doWrite = true) {
$clonedNode = parent::duplicate();
/**
* Duplicate a pages content. We need to make sure all the fields attached
* to that page go with it
*
* @return DataObject
*/
public function duplicate($doWrite = true)
{
$clonedNode = parent::duplicate();
foreach($this->Options() as $field) {
$newField = $field->duplicate(false);
$newField->ParentID = $clonedNode->ID;
$newField->Version = 0;
$newField->write();
}
foreach ($this->Options() as $field) {
$newField = $field->duplicate(false);
$newField->ParentID = $clonedNode->ID;
$newField->Version = 0;
$newField->write();
}
return $clonedNode;
}
return $clonedNode;
}
/**
* Return whether or not this field has addable options such as a
* {@link EditableDropdownField} or {@link EditableRadioField}
*
* @return bool
*/
public function getHasAddableOptions() {
return true;
}
/**
* Return whether or not this field has addable options such as a
* {@link EditableDropdownField} or {@link EditableRadioField}
*
* @return bool
*/
public function getHasAddableOptions()
{
return true;
}
/**
* Gets map of field options suitable for use in a form
*
* @return array
*/
protected function getOptionsMap() {
$optionSet = $this->Options();
$optionMap = $optionSet->map('Value', 'Title');
if($optionMap instanceof SS_Map) {
return $optionMap->toArray();
}
return $optionMap;
}
/**
* Gets map of field options suitable for use in a form
*
* @return array
*/
protected function getOptionsMap()
{
$optionSet = $this->Options();
$optionMap = $optionSet->map('Value', 'Title');
if ($optionMap instanceof SS_Map) {
return $optionMap->toArray();
}
return $optionMap;
}
/**
* Returns all default options
*
* @return SS_List
*/
protected function getDefaultOptions() {
return $this->Options()->filter('Default', 1);
}
/**
* Returns all default options
*
* @return SS_List
*/
protected function getDefaultOptions()
{
return $this->Options()->filter('Default', 1);
}
}

View File

@ -7,81 +7,87 @@
* @package userforms
*/
class EditableNumericField extends EditableFormField {
class EditableNumericField extends EditableFormField
{
private static $singular_name = 'Numeric Field';
private static $singular_name = 'Numeric Field';
private static $plural_name = 'Numeric Fields';
private static $plural_name = 'Numeric Fields';
private static $db = array(
'MinValue' => 'Int',
'MaxValue' => 'Int',
'Placeholder' => 'Varchar(255)'
);
private static $db = array(
'MinValue' => 'Int',
'MaxValue' => 'Int',
'Placeholder' => 'Varchar(255)'
);
public function getSetsOwnError() {
return true;
}
public function getSetsOwnError()
{
return true;
}
public function getCMSFields() {
$this->beforeUpdateCMSFields(function($fields) {
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'Placeholder',
_t('EditableTextField.PLACEHOLDER', 'Placeholder')
)
);
});
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function ($fields) {
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'Placeholder',
_t('EditableTextField.PLACEHOLDER', 'Placeholder')
)
);
});
return parent::getCMSFields();
}
return parent::getCMSFields();
}
/**
* @return NumericField
*/
public function getFormField() {
$field = NumericField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField')
->addExtraClass('number');
/**
* @return NumericField
*/
public function getFormField()
{
$field = NumericField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField')
->addExtraClass('number');
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
public function getFieldValidationOptions() {
$fields = parent::getFieldValidationOptions();
$fields->push(FieldGroup::create(
_t("EditableNumericField.RANGE", "Allowed numeric range"),
array(
new NumericField('MinValue', false),
new LiteralField('RangeValue', _t("EditableNumericField.RANGE_TO", "to")),
new NumericField('MaxValue', false)
)
));
return $fields;
}
public function getFieldValidationOptions()
{
$fields = parent::getFieldValidationOptions();
$fields->push(FieldGroup::create(
_t("EditableNumericField.RANGE", "Allowed numeric range"),
array(
new NumericField('MinValue', false),
new LiteralField('RangeValue', _t("EditableNumericField.RANGE_TO", "to")),
new NumericField('MaxValue', false)
)
));
return $fields;
}
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field) {
parent::updateFormField($field);
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field)
{
parent::updateFormField($field);
if($this->MinValue) {
$field->setAttribute('data-rule-min', $this->MinValue);
}
if ($this->MinValue) {
$field->setAttribute('data-rule-min', $this->MinValue);
}
if($this->MaxValue) {
$field->setAttribute('data-rule-max', $this->MaxValue);
}
if ($this->MaxValue) {
$field->setAttribute('data-rule-max', $this->MaxValue);
}
if($this->Placeholder) {
$field->setAttribute('placeholder', $this->Placeholder);
}
}
if ($this->Placeholder) {
$field->setAttribute('placeholder', $this->Placeholder);
}
}
}

View File

@ -7,30 +7,31 @@
* @method EditableMultipleOptionField Parent()
* @package userforms
*/
class EditableOption extends DataObject {
class EditableOption extends DataObject
{
private static $default_sort = "Sort";
private static $default_sort = "Sort";
private static $db = array(
"Name" => "Varchar(255)",
"Title" => "Varchar(255)",
"Default" => "Boolean",
private static $db = array(
"Name" => "Varchar(255)",
"Title" => "Varchar(255)",
"Default" => "Boolean",
"Sort" => "Int",
"Value" => "Varchar(255)",
);
);
private static $has_one = array(
"Parent" => "EditableMultipleOptionField",
);
private static $has_one = array(
"Parent" => "EditableMultipleOptionField",
);
private static $extensions = array(
"Versioned('Stage', 'Live')"
);
private static $extensions = array(
"Versioned('Stage', 'Live')"
);
private static $summary_fields = array(
'Title',
'Default'
);
private static $summary_fields = array(
'Title',
'Default'
);
protected static $allow_empty_values = false;
@ -39,7 +40,8 @@ class EditableOption extends DataObject {
*
* @return boolean
*/
public static function allow_empty_values() {
public static function allow_empty_values()
{
return (bool) self::$allow_empty_values;
}
@ -48,57 +50,63 @@ class EditableOption extends DataObject {
*
* @param boolean $allow
*/
public static function set_allow_empty_values($allow) {
public static function set_allow_empty_values($allow)
{
self::$allow_empty_values = (bool) $allow;
}
/**
* @param Member $member
*
* @return boolean
*/
public function canEdit($member = null) {
return $this->Parent()->canEdit($member);
}
/**
* @param Member $member
*
* @return boolean
*/
public function canEdit($member = null)
{
return $this->Parent()->canEdit($member);
}
/**
* @param Member $member
*
* @return boolean
*/
public function canDelete($member = null) {
return $this->canEdit($member);
}
/**
* @param Member $member
*
* @return boolean
*/
public function canDelete($member = null)
{
return $this->canEdit($member);
}
public function getEscapedTitle() {
return Convert::raw2att($this->Title);
}
public function getEscapedTitle()
{
return Convert::raw2att($this->Title);
}
/**
* @param Member $member
* @return bool
*/
public function canView($member = null) {
return $this->Parent()->canView($member);
}
public function canView($member = null)
{
return $this->Parent()->canView($member);
}
/**
* Return whether a user can create an object of this type
*
/**
* Return whether a user can create an object of this type
*
* @param Member $member
* @param array $context Virtual parameter to allow context to be passed in to check
* @return bool
*/
public function canCreate($member = null) {
// Check parent page
* @return bool
*/
public function canCreate($member = null)
{
// Check parent page
$parent = $this->getCanCreateContext(func_get_args());
if($parent) {
if ($parent) {
return $parent->canEdit($member);
}
// Fall back to secure admin permissions
return parent::canCreate($member);
}
}
/**
* Helper method to check the parent for this object
@ -106,13 +114,14 @@ class EditableOption extends DataObject {
* @param array $args List of arguments passed to canCreate
* @return DataObject Some parent dataobject to inherit permissions from
*/
protected function getCanCreateContext($args) {
protected function getCanCreateContext($args)
{
// Inspect second parameter to canCreate for a 'Parent' context
if(isset($args[1]['Parent'])) {
if (isset($args[1]['Parent'])) {
return $args[1]['Parent'];
}
// Hack in currently edited page if context is missing
if(Controller::has_curr() && Controller::curr() instanceof CMSMain) {
if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
return Controller::curr()->currentPage();
}
@ -124,7 +133,8 @@ class EditableOption extends DataObject {
* @param Member $member
* @return bool
*/
public function canPublish($member = null) {
public function canPublish($member = null)
{
return $this->canEdit($member);
}
@ -132,7 +142,8 @@ class EditableOption extends DataObject {
* @param Member $member
* @return bool
*/
public function canUnpublish($member = null) {
public function canUnpublish($member = null)
{
return $this->canDelete($member);
}
@ -145,7 +156,7 @@ class EditableOption extends DataObject {
public function getValue()
{
$value = $this->getField('Value');
if(empty($value) && !self::allow_empty_values()) {
if (empty($value) && !self::allow_empty_values()) {
return $this->Title;
}
return $value;

View File

@ -7,39 +7,43 @@
* @package userforms
*/
class EditableRadioField extends EditableMultipleOptionField {
class EditableRadioField extends EditableMultipleOptionField
{
private static $singular_name = 'Radio Group';
private static $singular_name = 'Radio Group';
private static $plural_name = 'Radio Groups';
private static $plural_name = 'Radio Groups';
/**
* @return FieldList
*/
public function getCMSFields() {
$fields = parent::getCMSFields();
/**
* @return FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName('Default');
$fields->removeByName('Default');
return $fields;
}
return $fields;
}
public function getFormField() {
$field = OptionsetField::create($this->Name, $this->EscapedTitle, $this->getOptionsMap());
$field->setFieldHolderTemplate('UserFormsMultipleOptionField_holder');
public function getFormField()
{
$field = OptionsetField::create($this->Name, $this->EscapedTitle, $this->getOptionsMap());
$field->setFieldHolderTemplate('UserFormsMultipleOptionField_holder');
// Set default item
$defaultOption = $this->getDefaultOptions()->first();
if($defaultOption) {
$field->setValue($defaultOption->EscapedTitle);
}
$this->doUpdateFormField($field);
return $field;
}
// Set default item
$defaultOption = $this->getDefaultOptions()->first();
if ($defaultOption) {
$field->setValue($defaultOption->EscapedTitle);
}
$this->doUpdateFormField($field);
return $field;
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) {
// We only want to trigger on load once for the radio group - hence we focus on the first option only.
$first = $forOnLoad ? ':first' : '';
return "$(\"input[name='{$this->Name}']{$first}\")";
}
public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false)
{
// We only want to trigger on load once for the radio group - hence we focus on the first option only.
$first = $forOnLoad ? ':first' : '';
return "$(\"input[name='{$this->Name}']{$first}\")";
}
}

View File

@ -7,109 +7,114 @@
* @package userforms
*/
class EditableTextField extends EditableFormField {
class EditableTextField extends EditableFormField
{
private static $singular_name = 'Text Field';
private static $singular_name = 'Text Field';
private static $plural_name = 'Text Fields';
private static $plural_name = 'Text Fields';
private static $db = array(
'MinLength' => 'Int',
'MaxLength' => 'Int',
'Rows' => 'Int(1)',
'Placeholder' => 'Varchar(255)'
);
private static $db = array(
'MinLength' => 'Int',
'MaxLength' => 'Int',
'Rows' => 'Int(1)',
'Placeholder' => 'Varchar(255)'
);
private static $defaults = array(
'Rows' => 1
);
private static $defaults = array(
'Rows' => 1
);
public function getCMSFields() {
$this->beforeUpdateCMSFields(function($fields) {
$fields->addFieldToTab(
'Root.Main',
NumericField::create(
'Rows',
_t('EditableTextField.NUMBERROWS', 'Number of rows')
)->setDescription(_t(
'EditableTextField.NUMBERROWS_DESCRIPTION',
'Fields with more than one row will be generated as a textarea'
))
);
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function ($fields) {
$fields->addFieldToTab(
'Root.Main',
NumericField::create(
'Rows',
_t('EditableTextField.NUMBERROWS', 'Number of rows')
)->setDescription(_t(
'EditableTextField.NUMBERROWS_DESCRIPTION',
'Fields with more than one row will be generated as a textarea'
))
);
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'Placeholder',
_t('EditableTextField.PLACEHOLDER', 'Placeholder')
)
);
});
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'Placeholder',
_t('EditableTextField.PLACEHOLDER', 'Placeholder')
)
);
});
return parent::getCMSFields();
}
return parent::getCMSFields();
}
/**
* @return FieldList
*/
public function getFieldValidationOptions() {
$fields = parent::getFieldValidationOptions();
/**
* @return FieldList
*/
public function getFieldValidationOptions()
{
$fields = parent::getFieldValidationOptions();
$fields->merge(array(
FieldGroup::create(
_t('EditableTextField.TEXTLENGTH', 'Allowed text length'),
array(
NumericField::create('MinLength', false),
LiteralField::create('RangeLength', _t("EditableTextField.RANGE_TO", "to")),
NumericField::create('MaxLength', false)
)
)
));
$fields->merge(array(
FieldGroup::create(
_t('EditableTextField.TEXTLENGTH', 'Allowed text length'),
array(
NumericField::create('MinLength', false),
LiteralField::create('RangeLength', _t("EditableTextField.RANGE_TO", "to")),
NumericField::create('MaxLength', false)
)
)
));
return $fields;
}
return $fields;
}
/**
* @return TextareaField|TextField
*/
public function getFormField() {
if($this->Rows > 1) {
$field = TextareaField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsTextareaField')
->setRows($this->Rows);
} else {
$field = TextField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField');
}
/**
* @return TextareaField|TextField
*/
public function getFormField()
{
if ($this->Rows > 1) {
$field = TextareaField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsTextareaField')
->setRows($this->Rows);
} else {
$field = TextField::create($this->Name, $this->EscapedTitle, $this->Default)
->setFieldHolderTemplate('UserFormsField_holder')
->setTemplate('UserFormsField');
}
$this->doUpdateFormField($field);
$this->doUpdateFormField($field);
return $field;
}
return $field;
}
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field) {
parent::updateFormField($field);
/**
* Updates a formfield with the additional metadata specified by this field
*
* @param FormField $field
*/
protected function updateFormField($field)
{
parent::updateFormField($field);
if(is_numeric($this->MinLength) && $this->MinLength > 0) {
$field->setAttribute('data-rule-minlength', intval($this->MinLength));
}
if (is_numeric($this->MinLength) && $this->MinLength > 0) {
$field->setAttribute('data-rule-minlength', intval($this->MinLength));
}
if(is_numeric($this->MaxLength) && $this->MaxLength > 0) {
if($field instanceof TextField) {
if (is_numeric($this->MaxLength) && $this->MaxLength > 0) {
if ($field instanceof TextField) {
$field->setMaxLength(intval($this->MaxLength));
}
$field->setAttribute('data-rule-maxlength', intval($this->MaxLength));
}
$field->setAttribute('data-rule-maxlength', intval($this->MaxLength));
}
if($this->Placeholder) {
$field->setAttribute('placeholder', $this->Placeholder);
}
}
if ($this->Placeholder) {
$field->setAttribute('placeholder', $this->Placeholder);
}
}
}

View File

@ -7,305 +7,312 @@
*
* @package userforms
*/
class UserDefinedForm_EmailRecipient extends DataObject {
class UserDefinedForm_EmailRecipient extends DataObject
{
private static $db = array(
'EmailAddress' => 'Varchar(200)',
'EmailSubject' => 'Varchar(200)',
'EmailFrom' => 'Varchar(200)',
'EmailReplyTo' => 'Varchar(200)',
'EmailBody' => 'Text',
'EmailBodyHtml' => 'HTMLText',
'EmailTemplate' => 'Varchar',
'SendPlain' => 'Boolean',
'HideFormData' => 'Boolean',
'CustomRulesCondition' => 'Enum("And,Or")'
);
private static $db = array(
'EmailAddress' => 'Varchar(200)',
'EmailSubject' => 'Varchar(200)',
'EmailFrom' => 'Varchar(200)',
'EmailReplyTo' => 'Varchar(200)',
'EmailBody' => 'Text',
'EmailBodyHtml' => 'HTMLText',
'EmailTemplate' => 'Varchar',
'SendPlain' => 'Boolean',
'HideFormData' => 'Boolean',
'CustomRulesCondition' => 'Enum("And,Or")'
);
private static $has_one = array(
'Form' => 'UserDefinedForm',
'SendEmailFromField' => 'EditableFormField',
'SendEmailToField' => 'EditableFormField',
'SendEmailSubjectField' => 'EditableFormField'
);
private static $has_one = array(
'Form' => 'UserDefinedForm',
'SendEmailFromField' => 'EditableFormField',
'SendEmailToField' => 'EditableFormField',
'SendEmailSubjectField' => 'EditableFormField'
);
private static $has_many = array(
'CustomRules' => 'UserDefinedForm_EmailRecipientCondition'
);
private static $has_many = array(
'CustomRules' => 'UserDefinedForm_EmailRecipientCondition'
);
private static $summary_fields = array(
'EmailAddress',
'EmailSubject',
'EmailFrom'
);
private static $summary_fields = array(
'EmailAddress',
'EmailSubject',
'EmailFrom'
);
/**
* Setting this to true will allow you to select "risky" fields as
* email recipient, such as free-text entry fields.
*
* It's advisable to leave this off.
*
* @config
* @var bool
*/
private static $allow_unbound_recipient_fields = false;
/**
* Setting this to true will allow you to select "risky" fields as
* email recipient, such as free-text entry fields.
*
* It's advisable to leave this off.
*
* @config
* @var bool
*/
private static $allow_unbound_recipient_fields = false;
public function summaryFields() {
$fields = parent::summaryFields();
if(isset($fields['EmailAddress'])) {
$fields['EmailAddress'] = _t('UserDefinedForm.EMAILADDRESS', 'Email');
}
if(isset($fields['EmailSubject'])) {
$fields['EmailSubject'] = _t('UserDefinedForm.EMAILSUBJECT', 'Subject');
}
if(isset($fields['EmailFrom'])) {
$fields['EmailFrom'] = _t('UserDefinedForm.EMAILFROM', 'From');
}
return $fields;
}
public function summaryFields()
{
$fields = parent::summaryFields();
if (isset($fields['EmailAddress'])) {
$fields['EmailAddress'] = _t('UserDefinedForm.EMAILADDRESS', 'Email');
}
if (isset($fields['EmailSubject'])) {
$fields['EmailSubject'] = _t('UserDefinedForm.EMAILSUBJECT', 'Subject');
}
if (isset($fields['EmailFrom'])) {
$fields['EmailFrom'] = _t('UserDefinedForm.EMAILFROM', 'From');
}
return $fields;
}
/**
* Get instance of UserDefinedForm when editing in getCMSFields
*
* @return UserDefinedFrom
*/
protected function getFormParent() {
$formID = $this->FormID
? $this->FormID
: Session::get('CMSMain.currentPage');
return UserDefinedForm::get()->byID($formID);
}
/**
* Get instance of UserDefinedForm when editing in getCMSFields
*
* @return UserDefinedFrom
*/
protected function getFormParent()
{
$formID = $this->FormID
? $this->FormID
: Session::get('CMSMain.currentPage');
return UserDefinedForm::get()->byID($formID);
}
public function getTitle() {
if($this->EmailAddress) {
return $this->EmailAddress;
}
if($this->EmailSubject) {
return $this->EmailSubject;
}
return parent::getTitle();
}
public function getTitle()
{
if ($this->EmailAddress) {
return $this->EmailAddress;
}
if ($this->EmailSubject) {
return $this->EmailSubject;
}
return parent::getTitle();
}
/**
* Generate a gridfield config for editing filter rules
*
* @return GridFieldConfig
*/
protected function getRulesConfig() {
$formFields = $this->getFormParent()->Fields();
/**
* Generate a gridfield config for editing filter rules
*
* @return GridFieldConfig
*/
protected function getRulesConfig()
{
$formFields = $this->getFormParent()->Fields();
$config = GridFieldConfig::create()
->addComponents(
new GridFieldButtonRow('before'),
new GridFieldToolbarHeader(),
new GridFieldAddNewInlineButton(),
new GridFieldDeleteAction(),
$columns = new GridFieldEditableColumns()
);
$config = GridFieldConfig::create()
->addComponents(
new GridFieldButtonRow('before'),
new GridFieldToolbarHeader(),
new GridFieldAddNewInlineButton(),
new GridFieldDeleteAction(),
$columns = new GridFieldEditableColumns()
);
$columns->setDisplayFields(array(
'ConditionFieldID' => function($record, $column, $grid) use ($formFields) {
return DropdownField::create($column, false, $formFields->map('ID', 'Title'));
},
'ConditionOption' => function($record, $column, $grid) {
$options = UserDefinedForm_EmailRecipientCondition::config()->condition_options;
return DropdownField::create($column, false, $options);
},
'ConditionValue' => function($record, $column, $grid) {
return TextField::create($column);
}
));
$columns->setDisplayFields(array(
'ConditionFieldID' => function ($record, $column, $grid) use ($formFields) {
return DropdownField::create($column, false, $formFields->map('ID', 'Title'));
},
'ConditionOption' => function ($record, $column, $grid) {
$options = UserDefinedForm_EmailRecipientCondition::config()->condition_options;
return DropdownField::create($column, false, $options);
},
'ConditionValue' => function ($record, $column, $grid) {
return TextField::create($column);
}
));
return $config;
}
return $config;
}
/**
* @return FieldList
*/
public function getCMSFields() {
Requirements::javascript(USERFORMS_DIR . '/javascript/Recipient.js');
/**
* @return FieldList
*/
public function getCMSFields()
{
Requirements::javascript(USERFORMS_DIR . '/javascript/Recipient.js');
// Determine optional field values
$form = $this->getFormParent();
// Determine optional field values
$form = $this->getFormParent();
// predefined choices are also candidates
$multiOptionFields = EditableMultipleOptionField::get()->filter('ParentID', $form->ID);
// predefined choices are also candidates
$multiOptionFields = EditableMultipleOptionField::get()->filter('ParentID', $form->ID);
// if they have email fields then we could send from it
$validEmailFromFields = EditableEmailField::get()->filter('ParentID', $form->ID);
// if they have email fields then we could send from it
$validEmailFromFields = EditableEmailField::get()->filter('ParentID', $form->ID);
// For the subject, only one-line entry boxes make sense
$validSubjectFields = ArrayList::create(
EditableTextField::get()
->filter('ParentID', $form->ID)
->exclude('Rows:GreaterThan', 1)
->toArray()
);
$validSubjectFields->merge($multiOptionFields);
// For the subject, only one-line entry boxes make sense
$validSubjectFields = ArrayList::create(
EditableTextField::get()
->filter('ParentID', $form->ID)
->exclude('Rows:GreaterThan', 1)
->toArray()
);
$validSubjectFields->merge($multiOptionFields);
// Check valid email-recipient fields
if($this->config()->allow_unbound_recipient_fields) {
// To address can only be email fields or multi option fields
$validEmailToFields = ArrayList::create($validEmailFromFields->toArray());
$validEmailToFields->merge($multiOptionFields);
} else {
// To address cannot be unbound, so restrict to pre-defined lists
$validEmailToFields = $multiOptionFields;
}
// Check valid email-recipient fields
if ($this->config()->allow_unbound_recipient_fields) {
// To address can only be email fields or multi option fields
$validEmailToFields = ArrayList::create($validEmailFromFields->toArray());
$validEmailToFields->merge($multiOptionFields);
} else {
// To address cannot be unbound, so restrict to pre-defined lists
$validEmailToFields = $multiOptionFields;
}
// Build fieldlist
$fields = FieldList::create(Tabset::create('Root')->addExtraClass('EmailRecipientForm'));
// Build fieldlist
$fields = FieldList::create(Tabset::create('Root')->addExtraClass('EmailRecipientForm'));
// Configuration fields
$fields->addFieldsToTab('Root.EmailDetails', array(
// Subject
FieldGroup::create(
TextField::create('EmailSubject', _t('UserDefinedForm.TYPESUBJECT', 'Type subject'))
->setAttribute('style', 'min-width: 400px;'),
DropdownField::create(
'SendEmailSubjectFieldID',
_t('UserDefinedForm.SELECTAFIELDTOSETSUBJECT', '.. or select a field to use as the subject'),
$validSubjectFields->map('ID', 'Title')
)->setEmptyString('')
)
->setTitle(_t('UserDefinedForm.EMAILSUBJECT', 'Email subject')),
// Configuration fields
$fields->addFieldsToTab('Root.EmailDetails', array(
// Subject
FieldGroup::create(
TextField::create('EmailSubject', _t('UserDefinedForm.TYPESUBJECT', 'Type subject'))
->setAttribute('style', 'min-width: 400px;'),
DropdownField::create(
'SendEmailSubjectFieldID',
_t('UserDefinedForm.SELECTAFIELDTOSETSUBJECT', '.. or select a field to use as the subject'),
$validSubjectFields->map('ID', 'Title')
)->setEmptyString('')
)
->setTitle(_t('UserDefinedForm.EMAILSUBJECT', 'Email subject')),
// To
FieldGroup::create(
TextField::create('EmailAddress', _t('UserDefinedForm.TYPETO', 'Type to address'))
->setAttribute('style', 'min-width: 400px;'),
DropdownField::create(
'SendEmailToFieldID',
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASTO', '.. or select a field to use as the to address'),
$validEmailToFields->map('ID', 'Title')
)->setEmptyString(' ')
)
->setTitle(_t('UserDefinedForm.SENDEMAILTO','Send email to'))
->setDescription(_t(
'UserDefinedForm.SENDEMAILTO_DESCRIPTION',
'You may enter multiple email addresses as a comma separated list.'
)),
// To
FieldGroup::create(
TextField::create('EmailAddress', _t('UserDefinedForm.TYPETO', 'Type to address'))
->setAttribute('style', 'min-width: 400px;'),
DropdownField::create(
'SendEmailToFieldID',
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASTO', '.. or select a field to use as the to address'),
$validEmailToFields->map('ID', 'Title')
)->setEmptyString(' ')
)
->setTitle(_t('UserDefinedForm.SENDEMAILTO', 'Send email to'))
->setDescription(_t(
'UserDefinedForm.SENDEMAILTO_DESCRIPTION',
'You may enter multiple email addresses as a comma separated list.'
)),
// From
TextField::create('EmailFrom', _t('UserDefinedForm.FROMADDRESS','Send email from'))
->setDescription(_t(
'UserDefinedForm.EmailFromContent',
"The from address allows you to set who the email comes from. On most servers this ".
"will need to be set to an email address on the same domain name as your site. ".
"For example on yoursite.com the from address may need to be something@yoursite.com. ".
"You can however, set any email address you wish as the reply to address."
)),
// From
TextField::create('EmailFrom', _t('UserDefinedForm.FROMADDRESS', 'Send email from'))
->setDescription(_t(
'UserDefinedForm.EmailFromContent',
"The from address allows you to set who the email comes from. On most servers this ".
"will need to be set to an email address on the same domain name as your site. ".
"For example on yoursite.com the from address may need to be something@yoursite.com. ".
"You can however, set any email address you wish as the reply to address."
)),
// Reply-To
FieldGroup::create(
TextField::create('EmailReplyTo', _t('UserDefinedForm.TYPEREPLY', 'Type reply address'))
->setAttribute('style', 'min-width: 400px;'),
DropdownField::create(
'SendEmailFromFieldID',
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASFROM', '.. or select a field to use as reply to address'),
$validEmailFromFields->map('ID', 'Title')
)->setEmptyString(' ')
)
->setTitle(_t('UserDefinedForm.REPLYADDRESS', 'Email for reply to'))
->setDescription(_t(
'UserDefinedForm.REPLYADDRESS_DESCRIPTION',
'The email address which the recipient is able to \'reply\' to.'
))
));
// Reply-To
FieldGroup::create(
TextField::create('EmailReplyTo', _t('UserDefinedForm.TYPEREPLY', 'Type reply address'))
->setAttribute('style', 'min-width: 400px;'),
DropdownField::create(
'SendEmailFromFieldID',
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASFROM', '.. or select a field to use as reply to address'),
$validEmailFromFields->map('ID', 'Title')
)->setEmptyString(' ')
)
->setTitle(_t('UserDefinedForm.REPLYADDRESS', 'Email for reply to'))
->setDescription(_t(
'UserDefinedForm.REPLYADDRESS_DESCRIPTION',
'The email address which the recipient is able to \'reply\' to.'
))
));
$fields->fieldByName('Root.EmailDetails')->setTitle(_t('UserDefinedForm_EmailRecipient.EMAILDETAILSTAB', 'Email Details'));
$fields->fieldByName('Root.EmailDetails')->setTitle(_t('UserDefinedForm_EmailRecipient.EMAILDETAILSTAB', 'Email Details'));
// Only show the preview link if the recipient has been saved.
if (!empty($this->EmailTemplate)) {
$preview = sprintf(
'<p><a href="%s" target="_blank" class="ss-ui-button">%s</a></p><em>%s</em>',
"admin/pages/edit/EditForm/field/EmailRecipients/item/{$this->ID}/preview",
_t('UserDefinedForm.PREVIEW_EMAIL', 'Preview email'),
_t('UserDefinedForm.PREVIEW_EMAIL_DESCRIPTION', 'Note: Unsaved changes will not appear in the preview.')
);
} else {
$preview = sprintf(
'<em>%s</em>',
_t(
'UserDefinedForm.PREVIEW_EMAIL_UNAVAILABLE',
'You can preview this email once you have saved the Recipient.'
)
);
}
// Only show the preview link if the recipient has been saved.
if (!empty($this->EmailTemplate)) {
$preview = sprintf(
'<p><a href="%s" target="_blank" class="ss-ui-button">%s</a></p><em>%s</em>',
"admin/pages/edit/EditForm/field/EmailRecipients/item/{$this->ID}/preview",
_t('UserDefinedForm.PREVIEW_EMAIL', 'Preview email'),
_t('UserDefinedForm.PREVIEW_EMAIL_DESCRIPTION', 'Note: Unsaved changes will not appear in the preview.')
);
} else {
$preview = sprintf(
'<em>%s</em>',
_t(
'UserDefinedForm.PREVIEW_EMAIL_UNAVAILABLE',
'You can preview this email once you have saved the Recipient.'
)
);
}
// Email templates
$fields->addFieldsToTab('Root.EmailContent', array(
CheckboxField::create('HideFormData', _t('UserDefinedForm.HIDEFORMDATA', 'Hide form data from email?')),
CheckboxField::create(
'SendPlain',
_t('UserDefinedForm.SENDPLAIN', 'Send email as plain text? (HTML will be stripped)')
),
DropdownField::create(
'EmailTemplate',
_t('UserDefinedForm.EMAILTEMPLATE', 'Email template'),
$this->getEmailTemplateDropdownValues()
)->addExtraClass('toggle-html-only'),
HTMLEditorField::create('EmailBodyHtml', _t('UserDefinedForm.EMAILBODYHTML', 'Body'))
->addExtraClass('toggle-html-only'),
TextareaField::create('EmailBody', _t('UserDefinedForm.EMAILBODY', 'Body'))
->addExtraClass('toggle-plain-only'),
LiteralField::create(
'EmailPreview',
'<div id="EmailPreview" class="field toggle-html-only">' . $preview . '</div>'
)
));
$fields->fieldByName('Root.EmailContent')->setTitle(_t('UserDefinedForm_EmailRecipient.EMAILCONTENTTAB', 'Email Content'));
// Email templates
$fields->addFieldsToTab('Root.EmailContent', array(
CheckboxField::create('HideFormData', _t('UserDefinedForm.HIDEFORMDATA', 'Hide form data from email?')),
CheckboxField::create(
'SendPlain',
_t('UserDefinedForm.SENDPLAIN', 'Send email as plain text? (HTML will be stripped)')
),
DropdownField::create(
'EmailTemplate',
_t('UserDefinedForm.EMAILTEMPLATE', 'Email template'),
$this->getEmailTemplateDropdownValues()
)->addExtraClass('toggle-html-only'),
HTMLEditorField::create('EmailBodyHtml', _t('UserDefinedForm.EMAILBODYHTML','Body'))
->addExtraClass('toggle-html-only'),
TextareaField::create('EmailBody', _t('UserDefinedForm.EMAILBODY','Body'))
->addExtraClass('toggle-plain-only'),
LiteralField::create(
'EmailPreview',
'<div id="EmailPreview" class="field toggle-html-only">' . $preview . '</div>'
)
));
// Custom rules for sending this field
$grid = new GridField(
"CustomRules",
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
$this->CustomRules(),
$this->getRulesConfig()
);
$grid->setDescription(_t(
'UserDefinedForm.RulesDescription',
'Emails will only be sent to the recipient if the custom rules are met. If no rules are defined, this receipient will receive notifications for every submission.'
));
$fields->addFieldsToTab('Root.CustomRules', array(
new DropdownField(
'CustomRulesCondition',
_t('UserDefinedForm.SENDIF', 'Send condition'),
array(
'Or' => _t('UserDefinedForm.SENDIFOR', 'Any conditions are true'),
'And' => _t('UserDefinedForm.SENDIFAND', 'All conditions are true')
)
),
$grid
));
$fields->fieldByName('Root.CustomRules')->setTitle(_t('UserDefinedForm_EmailRecipient.CUSTOMRULESTAB', 'Custom Rules'));
$fields->fieldByName('Root.EmailContent')->setTitle(_t('UserDefinedForm_EmailRecipient.EMAILCONTENTTAB', 'Email Content'));
$this->extend('updateCMSFields', $fields);
return $fields;
}
// Custom rules for sending this field
$grid = new GridField(
"CustomRules",
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
$this->CustomRules(),
$this->getRulesConfig()
);
$grid->setDescription(_t(
'UserDefinedForm.RulesDescription',
'Emails will only be sent to the recipient if the custom rules are met. If no rules are defined, this receipient will receive notifications for every submission.'
));
$fields->addFieldsToTab('Root.CustomRules', array(
new DropdownField(
'CustomRulesCondition',
_t('UserDefinedForm.SENDIF', 'Send condition'),
array(
'Or' => _t('UserDefinedForm.SENDIFOR', 'Any conditions are true'),
'And' => _t('UserDefinedForm.SENDIFAND', 'All conditions are true')
)
),
$grid
));
$fields->fieldByName('Root.CustomRules')->setTitle(_t('UserDefinedForm_EmailRecipient.CUSTOMRULESTAB', 'Custom Rules'));
$this->extend('updateCMSFields', $fields);
return $fields;
}
/**
* Return whether a user can create an object of this type
*
/**
* Return whether a user can create an object of this type
*
* @param Member $member
* @param array $context Virtual parameter to allow context to be passed in to check
* @return bool
*/
public function canCreate($member = null) {
// Check parent page
* @return bool
*/
public function canCreate($member = null)
{
// Check parent page
$parent = $this->getCanCreateContext(func_get_args());
if($parent) {
if ($parent) {
return $parent->canEdit($member);
}
// Fall back to secure admin permissions
return parent::canCreate($member);
}
}
/**
* Helper method to check the parent for this object
@ -313,13 +320,14 @@ class UserDefinedForm_EmailRecipient extends DataObject {
* @param array $args List of arguments passed to canCreate
* @return SiteTree Parent page instance
*/
protected function getCanCreateContext($args) {
protected function getCanCreateContext($args)
{
// Inspect second parameter to canCreate for a 'Parent' context
if(isset($args[1]['Form'])) {
if (isset($args[1]['Form'])) {
return $args[1]['Form'];
}
// Hack in currently edited page if context is missing
if(Controller::has_curr() && Controller::curr() instanceof CMSMain) {
if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
return Controller::curr()->currentPage();
}
@ -327,104 +335,111 @@ class UserDefinedForm_EmailRecipient extends DataObject {
return null;
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null) {
return $this->Form()->canView($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null)
{
return $this->Form()->canView($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null) {
return $this->Form()->canEdit($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null)
{
return $this->Form()->canEdit($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null) {
return $this->canEdit($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null)
{
return $this->canEdit($member);
}
/*
* Determine if this recipient may receive notifications for this submission
*
* @param array $data
* @param Form $form
* @return bool
*/
public function canSend($data, $form) {
// Skip if no rules configured
$customRules = $this->CustomRules();
if(!$customRules->count()) {
return true;
}
/*
* Determine if this recipient may receive notifications for this submission
*
* @param array $data
* @param Form $form
* @return bool
*/
public function canSend($data, $form)
{
// Skip if no rules configured
$customRules = $this->CustomRules();
if (!$customRules->count()) {
return true;
}
// Check all rules
$isAnd = $this->CustomRulesCondition === 'And';
foreach($customRules as $customRule) {
$matches = $customRule->matches($data, $form);
if($isAnd && !$matches) {
return false;
}
if(!$isAnd && $matches) {
return true;
}
}
// Check all rules
$isAnd = $this->CustomRulesCondition === 'And';
foreach ($customRules as $customRule) {
$matches = $customRule->matches($data, $form);
if ($isAnd && !$matches) {
return false;
}
if (!$isAnd && $matches) {
return true;
}
}
// Once all rules are checked
return $isAnd;
}
// Once all rules are checked
return $isAnd;
}
/**
* Make sure the email template saved against the recipient exists on the file system.
*
* @param string
*
* @return boolean
*/
public function emailTemplateExists($template = '') {
$t = ($template ? $template : $this->EmailTemplate);
/**
* Make sure the email template saved against the recipient exists on the file system.
*
* @param string
*
* @return boolean
*/
public function emailTemplateExists($template = '')
{
$t = ($template ? $template : $this->EmailTemplate);
return in_array($t, $this->getEmailTemplateDropdownValues());
}
return in_array($t, $this->getEmailTemplateDropdownValues());
}
/**
* Get the email body for the current email format
*
* @return string
*/
public function getEmailBodyContent() {
return $this->SendPlain ? $this->EmailBody : $this->EmailBodyHtml;
}
/**
* Get the email body for the current email format
*
* @return string
*/
public function getEmailBodyContent()
{
return $this->SendPlain ? $this->EmailBody : $this->EmailBodyHtml;
}
/**
* Gets a list of email templates suitable for populating the email template dropdown.
*
* @return array
*/
public function getEmailTemplateDropdownValues() {
$templates = array();
/**
* Gets a list of email templates suitable for populating the email template dropdown.
*
* @return array
*/
public function getEmailTemplateDropdownValues()
{
$templates = array();
$finder = new SS_FileFinder();
$finder->setOption('name_regex', '/^.*\.ss$/');
$finder = new SS_FileFinder();
$finder->setOption('name_regex', '/^.*\.ss$/');
$found = $finder->find(BASE_PATH . '/' . UserDefinedForm::config()->email_template_directory);
$found = $finder->find(BASE_PATH . '/' . UserDefinedForm::config()->email_template_directory);
foreach ($found as $key => $value) {
$template = pathinfo($value);
foreach ($found as $key => $value) {
$template = pathinfo($value);
$templates[$template['filename']] = $template['filename'];
}
$templates[$template['filename']] = $template['filename'];
}
return $templates;
}
return $templates;
}
}

View File

@ -6,71 +6,74 @@
*
* @method UserDefinedForm_EmailRecipient Parent()
*/
class UserDefinedForm_EmailRecipientCondition extends DataObject {
class UserDefinedForm_EmailRecipientCondition extends DataObject
{
/**
* List of options
*
* @config
* @var array
*/
private static $condition_options = array(
"IsBlank" => "Is blank",
"IsNotBlank" => "Is not blank",
"Equals" => "Equals",
"NotEquals" => "Doesn't equal"
);
/**
* List of options
*
* @config
* @var array
*/
private static $condition_options = array(
"IsBlank" => "Is blank",
"IsNotBlank" => "Is not blank",
"Equals" => "Equals",
"NotEquals" => "Doesn't equal"
);
private static $db = array(
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,Equals,NotEquals")',
'ConditionValue' => 'Varchar'
);
private static $db = array(
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,Equals,NotEquals")',
'ConditionValue' => 'Varchar'
);
private static $has_one = array(
'Parent' => 'UserDefinedForm_EmailRecipient',
'ConditionField' => 'EditableFormField'
);
private static $has_one = array(
'Parent' => 'UserDefinedForm_EmailRecipient',
'ConditionField' => 'EditableFormField'
);
/**
* Determine if this rule matches the given condition
*
* @param array $data
* @param Form $form
* @return bool
*/
public function matches($data, $form) {
$fieldName = $this->ConditionField()->Name;
$fieldValue = isset($data[$fieldName]) ? $data[$fieldName] : null;
switch($this->ConditionOption) {
case 'IsBlank':
return empty($fieldValue);
case 'IsNotBlank':
return !empty($fieldValue);
default:
$matches = is_array($fieldValue)
? in_array($this->ConditionValue, $fieldValue)
: $this->ConditionValue === (string) $fieldValue;
return ($this->ConditionOption === 'Equals') === (bool)$matches;
}
}
/**
* Determine if this rule matches the given condition
*
* @param array $data
* @param Form $form
* @return bool
*/
public function matches($data, $form)
{
$fieldName = $this->ConditionField()->Name;
$fieldValue = isset($data[$fieldName]) ? $data[$fieldName] : null;
switch ($this->ConditionOption) {
case 'IsBlank':
return empty($fieldValue);
case 'IsNotBlank':
return !empty($fieldValue);
default:
$matches = is_array($fieldValue)
? in_array($this->ConditionValue, $fieldValue)
: $this->ConditionValue === (string) $fieldValue;
return ($this->ConditionOption === 'Equals') === (bool)$matches;
}
}
/**
* Return whether a user can create an object of this type
*
/**
* Return whether a user can create an object of this type
*
* @param Member $member
* @param array $context Virtual parameter to allow context to be passed in to check
* @return bool
*/
public function canCreate($member = null) {
// Check parent page
* @return bool
*/
public function canCreate($member = null)
{
// Check parent page
$parent = $this->getCanCreateContext(func_get_args());
if($parent) {
if ($parent) {
return $parent->canEdit($member);
}
// Fall back to secure admin permissions
return parent::canCreate($member);
}
}
/**
* Helper method to check the parent for this object
@ -78,13 +81,14 @@ class UserDefinedForm_EmailRecipientCondition extends DataObject {
* @param array $args List of arguments passed to canCreate
* @return SiteTree Parent page instance
*/
protected function getCanCreateContext($args) {
protected function getCanCreateContext($args)
{
// Inspect second parameter to canCreate for a 'Parent' context
if(isset($args[1]['Parent'])) {
if (isset($args[1]['Parent'])) {
return $args[1]['Parent'];
}
// Hack in currently edited page if context is missing
if(Controller::has_curr() && Controller::curr() instanceof CMSMain) {
if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
return Controller::curr()->currentPage();
}
@ -92,30 +96,33 @@ class UserDefinedForm_EmailRecipientCondition extends DataObject {
return null;
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null) {
return $this->Parent()->canView($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null)
{
return $this->Parent()->canView($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null) {
return $this->Parent()->canEdit($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null)
{
return $this->Parent()->canEdit($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null) {
return $this->canEdit($member);
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null)
{
return $this->canEdit($member);
}
}

View File

@ -8,23 +8,26 @@
* @package userforms
*/
class UserFormRecipientEmail extends Email {
class UserFormRecipientEmail extends Email
{
protected $ss_template = "SubmittedFormEmail";
protected $ss_template = "SubmittedFormEmail";
protected $data;
protected $data;
public function __construct($submittedFields = null) {
parent::__construct($submittedFields = null);
}
public function __construct($submittedFields = null)
{
parent::__construct($submittedFields = null);
}
/**
* Set the "Reply-To" header with an email address rather than append as
* {@link Email::replyTo} does.
*
* @param string $email The email address to set the "Reply-To" header to
*/
public function setReplyTo($email) {
$this->customHeaders['Reply-To'] = $email;
}
/**
* Set the "Reply-To" header with an email address rather than append as
* {@link Email::replyTo} does.
*
* @param string $email The email address to set the "Reply-To" header to
*/
public function setReplyTo($email)
{
$this->customHeaders['Reply-To'] = $email;
}
}

View File

@ -5,47 +5,50 @@
*
* @package userforms
*/
class UserFormRecipientItemRequest extends GridFieldDetailForm_ItemRequest {
class UserFormRecipientItemRequest extends GridFieldDetailForm_ItemRequest
{
private static $allowed_actions = array(
'edit',
'view',
'ItemEditForm',
'preview'
);
private static $allowed_actions = array(
'edit',
'view',
'ItemEditForm',
'preview'
);
/**
* Renders a preview of the recipient email.
*/
public function preview() {
return $this->customise(new ArrayData(array(
'Body' => $this->record->getEmailBodyContent(),
'HideFormData' => $this->record->HideFormData,
'Fields' => $this->getPreviewFieldData()
)))->renderWith($this->record->EmailTemplate);
}
/**
* Renders a preview of the recipient email.
*/
public function preview()
{
return $this->customise(new ArrayData(array(
'Body' => $this->record->getEmailBodyContent(),
'HideFormData' => $this->record->HideFormData,
'Fields' => $this->getPreviewFieldData()
)))->renderWith($this->record->EmailTemplate);
}
/**
* Get some placeholder field values to display in the preview
* @return ArrayList
*/
private function getPreviewFieldData() {
$data = new ArrayList();
/**
* Get some placeholder field values to display in the preview
* @return ArrayList
*/
private function getPreviewFieldData()
{
$data = new ArrayList();
$fields = $this->record->Form()->Fields()->filter(array(
'ClassName:not' => 'EditableLiteralField',
'ClassName:not' => 'EditableFormHeading'
));
$fields = $this->record->Form()->Fields()->filter(array(
'ClassName:not' => 'EditableLiteralField',
'ClassName:not' => 'EditableFormHeading'
));
foreach ($fields as $field) {
$data->push(new ArrayData(array(
'Name' => $field->Name,
'Title' => $field->Title,
'Value' => '$' . $field->Name,
'FormattedValue' => '$' . $field->Name
)));
}
foreach ($fields as $field) {
$data->push(new ArrayData(array(
'Name' => $field->Name,
'Title' => $field->Title,
'Value' => '$' . $field->Name,
'FormattedValue' => '$' . $field->Name
)));
}
return $data;
}
return $data;
}
}

View File

@ -7,63 +7,68 @@
* @package userforms
*/
class SubmittedFileField extends SubmittedFormField {
class SubmittedFileField extends SubmittedFormField
{
private static $has_one = array(
"UploadedFile" => "File"
);
private static $has_one = array(
"UploadedFile" => "File"
);
/**
* Return the value of this field for inclusion into things such as
* reports.
*
* @return string
*/
public function getFormattedValue() {
$name = $this->getFileName();
$link = $this->getLink();
$title = _t('SubmittedFileField.DOWNLOADFILE', 'Download File');
/**
* Return the value of this field for inclusion into things such as
* reports.
*
* @return string
*/
public function getFormattedValue()
{
$name = $this->getFileName();
$link = $this->getLink();
$title = _t('SubmittedFileField.DOWNLOADFILE', 'Download File');
if($link) {
return DBField::create_field('HTMLText', sprintf(
'%s - <a href="%s" target="_blank">%s</a>',
$name, $link, $title
));
}
if ($link) {
return DBField::create_field('HTMLText', sprintf(
'%s - <a href="%s" target="_blank">%s</a>',
$name, $link, $title
));
}
return false;
}
return false;
}
/**
* Return the value for this field in the CSV export.
*
* @return string
*/
public function getExportValue() {
return ($link = $this->getLink()) ? $link : "";
}
/**
* Return the value for this field in the CSV export.
*
* @return string
*/
public function getExportValue()
{
return ($link = $this->getLink()) ? $link : "";
}
/**
* Return the link for the file attached to this submitted form field.
*
* @return string
*/
public function getLink() {
if($file = $this->UploadedFile()) {
if(trim($file->getFilename(), '/') != trim(ASSETS_DIR,'/')) {
return $this->UploadedFile()->URL;
}
}
}
/**
* Return the link for the file attached to this submitted form field.
*
* @return string
*/
public function getLink()
{
if ($file = $this->UploadedFile()) {
if (trim($file->getFilename(), '/') != trim(ASSETS_DIR, '/')) {
return $this->UploadedFile()->URL;
}
}
}
/**
* Return the name of the file, if present
*
* @return string
*/
public function getFileName() {
if($this->UploadedFile()) {
return $this->UploadedFile()->Name;
}
}
/**
* Return the name of the file, if present
*
* @return string
*/
public function getFileName()
{
if ($this->UploadedFile()) {
return $this->UploadedFile()->Name;
}
}
}

View File

@ -5,143 +5,150 @@
* @package userforms
*/
class SubmittedForm extends DataObject {
class SubmittedForm extends DataObject
{
private static $has_one = array(
"SubmittedBy" => "Member",
"Parent" => "UserDefinedForm",
);
private static $has_one = array(
"SubmittedBy" => "Member",
"Parent" => "UserDefinedForm",
);
private static $has_many = array(
"Values" => "SubmittedFormField"
);
private static $has_many = array(
"Values" => "SubmittedFormField"
);
private static $summary_fields = array(
'ID',
'Created'
);
private static $summary_fields = array(
'ID',
'Created'
);
/**
* Returns the value of a relation or, in the case of this form, the value
* of a given child {@link SubmittedFormField}
*
* @param string
*
* @return mixed
*/
public function relField($fieldName) {
// default case
if($value = parent::relField($fieldName)) {
return $value;
}
/**
* Returns the value of a relation or, in the case of this form, the value
* of a given child {@link SubmittedFormField}
*
* @param string
*
* @return mixed
*/
public function relField($fieldName)
{
// default case
if ($value = parent::relField($fieldName)) {
return $value;
}
// check values for a form field with the matching name.
$formField = SubmittedFormField::get()->filter(array(
'ParentID' => $this->ID,
'Name' => $fieldName
))->first();
// check values for a form field with the matching name.
$formField = SubmittedFormField::get()->filter(array(
'ParentID' => $this->ID,
'Name' => $fieldName
))->first();
if($formField) {
return $formField->getFormattedValue();
}
}
if ($formField) {
return $formField->getFormattedValue();
}
}
/**
* @return FieldList
*/
public function getCMSFields() {
/**
* @return FieldList
*/
public function getCMSFields()
{
$self = $this;
$self = $this;
$this->beforeUpdateCMSFields(function ($fields) use ($self) {
$fields->removeByName('Values');
$fields->dataFieldByName('SubmittedByID')->setDisabled(true);
$this->beforeUpdateCMSFields(function($fields) use ($self) {
$fields->removeByName('Values');
$fields->dataFieldByName('SubmittedByID')->setDisabled(true);
$values = new GridField(
'Values',
'SubmittedFormField',
$self->Values()->sort('Created', 'ASC')
);
$values = new GridField(
'Values',
'SubmittedFormField',
$self->Values()->sort('Created', 'ASC')
);
$config = new GridFieldConfig();
$config->addComponent(new GridFieldDataColumns());
$config->addComponent(new GridFieldExportButton());
$config->addComponent(new GridFieldPrintButton());
$values->setConfig($config);
$config = new GridFieldConfig();
$config->addComponent(new GridFieldDataColumns());
$config->addComponent(new GridFieldExportButton());
$config->addComponent(new GridFieldPrintButton());
$values->setConfig($config);
$fields->addFieldToTab('Root.Main', $values);
});
$fields->addFieldToTab('Root.Main', $values);
});
$fields = parent::getCMSFields();
$fields = parent::getCMSFields();
return $fields;
}
return $fields;
}
/**
* @param Member
*
* @return boolean
*/
public function canCreate($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Parent()->canCreate();
}
/**
* @param Member
*
* @return boolean
*/
public function canCreate($member = null) {
$extended = $this->extendedCan(__FUNCTION__, $member);
if($extended !== null) {
return $extended;
}
return $this->Parent()->canCreate();
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Parent()->canView();
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null) {
$extended = $this->extendedCan(__FUNCTION__, $member);
if($extended !== null) {
return $extended;
}
return $this->Parent()->canView();
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Parent()->canEdit();
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null) {
$extended = $this->extendedCan(__FUNCTION__, $member);
if($extended !== null) {
return $extended;
}
return $this->Parent()->canEdit();
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Parent()->canDelete();
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null) {
$extended = $this->extendedCan(__FUNCTION__, $member);
if($extended !== null) {
return $extended;
}
return $this->Parent()->canDelete();
}
/**
* Before we delete this form make sure we delete all the
* field values so that we don't leave old data round
*
* @return void
*/
protected function onBeforeDelete()
{
if ($this->Values()) {
foreach ($this->Values() as $value) {
$value->delete();
}
}
/**
* Before we delete this form make sure we delete all the
* field values so that we don't leave old data round
*
* @return void
*/
protected function onBeforeDelete() {
if($this->Values()) {
foreach($this->Values() as $value) {
$value->delete();
}
}
parent::onBeforeDelete();
}
parent::onBeforeDelete();
}
}

View File

@ -5,93 +5,101 @@
* @package userforms
*/
class SubmittedFormField extends DataObject {
class SubmittedFormField extends DataObject
{
private static $db = array(
"Name" => "Varchar",
"Value" => "Text",
"Title" => "Varchar(255)"
);
private static $db = array(
"Name" => "Varchar",
"Value" => "Text",
"Title" => "Varchar(255)"
);
private static $has_one = array(
"Parent" => "SubmittedForm"
);
private static $has_one = array(
"Parent" => "SubmittedForm"
);
private static $summary_fields = array(
'Title' => 'Title',
'FormattedValue' => 'Value'
);
private static $summary_fields = array(
'Title' => 'Title',
'FormattedValue' => 'Value'
);
/**
* @param Member
*
* @return boolean
*/
public function canCreate($member = null) {
return $this->Parent()->canCreate();
}
/**
* @param Member
*
* @return boolean
*/
public function canCreate($member = null)
{
return $this->Parent()->canCreate();
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null) {
return $this->Parent()->canView();
}
/**
* @param Member
*
* @return boolean
*/
public function canView($member = null)
{
return $this->Parent()->canView();
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null) {
return $this->Parent()->canEdit();
}
/**
* @param Member
*
* @return boolean
*/
public function canEdit($member = null)
{
return $this->Parent()->canEdit();
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null) {
return $this->Parent()->canDelete();
}
/**
* @param Member
*
* @return boolean
*/
public function canDelete($member = null)
{
return $this->Parent()->canDelete();
}
/**
* Generate a formatted value for the reports and email notifications.
* Converts new lines (which are stored in the database text field) as
* <brs> so they will output as newlines in the reports
*
* @return string
*/
public function getFormattedValue() {
return nl2br($this->dbObject('Value')->ATT());
}
/**
* Generate a formatted value for the reports and email notifications.
* Converts new lines (which are stored in the database text field) as
* <brs> so they will output as newlines in the reports
*
* @return string
*/
public function getFormattedValue()
{
return nl2br($this->dbObject('Value')->ATT());
}
/**
* Return the value of this submitted form field suitable for inclusion
* into the CSV
*
* @return Text
*/
public function getExportValue() {
return $this->Value;
}
/**
* Return the value of this submitted form field suitable for inclusion
* into the CSV
*
* @return Text
*/
public function getExportValue()
{
return $this->Value;
}
/**
* Find equivalent editable field for this submission.
*
* Note the field may have been modified or deleted from the original form
* so this may not always return the data you expect. If you need to save
* a particular state of editable form field at time of submission, copy
* that value to the submission.
*
* @return EditableFormField
*/
public function getEditableField() {
return $this->Parent()->Parent()->Fields()->filter(array(
'Name' => $this->Name
))->First();
}
/**
* Find equivalent editable field for this submission.
*
* Note the field may have been modified or deleted from the original form
* so this may not always return the data you expect. If you need to save
* a particular state of editable form field at time of submission, copy
* that value to the submission.
*
* @return EditableFormField
*/
public function getEditableField()
{
return $this->Parent()->Parent()->Fields()->filter(array(
'Name' => $this->Name
))->First();
}
}

View File

@ -2,53 +2,56 @@
use SilverStripe\Forms\SegmentFieldModifier\AbstractSegmentFieldModifier;
class DisambiguationSegmentFieldModifier extends AbstractSegmentFieldModifier {
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getPreview($value) {
if($this->form instanceof Form && $record = $this->form->getRecord()) {
$parent = $record->Parent();
class DisambiguationSegmentFieldModifier extends AbstractSegmentFieldModifier
{
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getPreview($value)
{
if ($this->form instanceof Form && $record = $this->form->getRecord()) {
$parent = $record->Parent();
$try = $value;
$try = $value;
$sibling = EditableformField::get()
->filter('ParentID', $parent->ID)
->filter('Name', $try)
->where('"ID" != ' . $record->ID)
->first();
$sibling = EditableformField::get()
->filter('ParentID', $parent->ID)
->filter('Name', $try)
->where('"ID" != ' . $record->ID)
->first();
$counter = 1;
$counter = 1;
while($sibling !== null) {
$try = $value . '_' . $counter++;
while ($sibling !== null) {
$try = $value . '_' . $counter++;
$sibling = EditableformField::get()
->filter('ParentID', $parent->ID)
->filter('Name', $try)
->first();
}
$sibling = EditableformField::get()
->filter('ParentID', $parent->ID)
->filter('Name', $try)
->first();
}
if ($try !== $value) {
return $try;
}
}
if ($try !== $value) {
return $try;
}
}
return $value;
}
return $value;
}
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getSuggestion($value) {
return $this->getPreview($value);
}
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getSuggestion($value)
{
return $this->getPreview($value);
}
}

View File

@ -2,26 +2,29 @@
use SilverStripe\Forms\SegmentFieldModifier\SlugSegmentFieldModifier;
class UnderscoreSegmentFieldModifier extends SlugSegmentFieldModifier {
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getPreview($value) {
return str_replace('-', '_', parent::getPreview($value));
}
class UnderscoreSegmentFieldModifier extends SlugSegmentFieldModifier
{
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getPreview($value)
{
return str_replace('-', '_', parent::getPreview($value));
}
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getSuggestion($value) {
return str_replace('-', '_', parent::getSuggestion($value));
}
/**
* @inheritdoc
*
* @param string $value
*
* @return string
*/
public function getSuggestion($value)
{
return str_replace('-', '_', parent::getSuggestion($value));
}
}

View File

@ -8,54 +8,54 @@
* @package userforms
*/
class UserFormsColumnCleanTask extends MigrationTask {
class UserFormsColumnCleanTask extends MigrationTask
{
protected $title = "UserForms EditableFormField Column Clean task";
protected $title = "UserForms EditableFormField Column Clean task";
protected $description = "Removes unused columns from EditableFormField for MySQL databases;";
protected $description = "Removes unused columns from EditableFormField for MySQL databases;";
protected $tables = array('EditableFormField');
protected $tables = array('EditableFormField');
protected $keepColumns = array('ID');
protected $keepColumns = array('ID');
/**
* Publish the existing forms.
*
*/
public function run($request) {
foreach ($this->tables as $db) {
$obj = new $db();
$columns = $obj->database_fields($db);
$query = "SHOW COLUMNS FROM $db";
$liveColumns = DB::query($query)->column();
$backedUp = 0;
$query = "SHOW TABLES LIKE 'Backup_$db'";
$tableExists = DB::query($query)->value();
if ($tableExists != null) {
echo "Tasks run already on $db exiting";
return;
}
$backedUp = 0;
foreach ($liveColumns as $index => $column) {
if ($backedUp == 0) {
echo "Backing up $db <br />";
echo "Creating Backup_$db <br />";
// backup table
$query = "CREATE TABLE Backup_$db LIKE $db";
DB::query($query);
echo "Populating Backup_$db <br />";
$query = "INSERT Backup_$db SELECT * FROM $db";
DB::query($query);
$backedUp = 1;
}
if (!isset($columns[$column]) && !in_array($column, $this->keepColumns)) {
echo "Dropping $column from $db <br />";
$query = "ALTER TABLE $db DROP COLUMN $column";
DB::query($query);
}
}
}
}
/**
* Publish the existing forms.
*
*/
public function run($request)
{
foreach ($this->tables as $db) {
$obj = new $db();
$columns = $obj->database_fields($db);
$query = "SHOW COLUMNS FROM $db";
$liveColumns = DB::query($query)->column();
$backedUp = 0;
$query = "SHOW TABLES LIKE 'Backup_$db'";
$tableExists = DB::query($query)->value();
if ($tableExists != null) {
echo "Tasks run already on $db exiting";
return;
}
$backedUp = 0;
foreach ($liveColumns as $index => $column) {
if ($backedUp == 0) {
echo "Backing up $db <br />";
echo "Creating Backup_$db <br />";
// backup table
$query = "CREATE TABLE Backup_$db LIKE $db";
DB::query($query);
echo "Populating Backup_$db <br />";
$query = "INSERT Backup_$db SELECT * FROM $db";
DB::query($query);
$backedUp = 1;
}
if (!isset($columns[$column]) && !in_array($column, $this->keepColumns)) {
echo "Dropping $column from $db <br />";
$query = "ALTER TABLE $db DROP COLUMN $column";
DB::query($query);
}
}
}
}
}

View File

@ -3,216 +3,225 @@
/**
* Service to support upgrade of userforms module
*/
class UserFormsUpgradeService {
class UserFormsUpgradeService
{
/**
* @var bool
*/
protected $quiet;
/**
* @var bool
*/
protected $quiet;
public function run() {
$this->log("Upgrading formfield rules and custom settings");
public function run()
{
$this->log("Upgrading formfield rules and custom settings");
// List of rules that have been created in all stages
$fields = Versioned::get_including_deleted('EditableFormField');
foreach($fields as $field) {
$this->upgradeField($field);
}
}
// List of rules that have been created in all stages
$fields = Versioned::get_including_deleted('EditableFormField');
foreach ($fields as $field) {
$this->upgradeField($field);
}
}
/**
* Migrate a versioned field in all stages
*
* @param EditableFormField $field
*/
protected function upgradeField(EditableFormField $field) {
$this->log("Upgrading formfield ID = ".$field->ID);
/**
* Migrate a versioned field in all stages
*
* @param EditableFormField $field
*/
protected function upgradeField(EditableFormField $field)
{
$this->log("Upgrading formfield ID = ".$field->ID);
// Check versions this field exists on
$filter = sprintf('"EditableFormField"."ID" = \'%d\' AND "Migrated" = 0', $field->ID);
$stageField = Versioned::get_one_by_stage('EditableFormField', 'Stage', $filter);
$liveField = Versioned::get_one_by_stage('EditableFormField', 'Live', $filter);
// Check versions this field exists on
$filter = sprintf('"EditableFormField"."ID" = \'%d\' AND "Migrated" = 0', $field->ID);
$stageField = Versioned::get_one_by_stage('EditableFormField', 'Stage', $filter);
$liveField = Versioned::get_one_by_stage('EditableFormField', 'Live', $filter);
if($stageField) {
$this->upgradeFieldInStage($stageField, 'Stage');
}
if ($stageField) {
$this->upgradeFieldInStage($stageField, 'Stage');
}
if($liveField) {
$this->upgradeFieldInStage($liveField, 'Live');
}
}
if ($liveField) {
$this->upgradeFieldInStage($liveField, 'Live');
}
}
/**
* Migrate a versioned field in a single stage
*
* @param EditableFormField $field
* @param stage $stage
*/
protected function upgradeFieldInStage(EditableFormField $field, $stage) {
Versioned::reading_stage($stage);
/**
* Migrate a versioned field in a single stage
*
* @param EditableFormField $field
* @param stage $stage
*/
protected function upgradeFieldInStage(EditableFormField $field, $stage)
{
Versioned::reading_stage($stage);
// Migrate field rules
$this->migrateRules($field, $stage);
// Migrate field rules
$this->migrateRules($field, $stage);
// Migrate custom settings
$this->migrateCustomSettings($field, $stage);
// Migrate custom settings
$this->migrateCustomSettings($field, $stage);
// Flag as migrated
$field->Migrated = true;
$field->write();
}
// Flag as migrated
$field->Migrated = true;
$field->write();
}
/**
* Migrate custom rules for the given field
*
* @param EditableFormField $field
* @param string $stage
*/
protected function migrateRules(EditableFormField $field, $stage) {
$rulesData = $field->CustomRules
? unserialize($field->CustomRules)
: array();
/**
* Migrate custom rules for the given field
*
* @param EditableFormField $field
* @param string $stage
*/
protected function migrateRules(EditableFormField $field, $stage)
{
$rulesData = $field->CustomRules
? unserialize($field->CustomRules)
: array();
// Skip blank rules or fields with custom rules already
if(empty($rulesData) || $field->DisplayRules()->count()) {
return;
}
// Skip blank rules or fields with custom rules already
if (empty($rulesData) || $field->DisplayRules()->count()) {
return;
}
// Check value of this condition
foreach($rulesData as $ruleDataItem) {
if(empty($ruleDataItem['ConditionOption']) || empty($ruleDataItem['Display'])) {
continue;
}
// Check value of this condition
foreach ($rulesData as $ruleDataItem) {
if (empty($ruleDataItem['ConditionOption']) || empty($ruleDataItem['Display'])) {
continue;
}
// Get data for this rule
$conditionOption = $ruleDataItem['ConditionOption'];
$display = $ruleDataItem['Display'];
$conditionFieldName = empty($ruleDataItem['ConditionField']) ? null : $ruleDataItem['ConditionField'];
$value = isset($ruleDataItem['Value'])
? $ruleDataItem['Value']
: null;
// Get data for this rule
$conditionOption = $ruleDataItem['ConditionOption'];
$display = $ruleDataItem['Display'];
$conditionFieldName = empty($ruleDataItem['ConditionField']) ? null : $ruleDataItem['ConditionField'];
$value = isset($ruleDataItem['Value'])
? $ruleDataItem['Value']
: null;
// Create rule
$rule = $this->findOrCreateRule($field, $stage, $conditionOption, $display, $conditionFieldName, $value);
$this->log("Upgrading rule ID = " . $rule->ID);
}
}
// Create rule
$rule = $this->findOrCreateRule($field, $stage, $conditionOption, $display, $conditionFieldName, $value);
$this->log("Upgrading rule ID = " . $rule->ID);
}
}
/**
* Migrate custom settings for the given field
*
* @param EditableFormField $field
* @param string $stage
*/
protected function migrateCustomSettings(EditableFormField $field, $stage) {
// Custom settings include:
// - ExtraClass
// - RightTitle
// - ShowOnLoad (show or '' are treated as true)
//
// - CheckedDefault (new field on EditableCheckbox - should be read from old "default" value)
// - Default (EditableCheckbox)
// - DefaultToToday (EditableDateField)
// - Folder (EditableFileField)
// - Level (EditableFormHeading)
// - HideFromReports (EditableFormHeading / EditableLiteralField)
// - Content (EditableLiteralField)
// - GroupID (EditableMemberListField)
// - MinValue (EditableNumericField)
// - MaxValue (EditableNumericField)
// - MinLength (EditableTextField)
// - MaxLength (EditableTextField)
// - Rows (EditableTextField)
/**
* Migrate custom settings for the given field
*
* @param EditableFormField $field
* @param string $stage
*/
protected function migrateCustomSettings(EditableFormField $field, $stage)
{
// Custom settings include:
// - ExtraClass
// - RightTitle
// - ShowOnLoad (show or '' are treated as true)
//
// - CheckedDefault (new field on EditableCheckbox - should be read from old "default" value)
// - Default (EditableCheckbox)
// - DefaultToToday (EditableDateField)
// - Folder (EditableFileField)
// - Level (EditableFormHeading)
// - HideFromReports (EditableFormHeading / EditableLiteralField)
// - Content (EditableLiteralField)
// - GroupID (EditableMemberListField)
// - MinValue (EditableNumericField)
// - MaxValue (EditableNumericField)
// - MinLength (EditableTextField)
// - MaxLength (EditableTextField)
// - Rows (EditableTextField)
$customSettings = $field->CustomSettings
? unserialize($field->CustomSettings)
: array();
$customSettings = $field->CustomSettings
? unserialize($field->CustomSettings)
: array();
// Skip blank rules or fields with custom rules already
if(empty($customSettings)) {
return;
}
// Skip blank rules or fields with custom rules already
if (empty($customSettings)) {
return;
}
$field->migrateSettings($customSettings);
$field->write();
}
$field->migrateSettings($customSettings);
$field->write();
}
/**
* Create or find an existing field with the matched specification
*
* @param EditableFormField $field
* @param string $stage
* @param string $conditionOption
* @param string $display
* @param string $conditionFieldName
* @param string $value
* @return EditableCustomRule
*/
protected function findOrCreateRule(EditableFormField $field, $stage, $conditionOption, $display, $conditionFieldName, $value) {
// Get id of field
$conditionField = $conditionFieldName
? EditableFormField::get()->filter('Name', $conditionFieldName)->first()
: null;
/**
* Create or find an existing field with the matched specification
*
* @param EditableFormField $field
* @param string $stage
* @param string $conditionOption
* @param string $display
* @param string $conditionFieldName
* @param string $value
* @return EditableCustomRule
*/
protected function findOrCreateRule(EditableFormField $field, $stage, $conditionOption, $display, $conditionFieldName, $value)
{
// Get id of field
$conditionField = $conditionFieldName
? EditableFormField::get()->filter('Name', $conditionFieldName)->first()
: null;
// If live, search stage record for matching one
if($stage === 'Live') {
$list = Versioned::get_by_stage('EditableCustomRule', 'Stage')
->filter(array(
'ParentID' => $field->ID,
'ConditionFieldID' => $conditionField ? $conditionField->ID : 0,
'Display' => $display,
'ConditionOption' => $conditionOption
));
if($value) {
$list = $list->filter('FieldValue', $value);
} else {
$list = $list->where('"FieldValue" IS NULL OR "FieldValue" = \'\'');
}
$rule = $list->first();
if($rule) {
$rule->write();
$rule->publish("Stage", "Live");
return $rule;
}
}
// If live, search stage record for matching one
if ($stage === 'Live') {
$list = Versioned::get_by_stage('EditableCustomRule', 'Stage')
->filter(array(
'ParentID' => $field->ID,
'ConditionFieldID' => $conditionField ? $conditionField->ID : 0,
'Display' => $display,
'ConditionOption' => $conditionOption
));
if ($value) {
$list = $list->filter('FieldValue', $value);
} else {
$list = $list->where('"FieldValue" IS NULL OR "FieldValue" = \'\'');
}
$rule = $list->first();
if ($rule) {
$rule->write();
$rule->publish("Stage", "Live");
return $rule;
}
}
// If none found, or in stage, create new record
$rule = new EditableCustomRule();
$rule->ParentID = $field->ID;
$rule->ConditionFieldID = $conditionField ? $conditionField->ID : 0;
$rule->Display = $display;
$rule->ConditionOption = $conditionOption;
$rule->FieldValue = $value;
$rule->write();
return $rule;
}
// If none found, or in stage, create new record
$rule = new EditableCustomRule();
$rule->ParentID = $field->ID;
$rule->ConditionFieldID = $conditionField ? $conditionField->ID : 0;
$rule->Display = $display;
$rule->ConditionOption = $conditionOption;
$rule->FieldValue = $value;
$rule->write();
return $rule;
}
public function log($message) {
if($this->getQuiet()) {
return;
}
if(Director::is_cli()) {
echo "{$message}\n";
} else {
echo "{$message}<br />";
}
}
public function log($message)
{
if ($this->getQuiet()) {
return;
}
if (Director::is_cli()) {
echo "{$message}\n";
} else {
echo "{$message}<br />";
}
}
/**
* Set if this service should be quiet
*
* @param bool $quiet
* @return $ths
*/
public function setQuiet($quiet) {
$this->quiet = $quiet;
return $this;
}
public function getQuiet() {
return $this->quiet;
}
/**
* Set if this service should be quiet
*
* @param bool $quiet
* @return $ths
*/
public function setQuiet($quiet)
{
$this->quiet = $quiet;
return $this;
}
public function getQuiet()
{
return $this->quiet;
}
}

View File

@ -5,17 +5,19 @@
*
* @author dmooyman
*/
class UserFormsUpgradeTask extends BuildTask {
class UserFormsUpgradeTask extends BuildTask
{
protected $title = "UserForms 3.0 Migration Tool";
protected $title = "UserForms 3.0 Migration Tool";
protected $description = "Upgrade tool for sites upgrading to userforms 3.0";
protected $description = "Upgrade tool for sites upgrading to userforms 3.0";
public function run($request) {
$service = Injector::inst()->create('UserFormsUpgradeService');
$service->log("Upgrading userforms module");
$service->setQuiet(false)
->run();
$service->log("Done");
}
public function run($request)
{
$service = Injector::inst()->create('UserFormsUpgradeService');
$service->log("Upgrading userforms module");
$service->setQuiet(false)
->run();
$service->log("Done");
}
}

View File

@ -10,30 +10,29 @@
* @package userforms
*/
class UserFormsVersionedTask extends MigrationTask {
class UserFormsVersionedTask extends MigrationTask
{
protected $title = "UserForms Versioned Initial Migration";
protected $title = "UserForms Versioned Initial Migration";
protected $description = "Publishes the existing forms";
protected $description = "Publishes the existing forms";
/**
* Publish the existing forms.
*
*/
public function run($request) {
$forms = Versioned::get_by_stage('UserDefinedForm', 'Live');
/**
* Publish the existing forms.
*
*/
public function run($request)
{
$forms = Versioned::get_by_stage('UserDefinedForm', 'Live');
if($forms) {
foreach($forms as $form) {
echo "Publishing $form->Title <br />";
$form->doPublish();
}
echo "Complete";
}
else {
echo "No Forms Found";
}
}
if ($forms) {
foreach ($forms as $form) {
echo "Publishing $form->Title <br />";
$form->doPublish();
}
echo "Complete";
} else {
echo "No Forms Found";
}
}
}

View File

@ -4,167 +4,178 @@
* @package userforms
*/
class EditableFormFieldTest extends FunctionalTest {
class EditableFormFieldTest extends FunctionalTest
{
static $fixture_file = 'userforms/tests/EditableFormFieldTest.yml';
public static $fixture_file = 'userforms/tests/EditableFormFieldTest.yml';
function testFormFieldPermissions() {
$text = $this->objFromFixture('EditableTextField', 'basic-text');
public function testFormFieldPermissions()
{
$text = $this->objFromFixture('EditableTextField', 'basic-text');
$this->logInWithPermission('ADMIN');
$this->assertTrue($text->canCreate());
$this->assertTrue($text->canView());
$this->assertTrue($text->canEdit());
$this->assertTrue($text->canDelete());
$this->logInWithPermission('ADMIN');
$this->assertTrue($text->canCreate());
$this->assertTrue($text->canView());
$this->assertTrue($text->canEdit());
$this->assertTrue($text->canDelete());
$text->setReadonly(true);
$this->assertTrue($text->canView());
$this->assertFalse($text->canEdit());
$this->assertFalse($text->canDelete());
$text->setReadonly(true);
$this->assertTrue($text->canView());
$this->assertFalse($text->canEdit());
$this->assertFalse($text->canDelete());
$text->setReadonly(false);
$this->assertTrue($text->canView());
$this->assertTrue($text->canEdit());
$this->assertTrue($text->canDelete());
$text->setReadonly(false);
$this->assertTrue($text->canView());
$this->assertTrue($text->canEdit());
$this->assertTrue($text->canDelete());
$member = Member::currentUser();
$member->logout();
$member = Member::currentUser();
$member->logout();
$this->logInWithPermission('SITETREE_VIEW_ALL');
$this->assertFalse($text->canCreate());
$this->logInWithPermission('SITETREE_VIEW_ALL');
$this->assertFalse($text->canCreate());
$text->setReadonly(false);
$this->assertTrue($text->canView());
$this->assertFalse($text->canEdit());
$this->assertFalse($text->canDelete());
$text->setReadonly(false);
$this->assertTrue($text->canView());
$this->assertFalse($text->canEdit());
$this->assertFalse($text->canDelete());
$text->setReadonly(true);
$this->assertTrue($text->canView());
$this->assertFalse($text->canEdit());
$this->assertFalse($text->canDelete());
}
$text->setReadonly(true);
$this->assertTrue($text->canView());
$this->assertFalse($text->canEdit());
$this->assertFalse($text->canDelete());
}
function testCustomRules() {
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'custom-rules-form');
public function testCustomRules()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'custom-rules-form');
$checkbox = $form->Fields()->find('ClassName', 'EditableCheckbox');
$field = $form->Fields()->find('ClassName', 'EditableTextField');
$checkbox = $form->Fields()->find('ClassName', 'EditableCheckbox');
$field = $form->Fields()->find('ClassName', 'EditableTextField');
$rules = $checkbox->DisplayRules();
$rules = $checkbox->DisplayRules();
// form has 2 fields - a checkbox and a text field
// it has 1 rule - when ticked the checkbox hides the text field
$this->assertEquals(1, $rules->Count());
$this->assertEquals($rules, $checkbox->EffectiveDisplayRules());
// form has 2 fields - a checkbox and a text field
// it has 1 rule - when ticked the checkbox hides the text field
$this->assertEquals(1, $rules->Count());
$this->assertEquals($rules, $checkbox->EffectiveDisplayRules());
$checkboxRule = $rules->First();
$checkboxRule->ConditionFieldID = $field->ID;
$checkboxRule = $rules->First();
$checkboxRule->ConditionFieldID = $field->ID;
$this->assertEquals($checkboxRule->Display, 'Hide');
$this->assertEquals($checkboxRule->ConditionOption, 'HasValue');
$this->assertEquals($checkboxRule->FieldValue, '6');
$this->assertEquals($checkboxRule->Display, 'Hide');
$this->assertEquals($checkboxRule->ConditionOption, 'HasValue');
$this->assertEquals($checkboxRule->FieldValue, '6');
// If field is required then all custom rules are disabled
$checkbox->Required = true;
$this->assertEquals(0, $checkbox->EffectiveDisplayRules()->count());
}
// If field is required then all custom rules are disabled
$checkbox->Required = true;
$this->assertEquals(0, $checkbox->EffectiveDisplayRules()->count());
}
/**
* @covers EditableOption::getValue
*/
public function testEditableOptionEmptyValue() {
$option = $this->objFromFixture('EditableOption', 'option-1');
$option->Value = '';
public function testEditableOptionEmptyValue()
{
$option = $this->objFromFixture('EditableOption', 'option-1');
$option->Value = '';
// Disallow empty values
EditableOption::set_allow_empty_values(false);
$this->assertEquals($option->Title, $option->Value);
$this->assertEquals($option->Title, $option->Value);
$option->Value = 'test';
$this->assertEquals('test', $option->Value);
$option->Value = 'test';
$this->assertEquals('test', $option->Value);
// Allow empty values
EditableOption::set_allow_empty_values(true);
$option->Value = '';
$this->assertEquals('', $option->Value);
$option->Value = '';
$this->assertEquals('', $option->Value);
}
function testEditableDropdownField() {
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
public function testEditableDropdownField()
{
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
$field = $dropdown->getFormField();
$field = $dropdown->getFormField();
$this->assertThat($field, $this->isInstanceOf('DropdownField'));
$values = $field->getSource();
$this->assertThat($field, $this->isInstanceOf('DropdownField'));
$values = $field->getSource();
$this->assertEquals(array('Option 1' => 'Option 1', 'Option 2' => 'Option 2'), $values);
}
$this->assertEquals(array('Option 1' => 'Option 1', 'Option 2' => 'Option 2'), $values);
}
function testEditableRadioField() {
$radio = $this->objFromFixture('EditableRadioField', 'radio-field');
public function testEditableRadioField()
{
$radio = $this->objFromFixture('EditableRadioField', 'radio-field');
$field = $radio->getFormField();
$field = $radio->getFormField();
$this->assertThat($field, $this->isInstanceOf('OptionsetField'));
$values = $field->getSource();
$this->assertThat($field, $this->isInstanceOf('OptionsetField'));
$values = $field->getSource();
$this->assertEquals(array('Option 5' => 'Option 5', 'Option 6' => 'Option 6'), $values);
}
$this->assertEquals(array('Option 5' => 'Option 5', 'Option 6' => 'Option 6'), $values);
}
function testMultipleOptionDuplication() {
$dropdown = $this->objFromFixture('EditableDropdown','basic-dropdown');
public function testMultipleOptionDuplication()
{
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
$clone = $dropdown->duplicate();
$clone = $dropdown->duplicate();
$this->assertEquals($clone->Options()->Count(), $dropdown->Options()->Count());
$this->assertEquals($clone->Options()->Count(), $dropdown->Options()->Count());
foreach($clone->Options() as $option) {
$orginal = $dropdown->Options()->find('Title', $option->Title);
foreach ($clone->Options() as $option) {
$orginal = $dropdown->Options()->find('Title', $option->Title);
$this->assertEquals($orginal->Sort, $option->Sort);
}
}
$this->assertEquals($orginal->Sort, $option->Sort);
}
}
public function testFileField() {
$fileField = $this->objFromFixture('EditableFileField', 'file-field');
$formField = $fileField->getFormField();
public function testFileField()
{
$fileField = $this->objFromFixture('EditableFileField', 'file-field');
$formField = $fileField->getFormField();
$this->assertContains('jpg', $formField->getValidator()->getAllowedExtensions());
$this->assertNotContains('notallowedextension', $formField->getValidator()->getAllowedExtensions());
}
$this->assertContains('jpg', $formField->getValidator()->getAllowedExtensions());
$this->assertNotContains('notallowedextension', $formField->getValidator()->getAllowedExtensions());
}
public function testFileFieldAllowedExtensionsBlacklist() {
Config::inst()->update('EditableFileField', 'allowed_extensions_blacklist', array('jpg'));
$fileField = $this->objFromFixture('EditableFileField', 'file-field');
$formField = $fileField->getFormField();
public function testFileFieldAllowedExtensionsBlacklist()
{
Config::inst()->update('EditableFileField', 'allowed_extensions_blacklist', array('jpg'));
$fileField = $this->objFromFixture('EditableFileField', 'file-field');
$formField = $fileField->getFormField();
$this->assertNotContains('jpg', $formField->getValidator()->getAllowedExtensions());
}
$this->assertNotContains('jpg', $formField->getValidator()->getAllowedExtensions());
}
/**
* Verify that unique names are automatically generated for each formfield
*/
public function testUniqueName() {
$textfield1 = new EditableTextField();
$this->assertEmpty($textfield1->Name);
/**
* Verify that unique names are automatically generated for each formfield
*/
public function testUniqueName()
{
$textfield1 = new EditableTextField();
$this->assertEmpty($textfield1->Name);
// Write values
$textfield1->write();
$textfield2 = new EditableTextField();
$textfield2->write();
$checkboxField = new EditableCheckbox();
$checkboxField->write();
// Write values
$textfield1->write();
$textfield2 = new EditableTextField();
$textfield2->write();
$checkboxField = new EditableCheckbox();
$checkboxField->write();
// Test values are in the expected format
$this->assertRegExp('/^EditableTextField_.+/', $textfield1->Name);
$this->assertRegExp('/^EditableTextField_.+/', $textfield2->Name);
$this->assertRegExp('/^EditableCheckbox_.+/', $checkboxField->Name);
$this->assertNotEquals($textfield1->Name, $textfield2->Name);
}
// Test values are in the expected format
$this->assertRegExp('/^EditableTextField_.+/', $textfield1->Name);
$this->assertRegExp('/^EditableTextField_.+/', $textfield2->Name);
$this->assertRegExp('/^EditableCheckbox_.+/', $checkboxField->Name);
$this->assertNotEquals($textfield1->Name, $textfield2->Name);
}
public function testLengthRange() {
public function testLengthRange()
{
/** @var EditableTextField $textField */
$textField = $this->objFromFixture('EditableTextField', 'basic-text');
@ -193,6 +204,4 @@ class EditableFormFieldTest extends FunctionalTest {
$this->assertEquals(10, $attributes['data-rule-minlength']);
$this->assertEquals(20, $attributes['data-rule-maxlength']);
}
}

View File

@ -3,40 +3,44 @@
/**
* Tests the {@see EditableLiteralField} class
*/
class EditableLiteralFieldTest extends SapphireTest {
class EditableLiteralFieldTest extends SapphireTest
{
public function setUp() {
parent::setUp();
HtmlEditorConfig::set_active('cms');
}
public function setUp()
{
parent::setUp();
HtmlEditorConfig::set_active('cms');
}
/**
* Tests the sanitisation of HTML content
*/
public function testSanitisation() {
$rawContent = '<h1>Welcome</h1><script>alert("Hello!");</script><p>Giant Robots!</p>';
$safeContent = '<h1>Welcome</h1><p>Giant Robots!</p>';
$field = new EditableLiteralField();
/**
* Tests the sanitisation of HTML content
*/
public function testSanitisation()
{
$rawContent = '<h1>Welcome</h1><script>alert("Hello!");</script><p>Giant Robots!</p>';
$safeContent = '<h1>Welcome</h1><p>Giant Robots!</p>';
$field = new EditableLiteralField();
// Test with sanitisation enabled
Config::inst()->update('HtmlEditorField', 'sanitise_server_side', true);
$field->setContent($rawContent);
$this->assertEquals($safeContent, $field->getContent());
// Test with sanitisation enabled
Config::inst()->update('HtmlEditorField', 'sanitise_server_side', true);
$field->setContent($rawContent);
$this->assertEquals($safeContent, $field->getContent());
// Test with sanitisation disabled
Config::inst()->remove('HtmlEditorField', 'sanitise_server_side');
$field->setContent($rawContent);
$this->assertEquals($rawContent, $field->getContent());
}
// Test with sanitisation disabled
Config::inst()->remove('HtmlEditorField', 'sanitise_server_side');
$field->setContent($rawContent);
$this->assertEquals($rawContent, $field->getContent());
}
public function testHideLabel() {
$field = new EditableLiteralField(array(
'Title' => 'Test label'
));
public function testHideLabel()
{
$field = new EditableLiteralField(array(
'Title' => 'Test label'
));
$this->assertContains('Test label', $field->getFormField()->Field());
$this->assertContains('Test label', $field->getFormField()->Field());
$field->HideLabel = true;
$this->assertNotContains('Test label', $field->getFormField()->Field());
}
$field->HideLabel = true;
$this->assertNotContains('Test label', $field->getFormField()->Field());
}
}

View File

@ -5,79 +5,85 @@
*
* @author dmooyman
*/
class SecureEditableFileFieldTest extends SapphireTest {
class SecureEditableFileFieldTest extends SapphireTest
{
protected $usesDatabase = true;
protected $usesDatabase = true;
public function setUp() {
parent::setUp();
public function setUp()
{
parent::setUp();
if(!class_exists('SecureFileExtension')) {
$this->skipTest = true;
$this->markTestSkipped(get_class() . ' skipped unless running with securefiles');
}
Config::inst()->update('EditableFileField', 'secure_folder_name', 'SecureEditableFileFieldTest/SecureUploads');
$this->clearPath();
}
if (!class_exists('SecureFileExtension')) {
$this->skipTest = true;
$this->markTestSkipped(get_class() . ' skipped unless running with securefiles');
}
Config::inst()->update('EditableFileField', 'secure_folder_name', 'SecureEditableFileFieldTest/SecureUploads');
$this->clearPath();
}
public function tearDown() {
$this->clearPath();
parent::tearDown();
}
public function tearDown()
{
$this->clearPath();
parent::tearDown();
}
protected function clearPath() {
if(file_exists(ASSETS_PATH . '/SecureEditableFileFieldTest')) {
Filesystem::removeFolder(ASSETS_PATH . '/SecureEditableFileFieldTest');
}
}
protected function clearPath()
{
if (file_exists(ASSETS_PATH . '/SecureEditableFileFieldTest')) {
Filesystem::removeFolder(ASSETS_PATH . '/SecureEditableFileFieldTest');
}
}
/**
* Test that newly created folders are secure
*/
public function testCreateFolder() {
$field = new EditableFileField();
$field->write();
$this->assertTrue($field->getIsSecure());
$this->assertTrue($field->Folder()->exists());
$this->assertEquals('assets/SecureEditableFileFieldTest/SecureUploads/', $field->Folder()->Filename);
$this->assertEquals('OnlyTheseUsers', $field->Folder()->CanViewType);
$this->assertEquals(1, $field->Folder()->ViewerGroups()->first()->Permissions()->filter('code', 'ADMIN')->count());
}
/**
* Test that newly created folders are secure
*/
public function testCreateFolder()
{
$field = new EditableFileField();
$field->write();
$this->assertTrue($field->getIsSecure());
$this->assertTrue($field->Folder()->exists());
$this->assertEquals('assets/SecureEditableFileFieldTest/SecureUploads/', $field->Folder()->Filename);
$this->assertEquals('OnlyTheseUsers', $field->Folder()->CanViewType);
$this->assertEquals(1, $field->Folder()->ViewerGroups()->first()->Permissions()->filter('code', 'ADMIN')->count());
}
/**
* Test new folders that are created without security enabled
*/
public function testCreateInsecure() {
Config::inst()->update('EditableFileField', 'disable_security', true);
/**
* Test new folders that are created without security enabled
*/
public function testCreateInsecure()
{
Config::inst()->update('EditableFileField', 'disable_security', true);
// Esure folder is created without a folder
$field = new EditableFileField();
$field->write();
$this->assertFalse($field->getIsSecure());
$this->assertFalse($field->Folder()->exists());
// Esure folder is created without a folder
$field = new EditableFileField();
$field->write();
$this->assertFalse($field->getIsSecure());
$this->assertFalse($field->Folder()->exists());
// Assigning a non-secure folder doesn't secure this
$folder = Folder::find_or_make('SecureEditableFileFieldTest/PublicFolder');
$field->FolderID = $folder->ID;
$field->write();
// Assigning a non-secure folder doesn't secure this
$folder = Folder::find_or_make('SecureEditableFileFieldTest/PublicFolder');
$field->FolderID = $folder->ID;
$field->write();
$this->assertFalse($field->getIsSecure());
$this->assertTrue($field->Folder()->exists());
$this->assertEquals('assets/SecureEditableFileFieldTest/PublicFolder/', $field->Folder()->Filename);
$this->assertEquals('Inherit', $field->Folder()->CanViewType);
$this->assertFalse($field->getIsSecure());
$this->assertTrue($field->Folder()->exists());
$this->assertEquals('assets/SecureEditableFileFieldTest/PublicFolder/', $field->Folder()->Filename);
$this->assertEquals('Inherit', $field->Folder()->CanViewType);
// Enabling security and re-saving will force this field to be made secure (but not changed)
Config::inst()->update('EditableFileField', 'disable_security', false);
singleton('EditableFileField')->requireDefaultRecords();
// Enabling security and re-saving will force this field to be made secure (but not changed)
Config::inst()->update('EditableFileField', 'disable_security', false);
singleton('EditableFileField')->requireDefaultRecords();
// Reload record from DB
$field = EditableFileField::get()->byID($field->ID);
// Reload record from DB
$field = EditableFileField::get()->byID($field->ID);
// Existing folder is now secured (retro-actively secures any old uploads)
$this->assertTrue($field->getIsSecure());
$this->assertTrue($field->Folder()->exists());
$this->assertEquals('assets/SecureEditableFileFieldTest/PublicFolder/', $field->Folder()->Filename);
$this->assertEquals('OnlyTheseUsers', $field->Folder()->CanViewType);
$this->assertEquals(1, $field->Folder()->ViewerGroups()->first()->Permissions()->filter('code', 'ADMIN')->count());
}
}
// Existing folder is now secured (retro-actively secures any old uploads)
$this->assertTrue($field->getIsSecure());
$this->assertTrue($field->Folder()->exists());
$this->assertEquals('assets/SecureEditableFileFieldTest/PublicFolder/', $field->Folder()->Filename);
$this->assertEquals('OnlyTheseUsers', $field->Folder()->CanViewType);
$this->assertEquals(1, $field->Folder()->ViewerGroups()->first()->Permissions()->filter('code', 'ADMIN')->count());
}
}

View File

@ -4,282 +4,296 @@
* @package userforms
*/
class UserDefinedFormControllerTest extends FunctionalTest {
class UserDefinedFormControllerTest extends FunctionalTest
{
static $fixture_file = 'UserDefinedFormTest.yml';
public static $fixture_file = 'UserDefinedFormTest.yml';
public function testProcess() {
$form = $this->setupFormFrontend();
public function testProcess()
{
$form = $this->setupFormFrontend();
$controller = new UserDefinedFormControllerTest_Controller($form);
$controller = new UserDefinedFormControllerTest_Controller($form);
$this->autoFollowRedirection = false;
$this->clearEmails();
$this->autoFollowRedirection = false;
$this->clearEmails();
// load the form
$this->get($form->URLSegment);
// load the form
$this->get($form->URLSegment);
$field = $this->objFromFixture('EditableTextField', 'basic-text');
$field = $this->objFromFixture('EditableTextField', 'basic-text');
$response = $this->submitForm('UserForm_Form', null, array($field->Name => 'Basic Value'));
$response = $this->submitForm('UserForm_Form', null, array($field->Name => 'Basic Value'));
// should have a submitted form field now
$submitted = DataObject::get('SubmittedFormField', "\"Name\" = 'basic-text-name'");
$this->assertDOSAllMatch(array('Name' => 'basic-text-name', 'Value' => 'Basic Value', 'Title' => 'Basic Text Field'), $submitted);
// should have a submitted form field now
$submitted = DataObject::get('SubmittedFormField', "\"Name\" = 'basic-text-name'");
$this->assertDOSAllMatch(array('Name' => 'basic-text-name', 'Value' => 'Basic Value', 'Title' => 'Basic Text Field'), $submitted);
// check emails
$this->assertEmailSent('test@example.com', 'no-reply@example.com', 'Email Subject');
$email = $this->findEmail('test@example.com', 'no-reply@example.com', 'Email Subject');
// check emails
$this->assertEmailSent('test@example.com', 'no-reply@example.com', 'Email Subject');
$email = $this->findEmail('test@example.com', 'no-reply@example.com', 'Email Subject');
// assert that the email has the field title and the value html email
$parser = new CSSContentParser($email['content']);
$title = $parser->getBySelector('strong');
// assert that the email has the field title and the value html email
$parser = new CSSContentParser($email['content']);
$title = $parser->getBySelector('strong');
$this->assertEquals('Basic Text Field', (string) $title[0], 'Email contains the field name');
$this->assertEquals('Basic Text Field', (string) $title[0], 'Email contains the field name');
$value = $parser->getBySelector('dd');
$this->assertEquals('Basic Value', (string) $value[0], 'Email contains the value');
$value = $parser->getBySelector('dd');
$this->assertEquals('Basic Value', (string) $value[0], 'Email contains the value');
// no html
$this->assertEmailSent('nohtml@example.com', 'no-reply@example.com', 'Email Subject');
$nohtml = $this->findEmail('nohtml@example.com', 'no-reply@example.com', 'Email Subject');
// no html
$this->assertEmailSent('nohtml@example.com', 'no-reply@example.com', 'Email Subject');
$nohtml = $this->findEmail('nohtml@example.com', 'no-reply@example.com', 'Email Subject');
$this->assertContains('Basic Text Field: Basic Value', $nohtml['content'], 'Email contains no html');
$this->assertContains('Basic Text Field: Basic Value', $nohtml['content'], 'Email contains no html');
// no data
$this->assertEmailSent('nodata@example.com', 'no-reply@example.com', 'Email Subject');
$nodata = $this->findEmail('nodata@example.com', 'no-reply@example.com', 'Email Subject');
// no data
$this->assertEmailSent('nodata@example.com', 'no-reply@example.com', 'Email Subject');
$nodata = $this->findEmail('nodata@example.com', 'no-reply@example.com', 'Email Subject');
$parser = new CSSContentParser($nodata['content']);
$list = $parser->getBySelector('dl');
$parser = new CSSContentParser($nodata['content']);
$list = $parser->getBySelector('dl');
$this->assertFalse(isset($list[0]), 'Email contains no fields');
$this->assertFalse(isset($list[0]), 'Email contains no fields');
// check to see if the user was redirected (301)
$this->assertEquals($response->getStatusCode(), 302);
$this->assertStringEndsWith('finished#uff', $response->getHeader('Location'));
}
// check to see if the user was redirected (301)
$this->assertEquals($response->getStatusCode(), 302);
$this->assertStringEndsWith('finished#uff', $response->getHeader('Location'));
}
public function testValidation() {
$form = $this->setupFormFrontend('email-form');
public function testValidation()
{
$form = $this->setupFormFrontend('email-form');
// Post with no fields
$this->get($form->URLSegment);
$response = $this->submitForm('UserForm_Form', null, array());
$this->assertPartialMatchBySelector(
'.field .message',
array('This field is required')
);
// Post with no fields
$this->get($form->URLSegment);
$response = $this->submitForm('UserForm_Form', null, array());
$this->assertPartialMatchBySelector(
'.field .message',
array('This field is required')
);
// Post with all fields, but invalid email
$this->get($form->URLSegment);
$this->submitForm('UserForm_Form', null, array(
'required-email' => 'invalid',
'required-text' => 'bob'
));
$this->assertPartialMatchBySelector(
'.field .message',
array('Please enter an email address')
);
// Post with all fields, but invalid email
$this->get($form->URLSegment);
$this->submitForm('UserForm_Form', null, array(
'required-email' => 'invalid',
'required-text' => 'bob'
));
$this->assertPartialMatchBySelector(
'.field .message',
array('Please enter an email address')
);
// Post with only required
$this->get($form->URLSegment);
$this->submitForm('UserForm_Form', null, array(
'required-text' => 'bob'
));
$this->assertPartialMatchBySelector(
'p',
array("Thanks, we've received your submission.")
);
}
// Post with only required
$this->get($form->URLSegment);
$this->submitForm('UserForm_Form', null, array(
'required-text' => 'bob'
));
$this->assertPartialMatchBySelector(
'p',
array("Thanks, we've received your submission.")
);
}
public function testFinished() {
$form = $this->setupFormFrontend();
public function testFinished()
{
$form = $this->setupFormFrontend();
// set formProcessed and SecurityID to replicate the form being filled out
$this->session()->inst_set('SecurityID', 1);
$this->session()->inst_set('FormProcessed', 1);
// set formProcessed and SecurityID to replicate the form being filled out
$this->session()->inst_set('SecurityID', 1);
$this->session()->inst_set('FormProcessed', 1);
$response = $this->get($form->URLSegment.'/finished');
$response = $this->get($form->URLSegment.'/finished');
$this->assertContains($form->OnCompleteMessage ,$response->getBody());
}
$this->assertContains($form->OnCompleteMessage, $response->getBody());
}
public function testAppendingFinished() {
$form = $this->setupFormFrontend();
public function testAppendingFinished()
{
$form = $this->setupFormFrontend();
// replicate finished being added to the end of the form URL without the form being filled out
$this->session()->inst_set('SecurityID', 1);
$this->session()->inst_set('FormProcessed', null);
// replicate finished being added to the end of the form URL without the form being filled out
$this->session()->inst_set('SecurityID', 1);
$this->session()->inst_set('FormProcessed', null);
$response = $this->get($form->URLSegment.'/finished');
$response = $this->get($form->URLSegment.'/finished');
$this->assertNotContains($form->OnCompleteMessage ,$response->getBody());
}
$this->assertNotContains($form->OnCompleteMessage, $response->getBody());
}
public function testForm() {
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
public function testForm()
{
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$controller = new UserDefinedFormControllerTest_Controller($form);
$controller = new UserDefinedFormControllerTest_Controller($form);
// test form
$this->assertEquals($controller->Form()->getName(), 'Form', 'The form is referenced as Form');
$this->assertEquals($controller->Form()->Fields()->Count(), 1); // disabled SecurityID token fields
$this->assertEquals($controller->Form()->Actions()->Count(), 1);
$this->assertEquals(count($controller->Form()->getValidator()->getRequired()), 0);
// test form
$this->assertEquals($controller->Form()->getName(), 'Form', 'The form is referenced as Form');
$this->assertEquals($controller->Form()->Fields()->Count(), 1); // disabled SecurityID token fields
$this->assertEquals($controller->Form()->Actions()->Count(), 1);
$this->assertEquals(count($controller->Form()->getValidator()->getRequired()), 0);
$requiredForm = $this->objFromFixture('UserDefinedForm', 'validation-form');
$controller = new UserDefinedFormControllerTest_Controller($requiredForm);
$requiredForm = $this->objFromFixture('UserDefinedForm', 'validation-form');
$controller = new UserDefinedFormControllerTest_Controller($requiredForm);
$this->assertEquals($controller->Form()->Fields()->Count(), 1); // disabled SecurityID token fields
$this->assertEquals($controller->Form()->Actions()->Count(), 1);
$this->assertEquals(count($controller->Form()->getValidator()->getRequired()), 1);
}
$this->assertEquals($controller->Form()->Fields()->Count(), 1); // disabled SecurityID token fields
$this->assertEquals($controller->Form()->Actions()->Count(), 1);
$this->assertEquals(count($controller->Form()->getValidator()->getRequired()), 1);
}
public function testGetFormFields() {
// generating the fieldset of fields
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
public function testGetFormFields()
{
// generating the fieldset of fields
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$controller = new UserDefinedFormControllerTest_Controller($form);
$controller = new UserDefinedFormControllerTest_Controller($form);
$formSteps = $controller->Form()->getFormFields();
$firstStep = $formSteps->first();
$formSteps = $controller->Form()->getFormFields();
$firstStep = $formSteps->first();
$this->assertEquals($formSteps->Count(), 1);
$this->assertEquals($firstStep->getChildren()->Count(), 1);
$this->assertEquals($formSteps->Count(), 1);
$this->assertEquals($firstStep->getChildren()->Count(), 1);
// custom error message on a form field
$requiredForm = $this->objFromFixture('UserDefinedForm', 'validation-form');
$controller = new UserDefinedFormControllerTest_Controller($requiredForm);
// custom error message on a form field
$requiredForm = $this->objFromFixture('UserDefinedForm', 'validation-form');
$controller = new UserDefinedFormControllerTest_Controller($requiredForm);
UserDefinedForm::config()->required_identifier = "*";
UserDefinedForm::config()->required_identifier = "*";
$formSteps = $controller->Form()->getFormFields();
$firstStep = $formSteps->first();
$firstField = $firstStep->getChildren()->first();
$formSteps = $controller->Form()->getFormFields();
$firstStep = $formSteps->first();
$firstField = $firstStep->getChildren()->first();
$this->assertEquals('Custom Error Message', $firstField->getCustomValidationMessage());
$this->assertEquals($firstField->Title(), 'Required Text Field <span class=\'required-identifier\'>*</span>');
$this->assertEquals('Custom Error Message', $firstField->getCustomValidationMessage());
$this->assertEquals($firstField->Title(), 'Required Text Field <span class=\'required-identifier\'>*</span>');
// test custom right title
$field = $form->Fields()->limit(1, 1)->First();
$field->RightTitle = 'Right Title';
$field->write();
// test custom right title
$field = $form->Fields()->limit(1, 1)->First();
$field->RightTitle = 'Right Title';
$field->write();
$controller = new UserDefinedFormControllerTest_Controller($form);
$formSteps = $controller->Form()->getFormFields();
$firstStep = $formSteps->first();
$controller = new UserDefinedFormControllerTest_Controller($form);
$formSteps = $controller->Form()->getFormFields();
$firstStep = $formSteps->first();
$this->assertEquals($firstStep->getChildren()->First()->RightTitle(), "Right Title");
$this->assertEquals($firstStep->getChildren()->First()->RightTitle(), "Right Title");
// test empty form
$emptyForm = $this->objFromFixture('UserDefinedForm', 'empty-form');
$controller = new UserDefinedFormControllerTest_Controller($emptyForm);
// test empty form
$emptyForm = $this->objFromFixture('UserDefinedForm', 'empty-form');
$controller = new UserDefinedFormControllerTest_Controller($emptyForm);
$this->assertFalse($controller->Form()->getFormFields()->exists());
}
$this->assertFalse($controller->Form()->getFormFields()->exists());
}
public function testGetFormActions()
{
// generating the fieldset of actions
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
public function testGetFormActions()
{
// generating the fieldset of actions
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$controller = new UserDefinedFormControllerTest_Controller($form);
$actions = $controller->Form()->getFormActions();
$controller = new UserDefinedFormControllerTest_Controller($form);
$actions = $controller->Form()->getFormActions();
// by default will have 1 submit button which links to process
$expected = new FieldList(new FormAction('process', 'Submit'));
$expected->setForm($controller->Form());
// by default will have 1 submit button which links to process
$expected = new FieldList(new FormAction('process', 'Submit'));
$expected->setForm($controller->Form());
$this->assertEquals($actions, $expected);
$this->assertEquals($actions, $expected);
// the custom popup should have a reset button and a custom text
$custom = $this->objFromFixture('UserDefinedForm', 'form-with-reset-and-custom-action');
$controller = new UserDefinedFormControllerTest_Controller($custom);
$actions = $controller->Form()->getFormActions();
// the custom popup should have a reset button and a custom text
$custom = $this->objFromFixture('UserDefinedForm', 'form-with-reset-and-custom-action');
$controller = new UserDefinedFormControllerTest_Controller($custom);
$actions = $controller->Form()->getFormActions();
$expected = new FieldList(new FormAction('process', 'Custom Button'));
$expected->push(new ResetFormAction("clearForm", "Clear"));
$expected->setForm($controller->Form());
$expected = new FieldList(new FormAction('process', 'Custom Button'));
$expected->push(new ResetFormAction("clearForm", "Clear"));
$expected->setForm($controller->Form());
$this->assertEquals($actions, $expected);
}
$this->assertEquals($actions, $expected);
}
public function testRenderingIntoFormTemplate()
{
$form = $this->setupFormFrontend();
public function testRenderingIntoFormTemplate() {
$form = $this->setupFormFrontend();
$form->Content = 'This is some content without a form nested between it';
$form->doPublish();
$form->Content = 'This is some content without a form nested between it';
$form->doPublish();
$controller = new UserDefinedFormControllerTest_Controller($form);
$controller = new UserDefinedFormControllerTest_Controller($form);
// check to see if $Form is replaced to inside the content
$index = new ArrayData($controller->index());
$parser = new CSSContentParser($index->renderWith(array('UserDefinedFormControllerTest')));
// check to see if $Form is replaced to inside the content
$index = new ArrayData($controller->index());
$parser = new CSSContentParser($index->renderWith(array('UserDefinedFormControllerTest')));
$this->checkTemplateIsCorrect($parser);
}
$this->checkTemplateIsCorrect($parser);
}
public function testRenderingIntoTemplateWithSubstringReplacement()
{
$form = $this->setupFormFrontend();
public function testRenderingIntoTemplateWithSubstringReplacement() {
$form = $this->setupFormFrontend();
$controller = new UserDefinedFormControllerTest_Controller($form);
$controller = new UserDefinedFormControllerTest_Controller($form);
// check to see if $Form is replaced to inside the content
$index = new ArrayData($controller->index());
$parser = new CSSContentParser($index->renderWith(array('UserDefinedFormControllerTest')));
// check to see if $Form is replaced to inside the content
$index = new ArrayData($controller->index());
$parser = new CSSContentParser($index->renderWith(array('UserDefinedFormControllerTest')));
$this->checkTemplateIsCorrect($parser);
}
/**
* Publish a form for use on the frontend
*
* @param string $fixtureName
* @return UserDefinedForm
*/
protected function setupFormFrontend($fixtureName = 'basic-form-page')
{
$form = $this->objFromFixture('UserDefinedForm', $fixtureName);
$this->logInWithPermission('ADMIN');
$this->checkTemplateIsCorrect($parser);
}
/**
* Publish a form for use on the frontend
*
* @param string $fixtureName
* @return UserDefinedForm
*/
protected function setupFormFrontend($fixtureName = 'basic-form-page') {
$form = $this->objFromFixture('UserDefinedForm', $fixtureName);
$this->logInWithPermission('ADMIN');
$form->doPublish();
$form->doPublish();
$member = Member::currentUser();
$member->logOut();
$member = Member::currentUser();
$member->logOut();
return $form;
}
return $form;
}
public function checkTemplateIsCorrect($parser)
{
$this->assertArrayHasKey(0, $parser->getBySelector('form#UserForm_Form'));
public function checkTemplateIsCorrect($parser) {
$this->assertArrayHasKey(0, $parser->getBySelector('form#UserForm_Form'));
// check for the input
$this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
// check for the input
$this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
// check for the label and the text
$label = $parser->getBySelector('label.left');
$this->assertArrayHasKey(0, $label);
// check for the label and the text
$label = $parser->getBySelector('label.left');
$this->assertArrayHasKey(0, $label);
$this->assertEquals((string) $label[0][0], "Basic Text Field", "Label contains correct field name");
$this->assertEquals((string) $label[0][0], "Basic Text Field", "Label contains correct field name");
// check for the action
$action = $parser->getBySelector('input.action');
$this->assertArrayHasKey(0, $action);
// check for the action
$action = $parser->getBySelector('input.action');
$this->assertArrayHasKey(0, $action);
$this->assertEquals((string) $action[0]['value'], "Submit", "Submit button has default text");
}
$this->assertEquals((string) $action[0]['value'], "Submit", "Submit button has default text");
}
}
class UserDefinedFormControllerTest_Controller extends UserDefinedForm_Controller implements TestOnly {
class UserDefinedFormControllerTest_Controller extends UserDefinedForm_Controller implements TestOnly
{
/**
* Overloaded to avoid inconsistencies between 2.4.2 and 2.4.3 (disables all security tokens in unit tests by default)
*/
public function Form() {
$form = parent::Form();
/**
* Overloaded to avoid inconsistencies between 2.4.2 and 2.4.3 (disables all security tokens in unit tests by default)
*/
public function Form()
{
$form = parent::Form();
if($form) $form->disableSecurityToken();
return $form;
}
if ($form) {
$form->disableSecurityToken();
}
return $form;
}
}

View File

@ -3,421 +3,436 @@
/**
* @package userforms
*/
class UserDefinedFormTest extends FunctionalTest {
class UserDefinedFormTest extends FunctionalTest
{
static $fixture_file = 'UserDefinedFormTest.yml';
public static $fixture_file = 'UserDefinedFormTest.yml';
public function testRollbackToVersion() {
$this->markTestSkipped(
'UserDefinedForm::rollback() has not been implemented completely'
);
public function testRollbackToVersion()
{
$this->markTestSkipped(
'UserDefinedForm::rollback() has not been implemented completely'
);
// @todo
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
// @todo
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$form->SubmitButtonText = 'Button Text';
$form->write();
$form->doPublish();
$origVersion = $form->Version;
$form->SubmitButtonText = 'Button Text';
$form->write();
$form->doPublish();
$origVersion = $form->Version;
$form->SubmitButtonText = 'Updated Button Text';
$form->write();
$form->doPublish();
$form->SubmitButtonText = 'Updated Button Text';
$form->write();
$form->doPublish();
// check published site
$updated = Versioned::get_one_by_stage("UserDefinedForm", "Stage", "\"UserDefinedForm\".\"ID\" = $form->ID");
$this->assertEquals($updated->SubmitButtonText, 'Updated Button Text');
// check published site
$updated = Versioned::get_one_by_stage("UserDefinedForm", "Stage", "\"UserDefinedForm\".\"ID\" = $form->ID");
$this->assertEquals($updated->SubmitButtonText, 'Updated Button Text');
$form->doRollbackTo($origVersion);
$form->doRollbackTo($origVersion);
$orignal = Versioned::get_one_by_stage("UserDefinedForm", "Stage", "\"UserDefinedForm\".\"ID\" = $form->ID");
$this->assertEquals($orignal->SubmitButtonText, 'Button Text');
}
$orignal = Versioned::get_one_by_stage("UserDefinedForm", "Stage", "\"UserDefinedForm\".\"ID\" = $form->ID");
$this->assertEquals($orignal->SubmitButtonText, 'Button Text');
}
public function testGetCMSFields() {
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
public function testGetCMSFields()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$fields = $form->getCMSFields();
$fields = $form->getCMSFields();
$this->assertTrue($fields->dataFieldByName('Fields') !== null);
$this->assertTrue($fields->dataFieldByName('EmailRecipients') != null);
$this->assertTrue($fields->dataFieldByName('Submissions') != null);
$this->assertTrue($fields->dataFieldByName('OnCompleteMessage') != null);
}
$this->assertTrue($fields->dataFieldByName('Fields') !== null);
$this->assertTrue($fields->dataFieldByName('EmailRecipients') != null);
$this->assertTrue($fields->dataFieldByName('Submissions') != null);
$this->assertTrue($fields->dataFieldByName('OnCompleteMessage') != null);
}
public function testEmailRecipientPopup() {
$this->logInWithPermission('ADMIN');
public function testEmailRecipientPopup()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$popup = new UserDefinedForm_EmailRecipient();
$popup->FormID = $form->ID;
$popup = new UserDefinedForm_EmailRecipient();
$popup->FormID = $form->ID;
$fields = $popup->getCMSFields();
$fields = $popup->getCMSFields();
$this->assertTrue($fields->dataFieldByName('EmailSubject') !== null);
$this->assertTrue($fields->dataFieldByName('EmailFrom') !== null);
$this->assertTrue($fields->dataFieldByName('EmailAddress') !== null);
$this->assertTrue($fields->dataFieldByName('HideFormData') !== null);
$this->assertTrue($fields->dataFieldByName('SendPlain') !== null);
$this->assertTrue($fields->dataFieldByName('EmailBody') !== null);
$this->assertTrue($fields->dataFieldByName('EmailSubject') !== null);
$this->assertTrue($fields->dataFieldByName('EmailFrom') !== null);
$this->assertTrue($fields->dataFieldByName('EmailAddress') !== null);
$this->assertTrue($fields->dataFieldByName('HideFormData') !== null);
$this->assertTrue($fields->dataFieldByName('SendPlain') !== null);
$this->assertTrue($fields->dataFieldByName('EmailBody') !== null);
// add an email field, it should now add a or from X address picker
$email = $this->objFromFixture('EditableEmailField','email-field');
$form->Fields()->add($email);
// add an email field, it should now add a or from X address picker
$email = $this->objFromFixture('EditableEmailField', 'email-field');
$form->Fields()->add($email);
$popup->write();
$popup->write();
$fields = $popup->getCMSFields();
$this->assertThat($fields->dataFieldByName('SendEmailToFieldID'), $this->isInstanceOf('DropdownField'));
$fields = $popup->getCMSFields();
$this->assertThat($fields->dataFieldByName('SendEmailToFieldID'), $this->isInstanceOf('DropdownField'));
// if the front end has checkboxs or dropdown they can select from that can also be used to send things
$dropdown = $this->objFromFixture('EditableDropdown', 'department-dropdown');
$form->Fields()->add($dropdown);
// if the front end has checkboxs or dropdown they can select from that can also be used to send things
$dropdown = $this->objFromFixture('EditableDropdown', 'department-dropdown');
$form->Fields()->add($dropdown);
$fields = $popup->getCMSFields();
$this->assertTrue($fields->dataFieldByName('SendEmailToFieldID') !== null);
$fields = $popup->getCMSFields();
$this->assertTrue($fields->dataFieldByName('SendEmailToFieldID') !== null);
$popup->delete();
}
$popup->delete();
}
function testGetEmailBodyContent() {
$recipient = new UserDefinedForm_EmailRecipient();
public function testGetEmailBodyContent()
{
$recipient = new UserDefinedForm_EmailRecipient();
$emailBody = 'not html';
$emailBodyHtml = '<p>html</p>';
$emailBody = 'not html';
$emailBodyHtml = '<p>html</p>';
$recipient->EmailBody = $emailBody;
$recipient->EmailBodyHtml = $emailBodyHtml;
$recipient->write();
$recipient->EmailBody = $emailBody;
$recipient->EmailBodyHtml = $emailBodyHtml;
$recipient->write();
$this->assertEquals($recipient->SendPlain, 0);
$this->assertEquals($recipient->getEmailBodyContent(), $emailBodyHtml);
$this->assertEquals($recipient->SendPlain, 0);
$this->assertEquals($recipient->getEmailBodyContent(), $emailBodyHtml);
$recipient->SendPlain = 1;
$recipient->write();
$recipient->SendPlain = 1;
$recipient->write();
$this->assertEquals($recipient->getEmailBodyContent(), $emailBody);
$this->assertEquals($recipient->getEmailBodyContent(), $emailBody);
$recipient->delete();
}
$recipient->delete();
}
function testGetEmailTemplateDropdownValues() {
$recipient = new UserDefinedForm_EmailRecipient();
public function testGetEmailTemplateDropdownValues()
{
$recipient = new UserDefinedForm_EmailRecipient();
$defaultValues = array('SubmittedFormEmail' => 'SubmittedFormEmail');
$defaultValues = array('SubmittedFormEmail' => 'SubmittedFormEmail');
$this->assertEquals($recipient->getEmailTemplateDropdownValues(), $defaultValues);
}
$this->assertEquals($recipient->getEmailTemplateDropdownValues(), $defaultValues);
}
function testEmailTemplateExists() {
$recipient = new UserDefinedForm_EmailRecipient();
public function testEmailTemplateExists()
{
$recipient = new UserDefinedForm_EmailRecipient();
// Set the default template
$recipient->EmailTemplate = current(array_keys($recipient->getEmailTemplateDropdownValues()));
$recipient->write();
// Set the default template
$recipient->EmailTemplate = current(array_keys($recipient->getEmailTemplateDropdownValues()));
$recipient->write();
// The default template exists
$this->assertTrue($recipient->emailTemplateExists());
// The default template exists
$this->assertTrue($recipient->emailTemplateExists());
// A made up template doesn't exists
$this->assertFalse($recipient->emailTemplateExists('MyTemplateThatsNotThere'));
// A made up template doesn't exists
$this->assertFalse($recipient->emailTemplateExists('MyTemplateThatsNotThere'));
$recipient->delete();
}
$recipient->delete();
}
function testCanEditAndDeleteRecipient() {
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
public function testCanEditAndDeleteRecipient()
{
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$this->logInWithPermission('ADMIN');
foreach($form->EmailRecipients() as $recipient) {
$this->assertTrue($recipient->canEdit());
$this->assertTrue($recipient->canDelete());
}
$this->logInWithPermission('ADMIN');
foreach ($form->EmailRecipients() as $recipient) {
$this->assertTrue($recipient->canEdit());
$this->assertTrue($recipient->canDelete());
}
$member = Member::currentUser();
$member->logOut();
$member = Member::currentUser();
$member->logOut();
$this->logInWithPermission('SITETREE_VIEW_ALL');
foreach($form->EmailRecipients() as $recipient) {
$this->assertFalse($recipient->canEdit());
$this->assertFalse($recipient->canDelete());
}
}
$this->logInWithPermission('SITETREE_VIEW_ALL');
foreach ($form->EmailRecipients() as $recipient) {
$this->assertFalse($recipient->canEdit());
$this->assertFalse($recipient->canDelete());
}
}
function testPublishing() {
$this->logInWithPermission('ADMIN');
public function testPublishing()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$form->write();
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$form->write();
$form->doPublish();
$form->doPublish();
$live = Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID");
$live = Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID");
$this->assertNotNull($live);
$this->assertEquals(2, $live->Fields()->Count()); // one page and one field
$this->assertNotNull($live);
$this->assertEquals(2, $live->Fields()->Count()); // one page and one field
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
$form->Fields()->add($dropdown);
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
$form->Fields()->add($dropdown);
$stage = Versioned::get_one_by_stage("UserDefinedForm", "Stage", "\"UserDefinedForm\".\"ID\" = $form->ID");
$this->assertEquals(3, $stage->Fields()->Count());
$stage = Versioned::get_one_by_stage("UserDefinedForm", "Stage", "\"UserDefinedForm\".\"ID\" = $form->ID");
$this->assertEquals(3, $stage->Fields()->Count());
// should not have published the dropdown
$liveDropdown = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $dropdown->ID");
$this->assertNull($liveDropdown);
// should not have published the dropdown
$liveDropdown = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $dropdown->ID");
$this->assertNull($liveDropdown);
// when publishing it should have added it
$form->doPublish();
// when publishing it should have added it
$form->doPublish();
$live = Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID");
$this->assertEquals(3, $live->Fields()->Count());
$live = Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID");
$this->assertEquals(3, $live->Fields()->Count());
// edit the title
$text = $form->Fields()->limit(1, 1)->First();
$text->Title = 'Edited title';
$text->write();
// edit the title
$text = $form->Fields()->limit(1, 1)->First();
$text->Title = 'Edited title';
$text->write();
$liveText = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $text->ID");
$this->assertFalse($liveText->Title == $text->Title);
$liveText = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $text->ID");
$this->assertFalse($liveText->Title == $text->Title);
$form->doPublish();
$form->doPublish();
$liveText = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $text->ID");
$this->assertTrue($liveText->Title == $text->Title);
$liveText = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $text->ID");
$this->assertTrue($liveText->Title == $text->Title);
// Add a display rule to the dropdown
$displayRule = new EditableCustomRule();
$displayRule->ParentID = $dropdown->ID;
$displayRule->ConditionFieldID = $text->ID;
$displayRule->write();
$ruleID = $displayRule->ID;
// Add a display rule to the dropdown
$displayRule = new EditableCustomRule();
$displayRule->ParentID = $dropdown->ID;
$displayRule->ConditionFieldID = $text->ID;
$displayRule->write();
$ruleID = $displayRule->ID;
// Not live
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertEmpty($liveRule);
// Not live
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertEmpty($liveRule);
// Publish form, it's now live
$form->doPublish();
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertNotEmpty($liveRule);
// Publish form, it's now live
$form->doPublish();
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertNotEmpty($liveRule);
// Remove rule
$displayRule->delete();
// Remove rule
$displayRule->delete();
// Live rule still exists
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertNotEmpty($liveRule);
// Live rule still exists
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertNotEmpty($liveRule);
// Publish form, it should remove this rule
$form->doPublish();
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertEmpty($liveRule);
}
// Publish form, it should remove this rule
$form->doPublish();
$liveRule = Versioned::get_one_by_stage("EditableCustomRule", "Live", "\"EditableCustomRule_Live\".\"ID\" = $ruleID");
$this->assertEmpty($liveRule);
}
function testUnpublishing() {
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$form->write();
$this->assertEquals(0, DB::query("SELECT COUNT(*) FROM \"EditableFormField_Live\"")->value());
$form->doPublish();
public function testUnpublishing()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$form->write();
$this->assertEquals(0, DB::query("SELECT COUNT(*) FROM \"EditableFormField_Live\"")->value());
$form->doPublish();
// assert that it exists and has a field
$live = Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID");
$this->assertTrue(isset($live));
$this->assertEquals(2, DB::query("SELECT COUNT(*) FROM \"EditableFormField_Live\"")->value());
// unpublish
$form->doUnpublish();
$this->assertNull(Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID"));
$this->assertEquals(0, DB::query("SELECT COUNT(*) FROM \"EditableFormField_Live\"")->value());
}
function testDoRevertToLive() {
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$field = $form->Fields()->First();
$field->Title = 'Title';
$field->write();
$form->doPublish();
$field->Title = 'Edited title';
$field->write();
// check that the published version is not updated
$live = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $field->ID");
$this->assertEquals('Title', $live->Title);
// revert back to the live data
$form->doRevertToLive();
$form->flushCache();
$check = Versioned::get_one_by_stage("EditableFormField", "Stage", "\"EditableFormField\".\"ID\" = $field->ID");
$this->assertEquals('Title', $check->Title);
}
function testDuplicatingForm() {
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$duplicate = $form->duplicate();
$this->assertEquals($form->Fields()->Count(), $duplicate->Fields()->Count());
$this->assertEquals($form->EmailRecipients()->Count(), $form->EmailRecipients()->Count());
// can't compare object since the dates/ids change
$this->assertEquals($form->Fields()->First()->Title, $duplicate->Fields()->First()->Title);
// Test duplicate with group
$form2 = $this->objFromFixture('UserDefinedForm', 'page-with-group');
$form2Validator = new UserFormValidator();
$form2Validator->setForm(new Form(new Controller(), 'Form', new FieldList(), new FieldList()));
$this->assertTrue($form2Validator->php($form2->toMap()));
// Check field groups exist
$form2GroupStart = $form2->Fields()->filter('ClassName', 'EditableFieldGroup')->first();
$form2GroupEnd = $form2->Fields()->filter('ClassName', 'EditableFieldGroupEnd')->first();
$this->assertEquals($form2GroupEnd->ID, $form2GroupStart->EndID);
// Duplicate this
$form3 = $form2->duplicate();
$form3Validator = new UserFormValidator();
$form3Validator->setForm(new Form(new Controller(), 'Form', new FieldList(), new FieldList()));
$this->assertTrue($form3Validator->php($form3->toMap()));
// Check field groups exist
$form3GroupStart = $form3->Fields()->filter('ClassName', 'EditableFieldGroup')->first();
$form3GroupEnd = $form3->Fields()->filter('ClassName', 'EditableFieldGroupEnd')->first();
$this->assertEquals($form3GroupEnd->ID, $form3GroupStart->EndID);
$this->assertNotEquals($form2GroupEnd->ID, $form3GroupStart->EndID);
}
function testFormOptions() {
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$fields = $form->getFormOptions();
$submit = $fields->fieldByName('SubmitButtonText');
$reset = $fields->fieldByName('ShowClearButton');
$this->assertEquals($submit->Title(), 'Text on submit button:');
$this->assertEquals($reset->Title(), 'Show Clear Form Button');
}
public function testEmailRecipientFilters() {
$form = $this->objFromFixture('UserDefinedForm', 'filtered-form-page');
// Check unfiltered recipients
$result0 = $form
->EmailRecipients()
->sort('EmailAddress')
->column('EmailAddress');
$this->assertEquals(
array(
'filtered1@example.com',
'filtered2@example.com',
'unfiltered@example.com'
),
$result0
);
// check filters based on given data
$result1 = $form->FilteredEmailRecipients(
array(
'your-name' => 'Value',
'address' => '',
'street' => 'Anything',
'city' => 'Matches Not Equals',
'colours' => array('Red') // matches 2
), null
)
->sort('EmailAddress')
->column('EmailAddress');
$this->assertEquals(
array(
'filtered2@example.com',
'unfiltered@example.com'
),
$result1
);
// Check all positive matches
$result2 = $form->FilteredEmailRecipients(
array(
'your-name' => '',
'address' => 'Anything',
'street' => 'Matches Equals',
'city' => 'Anything',
'colours' => array('Red', 'Blue') // matches 2
), null
)
->sort('EmailAddress')
->column('EmailAddress');
$this->assertEquals(
array(
'filtered1@example.com',
'filtered2@example.com',
'unfiltered@example.com'
),
$result2
);
$result3 = $form->FilteredEmailRecipients(
array(
'your-name' => 'Should be blank but is not',
'address' => 'Anything',
'street' => 'Matches Equals',
'city' => 'Anything',
'colours' => array('Blue')
), null
)->column('EmailAddress');
$this->assertEquals(
array(
'unfiltered@example.com'
),
$result3
);
$result4 = $form->FilteredEmailRecipients(
array(
'your-name' => '',
'address' => 'Anything',
'street' => 'Wrong value for this field',
'city' => '',
'colours' => array('Blue', 'Green')
), null
)->column('EmailAddress');
$this->assertEquals(
array(
'unfiltered@example.com'
),
$result4
);
}
public function testIndex() {
// Test that the $UserDefinedForm is stripped out
$page = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$page->publish('Stage', 'Live');
$result = $this->get($page->Link());
$body = Convert::nl2os($result->getBody(), ''); // strip out newlines
$this->assertFalse($result->isError());
$this->assertContains('<p>Here is my form</p><form', $body);
$this->assertContains('</form><p>Thank you for filling it out</p>', $body);
$this->assertNotContains('<p>$UserDefinedForm</p>', $body);
$this->assertNotContains('<p></p>', $body);
$this->assertNotContains('</p><p>Thank you for filling it out</p>', $body);
}
}
// assert that it exists and has a field
$live = Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID");
$this->assertTrue(isset($live));
$this->assertEquals(2, DB::query("SELECT COUNT(*) FROM \"EditableFormField_Live\"")->value());
// unpublish
$form->doUnpublish();
$this->assertNull(Versioned::get_one_by_stage("UserDefinedForm", "Live", "\"UserDefinedForm_Live\".\"ID\" = $form->ID"));
$this->assertEquals(0, DB::query("SELECT COUNT(*) FROM \"EditableFormField_Live\"")->value());
}
public function testDoRevertToLive()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$field = $form->Fields()->First();
$field->Title = 'Title';
$field->write();
$form->doPublish();
$field->Title = 'Edited title';
$field->write();
// check that the published version is not updated
$live = Versioned::get_one_by_stage("EditableFormField", "Live", "\"EditableFormField_Live\".\"ID\" = $field->ID");
$this->assertEquals('Title', $live->Title);
// revert back to the live data
$form->doRevertToLive();
$form->flushCache();
$check = Versioned::get_one_by_stage("EditableFormField", "Stage", "\"EditableFormField\".\"ID\" = $field->ID");
$this->assertEquals('Title', $check->Title);
}
public function testDuplicatingForm()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$duplicate = $form->duplicate();
$this->assertEquals($form->Fields()->Count(), $duplicate->Fields()->Count());
$this->assertEquals($form->EmailRecipients()->Count(), $form->EmailRecipients()->Count());
// can't compare object since the dates/ids change
$this->assertEquals($form->Fields()->First()->Title, $duplicate->Fields()->First()->Title);
// Test duplicate with group
$form2 = $this->objFromFixture('UserDefinedForm', 'page-with-group');
$form2Validator = new UserFormValidator();
$form2Validator->setForm(new Form(new Controller(), 'Form', new FieldList(), new FieldList()));
$this->assertTrue($form2Validator->php($form2->toMap()));
// Check field groups exist
$form2GroupStart = $form2->Fields()->filter('ClassName', 'EditableFieldGroup')->first();
$form2GroupEnd = $form2->Fields()->filter('ClassName', 'EditableFieldGroupEnd')->first();
$this->assertEquals($form2GroupEnd->ID, $form2GroupStart->EndID);
// Duplicate this
$form3 = $form2->duplicate();
$form3Validator = new UserFormValidator();
$form3Validator->setForm(new Form(new Controller(), 'Form', new FieldList(), new FieldList()));
$this->assertTrue($form3Validator->php($form3->toMap()));
// Check field groups exist
$form3GroupStart = $form3->Fields()->filter('ClassName', 'EditableFieldGroup')->first();
$form3GroupEnd = $form3->Fields()->filter('ClassName', 'EditableFieldGroupEnd')->first();
$this->assertEquals($form3GroupEnd->ID, $form3GroupStart->EndID);
$this->assertNotEquals($form2GroupEnd->ID, $form3GroupStart->EndID);
}
public function testFormOptions()
{
$this->logInWithPermission('ADMIN');
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$fields = $form->getFormOptions();
$submit = $fields->fieldByName('SubmitButtonText');
$reset = $fields->fieldByName('ShowClearButton');
$this->assertEquals($submit->Title(), 'Text on submit button:');
$this->assertEquals($reset->Title(), 'Show Clear Form Button');
}
public function testEmailRecipientFilters()
{
$form = $this->objFromFixture('UserDefinedForm', 'filtered-form-page');
// Check unfiltered recipients
$result0 = $form
->EmailRecipients()
->sort('EmailAddress')
->column('EmailAddress');
$this->assertEquals(
array(
'filtered1@example.com',
'filtered2@example.com',
'unfiltered@example.com'
),
$result0
);
// check filters based on given data
$result1 = $form->FilteredEmailRecipients(
array(
'your-name' => 'Value',
'address' => '',
'street' => 'Anything',
'city' => 'Matches Not Equals',
'colours' => array('Red') // matches 2
), null
)
->sort('EmailAddress')
->column('EmailAddress');
$this->assertEquals(
array(
'filtered2@example.com',
'unfiltered@example.com'
),
$result1
);
// Check all positive matches
$result2 = $form->FilteredEmailRecipients(
array(
'your-name' => '',
'address' => 'Anything',
'street' => 'Matches Equals',
'city' => 'Anything',
'colours' => array('Red', 'Blue') // matches 2
), null
)
->sort('EmailAddress')
->column('EmailAddress');
$this->assertEquals(
array(
'filtered1@example.com',
'filtered2@example.com',
'unfiltered@example.com'
),
$result2
);
$result3 = $form->FilteredEmailRecipients(
array(
'your-name' => 'Should be blank but is not',
'address' => 'Anything',
'street' => 'Matches Equals',
'city' => 'Anything',
'colours' => array('Blue')
), null
)->column('EmailAddress');
$this->assertEquals(
array(
'unfiltered@example.com'
),
$result3
);
$result4 = $form->FilteredEmailRecipients(
array(
'your-name' => '',
'address' => 'Anything',
'street' => 'Wrong value for this field',
'city' => '',
'colours' => array('Blue', 'Green')
), null
)->column('EmailAddress');
$this->assertEquals(
array(
'unfiltered@example.com'
),
$result4
);
}
public function testIndex()
{
// Test that the $UserDefinedForm is stripped out
$page = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
$page->publish('Stage', 'Live');
$result = $this->get($page->Link());
$body = Convert::nl2os($result->getBody(), ''); // strip out newlines
$this->assertFalse($result->isError());
$this->assertContains('<p>Here is my form</p><form', $body);
$this->assertContains('</form><p>Thank you for filling it out</p>', $body);
$this->assertNotContains('<p>$UserDefinedForm</p>', $body);
$this->assertNotContains('<p></p>', $body);
$this->assertNotContains('</p><p>Thank you for filling it out</p>', $body);
}
}

View File

@ -1,18 +1,20 @@
<?php
class UserFormTest extends SapphireTest {
class UserFormTest extends SapphireTest
{
protected static $fixture_file = 'UserDefinedFormTest.yml';
protected static $fixture_file = 'UserDefinedFormTest.yml';
/**
* Tests that a form will not generate empty pages
*/
public function testEmptyPages() {
$page = $this->objFromFixture('UserDefinedForm', 'empty-page');
$this->assertEquals(5, $page->Fields()->count());
$controller = ModelAsController::controller_for($page);
$form = new UserForm($controller);
$this->assertEquals(2, $form->getSteps()->count());
}
}
/**
* Tests that a form will not generate empty pages
*/
public function testEmptyPages()
{
$page = $this->objFromFixture('UserDefinedForm', 'empty-page');
$this->assertEquals(5, $page->Fields()->count());
$controller = ModelAsController::controller_for($page);
$form = new UserForm($controller);
$this->assertEquals(2, $form->getSteps()->count());
}
}

View File

@ -1,216 +1,220 @@
<?php
class UserFormsUpgradeServiceTest extends SapphireTest {
class UserFormsUpgradeServiceTest extends SapphireTest
{
static $fixture_file = 'UserFormsUpgradeServiceTest.yml';
public static $fixture_file = 'UserFormsUpgradeServiceTest.yml';
public function setUp() {
Config::inst()->update('UserDefinedForm', 'upgrade_on_build', false);
parent::setUp();
public function setUp()
{
Config::inst()->update('UserDefinedForm', 'upgrade_on_build', false);
parent::setUp();
// Assign rules programatically
$field1 = $this->objFromFixture('EditableTextField', 'text1');
$field2 = $this->objFromFixture('EditableTextField', 'text2');
$field3 = $this->objFromFixture('EditableTextField', 'text3');
// Assign rules programatically
$field1 = $this->objFromFixture('EditableTextField', 'text1');
$field2 = $this->objFromFixture('EditableTextField', 'text2');
$field3 = $this->objFromFixture('EditableTextField', 'text3');
$field3->CustomRules = serialize(array(
array(
'Display' => 'Show',
'ConditionField' => $field1->Name,
'ConditionOption' => 'IsBlank',
'Value' => ''
),
array(
'Display' => 'Hide',
'ConditionField' => $field2->Name,
'ConditionOption' => 'HasValue',
'Value' => 'bob'
)
));
$field3->write();
$field3->CustomRules = serialize(array(
array(
'Display' => 'Show',
'ConditionField' => $field1->Name,
'ConditionOption' => 'IsBlank',
'Value' => ''
),
array(
'Display' => 'Hide',
'ConditionField' => $field2->Name,
'ConditionOption' => 'HasValue',
'Value' => 'bob'
)
));
$field3->write();
// Assign settings programatically
$field4 = $this->objFromFixture('EditableTextField', 'text4');
$field4->CustomSettings = serialize(array(
'MinLength' => 20,
'MaxLength' => 100,
'Rows' => 4,
'ExtraClass' => 'special class',
'RightTitle' => 'My Field',
'ShowOnLoad' => '',
'Default' => 'Enter your text here'
));
$field4->write();
// Assign settings programatically
$field4 = $this->objFromFixture('EditableTextField', 'text4');
$field4->CustomSettings = serialize(array(
'MinLength' => 20,
'MaxLength' => 100,
'Rows' => 4,
'ExtraClass' => 'special class',
'RightTitle' => 'My Field',
'ShowOnLoad' => '',
'Default' => 'Enter your text here'
));
$field4->write();
$numeric1 = $this->objFromFixture('EditableNumericField', 'numeric1');
$numeric1->CustomSettings = serialize(array(
'RightTitle' => 'Number of %',
'Default' => 1,
'MinValue' => 1,
'MaxValue' => 100,
'ShowOnLoad' => 'Show'
));
$numeric1->write();
$numeric1 = $this->objFromFixture('EditableNumericField', 'numeric1');
$numeric1->CustomSettings = serialize(array(
'RightTitle' => 'Number of %',
'Default' => 1,
'MinValue' => 1,
'MaxValue' => 100,
'ShowOnLoad' => 'Show'
));
$numeric1->write();
$group1 = $this->objFromFixture('Group', 'group1');
$members1 = $this->objFromFixture('EditableMemberListField', 'members1');
$members1->CustomSettings = serialize(array(
'RightTitle' => 'Select group',
'GroupID' => $group1->ID,
'ShowOnLoad' => 'Hide'
));
$members1->write();
$group1 = $this->objFromFixture('Group', 'group1');
$members1 = $this->objFromFixture('EditableMemberListField', 'members1');
$members1->CustomSettings = serialize(array(
'RightTitle' => 'Select group',
'GroupID' => $group1->ID,
'ShowOnLoad' => 'Hide'
));
$members1->write();
$literal1 = $this->objFromFixture('EditableLiteralField', 'literal1');
$literal1->CustomSettings = serialize(array(
'HideFromReports' => 1,
'RightTitle' => 'Literal',
'Content' => '<p>Content</p>',
'ShowOnLoad' => true
));
$literal1->write();
$literal1 = $this->objFromFixture('EditableLiteralField', 'literal1');
$literal1->CustomSettings = serialize(array(
'HideFromReports' => 1,
'RightTitle' => 'Literal',
'Content' => '<p>Content</p>',
'ShowOnLoad' => true
));
$literal1->write();
$heading1 = $this->objFromFixture('EditableFormHeading', 'heading1');
$heading1->CustomSettings = serialize(array(
'RightTitle' => 'Right',
'Level' => 3,
'HideFromReports' => true,
'ShowOnLoad' => false
));
$heading1->write();
$heading1 = $this->objFromFixture('EditableFormHeading', 'heading1');
$heading1->CustomSettings = serialize(array(
'RightTitle' => 'Right',
'Level' => 3,
'HideFromReports' => true,
'ShowOnLoad' => false
));
$heading1->write();
$folder = $this->objFromFixture('Folder', 'folder1');
$file1 = $this->objFromFixture('EditableFileField', 'file1');
$file1->CustomSettings = serialize(array(
'RightTitle' => 'File field',
'Folder' => $folder->ID
));
$file1->write();
$folder = $this->objFromFixture('Folder', 'folder1');
$file1 = $this->objFromFixture('EditableFileField', 'file1');
$file1->CustomSettings = serialize(array(
'RightTitle' => 'File field',
'Folder' => $folder->ID
));
$file1->write();
$date1 = $this->objFromFixture('EditableDateField', 'date1');
$date1->CustomSettings = serialize(array(
'RightTitle' => 'Date field',
'DefaultToToday' => '1'
));
$date1->write();
$date1 = $this->objFromFixture('EditableDateField', 'date1');
$date1->CustomSettings = serialize(array(
'RightTitle' => 'Date field',
'DefaultToToday' => '1'
));
$date1->write();
$checkbox1 = $this->objFromFixture('EditableCheckbox', 'checkbox1');
$checkbox1->CustomSettings = serialize(array(
'Default' => true,
'RightTitle' => 'Check this'
));
$checkbox1->write();
$checkbox1 = $this->objFromFixture('EditableCheckbox', 'checkbox1');
$checkbox1->CustomSettings = serialize(array(
'Default' => true,
'RightTitle' => 'Check this'
));
$checkbox1->write();
}
}
/**
* @return UserFormsUpgradeService;
*/
protected function getService()
{
return singleton('UserFormsUpgradeService');
}
/**
* @return UserFormsUpgradeService;
*/
protected function getService() {
return singleton('UserFormsUpgradeService');
}
/**
* Tests migration of custom rules
*/
public function testCustomRulesMigration()
{
$service = $this->getService();
$service->setQuiet(true);
$service->run();
/**
* Tests migration of custom rules
*/
public function testCustomRulesMigration() {
$service = $this->getService();
$service->setQuiet(true);
$service->run();
$field1 = $this->objFromFixture('EditableTextField', 'text1');
$field2 = $this->objFromFixture('EditableTextField', 'text2');
$field3 = $this->objFromFixture('EditableTextField', 'text3');
$field1 = $this->objFromFixture('EditableTextField', 'text1');
$field2 = $this->objFromFixture('EditableTextField', 'text2');
$field3 = $this->objFromFixture('EditableTextField', 'text3');
$this->assertDOSEquals(array(
array(
'Display' => 'Show',
'ConditionFieldID' => $field1->ID,
'ConditionOption' => 'IsBlank'
),
array(
'Display' => 'Hide',
'ConditionFieldID' => $field2->ID,
'ConditionOption' => 'HasValue',
'FieldValue' => 'bob'
)
), $field3->DisplayRules());
}
$this->assertDOSEquals(array(
array(
'Display' => 'Show',
'ConditionFieldID' => $field1->ID,
'ConditionOption' => 'IsBlank'
),
array(
'Display' => 'Hide',
'ConditionFieldID' => $field2->ID,
'ConditionOption' => 'HasValue',
'FieldValue' => 'bob'
)
), $field3->DisplayRules());
}
/**
* Tests migration of all custom settings
*/
public function testCustomSettingsMigration()
{
$service = $this->getService();
$service->setQuiet(true);
$service->run();
/**
* Tests migration of all custom settings
*/
public function testCustomSettingsMigration() {
$service = $this->getService();
$service->setQuiet(true);
$service->run();
$group1 = $this->objFromFixture('Group', 'group1');
$form = $this->objFromFixture('UserDefinedForm', 'form-with-settings');
$folder = $this->objFromFixture('Folder', 'folder1');
$group1 = $this->objFromFixture('Group', 'group1');
$form = $this->objFromFixture('UserDefinedForm', 'form-with-settings');
$folder = $this->objFromFixture('Folder', 'folder1');
$this->assertDOSEquals(array(
array(
'ClassName' => 'EditableTextField',
'Title' => 'Text with rule',
'MinLength' => 20,
'MaxLength' => 100,
'Rows' => 4,
'ExtraClass' => 'special class',
'RightTitle' => 'My Field',
'ShowOnLoad' => true,
'Default' => 'Enter your text here',
),
array(
'ClassName' => 'EditableNumericField',
'Title' => 'Numeric 1',
'RightTitle' => 'Number of %',
'Default' => 1,
'MinValue' => 1,
'MaxValue' => 100,
'ShowOnLoad' => true,
),
array(
'ClassName' => 'EditableMemberListField',
'Title' => 'Members 1',
'RightTitle' => 'Select group',
'GroupID' => $group1->ID,
'ShowOnLoad' => false,
),
array(
'ClassName' => 'EditableLiteralField',
'Title' => 'Literal 1',
'HideFromReports' => true,
'RightTitle' => 'Literal',
'Content' => '<p>Content</p>',
'ShowOnLoad' => true,
),
array(
'ClassName' => 'EditableFormHeading',
'Title' => 'Heading 1',
'RightTitle' => 'Right',
'Level' => 3,
'HideFromReports' => true,
'ShowOnLoad' => false,
),
array(
'ClassName' => 'EditableFileField',
'Title' => 'File 1',
'RightTitle' => 'File field',
'FolderID' => $folder->ID,
),
array(
'ClassName' => 'EditableDateField',
'Title' => 'Date 1',
'RightTitle' => 'Date field',
'DefaultToToday' => true,
),
array(
'ClassName' => 'EditableCheckbox',
'Title' => 'Checkbox 1',
'CheckedDefault' => true,
'RightTitle' => 'Check this',
),
), $form->Fields());
}
$this->assertDOSEquals(array(
array(
'ClassName' => 'EditableTextField',
'Title' => 'Text with rule',
'MinLength' => 20,
'MaxLength' => 100,
'Rows' => 4,
'ExtraClass' => 'special class',
'RightTitle' => 'My Field',
'ShowOnLoad' => true,
'Default' => 'Enter your text here',
),
array(
'ClassName' => 'EditableNumericField',
'Title' => 'Numeric 1',
'RightTitle' => 'Number of %',
'Default' => 1,
'MinValue' => 1,
'MaxValue' => 100,
'ShowOnLoad' => true,
),
array(
'ClassName' => 'EditableMemberListField',
'Title' => 'Members 1',
'RightTitle' => 'Select group',
'GroupID' => $group1->ID,
'ShowOnLoad' => false,
),
array(
'ClassName' => 'EditableLiteralField',
'Title' => 'Literal 1',
'HideFromReports' => true,
'RightTitle' => 'Literal',
'Content' => '<p>Content</p>',
'ShowOnLoad' => true,
),
array(
'ClassName' => 'EditableFormHeading',
'Title' => 'Heading 1',
'RightTitle' => 'Right',
'Level' => 3,
'HideFromReports' => true,
'ShowOnLoad' => false,
),
array(
'ClassName' => 'EditableFileField',
'Title' => 'File 1',
'RightTitle' => 'File field',
'FolderID' => $folder->ID,
),
array(
'ClassName' => 'EditableDateField',
'Title' => 'Date 1',
'RightTitle' => 'Date field',
'DefaultToToday' => true,
),
array(
'ClassName' => 'EditableCheckbox',
'Title' => 'Checkbox 1',
'CheckedDefault' => true,
'RightTitle' => 'Check this',
),
), $form->Fields());
}
}