diff --git a/.upgrade.yml b/.upgrade.yml index 9ed29a4..7ae535e 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -13,7 +13,7 @@ mappings: UserFormsStepField: SilverStripe\UserForms\FormField\UserFormsStepField EditableCustomRule: SilverStripe\UserForms\Model\EditableCustomRule UserDefinedForm: SilverStripe\UserForms\Model\UserDefinedForm - UserDefinedFormController: SilverStripe\UserForms\Model\UserDefinedFormController + UserDefinedFormController: SilverStripe\UserForms\Control\UserDefinedFormController EditableCheckbox: SilverStripe\UserForms\Model\EditableFormField\EditableCheckbox EditableCheckboxGroupField: SilverStripe\UserForms\Model\EditableFormField\EditableCheckboxGroupField EditableCountryDropdownField: SilverStripe\UserForms\Model\EditableFormField\EditableCountryDropdownField @@ -47,7 +47,7 @@ mappings: UserFormTest: SilverStripe\UserForms\Tests\Form\UserFormTest UserFormsCheckboxSetFieldTest: SilverStripe\UserForms\Tests\FormField\UserFormsCheckboxSetFieldTest EditableCustomRuleTest: SilverStripe\UserForms\Tests\Model\EditableCustomRuleTest - UserDefinedFormControllerTest: SilverStripe\UserForms\Tests\Model\UserDefinedFormControllerTest + UserDefinedFormControllerTest: SilverStripe\UserForms\Tests\Control\UserDefinedFormControllerTest UserDefinedFormTest: SilverStripe\UserForms\Tests\Model\UserDefinedFormTest EditableDropdownTest: SilverStripe\UserForms\Tests\Model\EditableFormField\EditableDropdownTest EditableFileFieldTest: SilverStripe\UserForms\Tests\Model\EditableFormField\EditableFileFieldTest diff --git a/_config/routes.yml b/_config/routes.yml index 20e7ff7..531352d 100644 --- a/_config/routes.yml +++ b/_config/routes.yml @@ -4,4 +4,4 @@ After: framework/routes#coreroutes --- SilverStripe\Control\Director: rules: - UserDefinedFormController//$Action: SilverStripe\UserForms\Model\UserDefinedFormController + UserDefinedFormController//$Action: SilverStripe\UserForms\Control\UserDefinedFormController diff --git a/code/Model/UserDefinedFormController.php b/code/Control/UserDefinedFormController.php similarity index 99% rename from code/Model/UserDefinedFormController.php rename to code/Control/UserDefinedFormController.php index 44711d3..99b8273 100644 --- a/code/Model/UserDefinedFormController.php +++ b/code/Control/UserDefinedFormController.php @@ -1,6 +1,6 @@ setFields($fields = $this->getFormFields()); + $fields->setForm($this); $this->setActions($actions = $this->getFormActions()); $actions->setForm($this); @@ -120,6 +121,7 @@ class UserForm extends Form { $fields = new UserFormsFieldList(); $target = $fields; + foreach ($this->controller->Fields() as $field) { $target = $target->processNext($field); } diff --git a/code/Model/EditableFormField.php b/code/Model/EditableFormField.php index 747d67d..9679782 100755 --- a/code/Model/EditableFormField.php +++ b/code/Model/EditableFormField.php @@ -25,6 +25,7 @@ use SilverStripe\Forms\TabSet; use SilverStripe\Forms\TextField; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DB; use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\ValidationException; use SilverStripe\UserForms\Extension\UserFormFieldEditorExtension; @@ -36,6 +37,7 @@ use SilverStripe\UserForms\Model\EditableFormField\EditableFormStep; use SilverStripe\UserForms\Model\Submission\SubmittedFormField; use SilverStripe\UserForms\Modifier\DisambiguationSegmentFieldModifier; use SilverStripe\UserForms\Modifier\UnderscoreSegmentFieldModifier; +use SilverStripe\UserForms\UserForm; use SilverStripe\Versioned\Versioned; use Symbiote\GridFieldExtensions\GridFieldAddNewInlineButton; use Symbiote\GridFieldExtensions\GridFieldEditableColumns; @@ -146,7 +148,7 @@ class EditableFormField extends DataObject * @var array */ private static $has_one = [ - 'Parent' => UserDefinedForm::class, + 'Parent' => DataObject::class, ]; /** @@ -321,6 +323,17 @@ class EditableFormField extends DataObject return $fields; } + + public function requireDefaultRecords() + { + parent::requireDefaultRecords(); + + // make sure to migrate the class across (prior to v5.x) + DB::query("UPDATE EditableFormField SET ParentClass = 'Page' WHERE ParentClass IS NULL"); + DB::query("UPDATE EditableFormField_Live SET ParentClass = 'Page' WHERE ParentClass IS NULL"); + DB::query("UPDATE EditableFormField_Versions SET ParentClass = 'Page' WHERE ParentClass IS NULL"); + } + /** * Return fields to display on the 'Display Rules' tab * diff --git a/code/Model/Recipient/EmailRecipient.php b/code/Model/Recipient/EmailRecipient.php index 9e5b42b..84dbe80 100644 --- a/code/Model/Recipient/EmailRecipient.php +++ b/code/Model/Recipient/EmailRecipient.php @@ -26,6 +26,7 @@ use SilverStripe\Forms\TextareaField; use SilverStripe\Forms\TextField; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DB; use SilverStripe\ORM\FieldType\DBField; use SilverStripe\UserForms\Model\EditableFormField\EditableEmailField; use SilverStripe\UserForms\Model\EditableFormField; @@ -33,6 +34,7 @@ use SilverStripe\UserForms\Model\EditableFormField\EditableMultipleOptionField; use SilverStripe\UserForms\Model\EditableFormField\EditableTextField; use SilverStripe\UserForms\Model\Recipient\EmailRecipientCondition; use SilverStripe\UserForms\Model\UserDefinedForm; +use SilverStripe\UserForms\UserForm; use SilverStripe\View\Requirements; use Symbiote\GridFieldExtensions\GridFieldAddNewInlineButton; use Symbiote\GridFieldExtensions\GridFieldEditableColumns; @@ -59,7 +61,7 @@ class EmailRecipient extends DataObject ]; private static $has_one = [ - 'Form' => UserDefinedForm::class, + 'Form' => DataObject::class, 'SendEmailFromField' => EditableFormField::class, 'SendEmailToField' => EditableFormField::class, 'SendEmailSubjectField' => EditableFormField::class @@ -96,6 +98,14 @@ class EmailRecipient extends DataObject */ private static $allow_unbound_recipient_fields = false; + public function requireDefaultRecords() + { + parent::requireDefaultRecords(); + + // make sure to migrate the class across (prior to v5.x) + DB::query("UPDATE UserDefinedForm_EmailRecipient SET FormClass = 'Page' WHERE FormClass IS NULL"); + } + public function summaryFields() { $fields = parent::summaryFields(); @@ -436,7 +446,11 @@ class EmailRecipient extends DataObject */ public function canView($member = null) { - return $this->Form()->canView($member); + if ($form = $this->Form()) { + return $form->canView($member); + } + + return parent::canView($member); } /** @@ -446,7 +460,11 @@ class EmailRecipient extends DataObject */ public function canEdit($member = null) { - return $this->Form()->canEdit($member); + if ($form = $this->Form()) { + return $form->canEdit($member); + } + + return parent::canEdit($member); } /** @@ -459,7 +477,7 @@ class EmailRecipient extends DataObject return $this->canEdit($member); } - /* + /** * Determine if this recipient may receive notifications for this submission * * @param array $data diff --git a/code/Model/Submission/SubmittedForm.php b/code/Model/Submission/SubmittedForm.php index ba9d99b..922d94c 100755 --- a/code/Model/Submission/SubmittedForm.php +++ b/code/Model/Submission/SubmittedForm.php @@ -9,20 +9,16 @@ use SilverStripe\Forms\GridField\GridFieldExportButton; use SilverStripe\Forms\GridField\GridFieldPrintButton; use SilverStripe\Forms\ReadonlyField; use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DB; use SilverStripe\Security\Member; use SilverStripe\UserForms\Model\UserDefinedForm; use SilverStripe\UserForms\Model\Submission\SubmittedFormField; -/** - * Contents of an UserDefinedForm submission - * - * @package userforms - */ class SubmittedForm extends DataObject { private static $has_one = [ 'SubmittedBy' => Member::class, - 'Parent' => UserDefinedForm::class, + 'Parent' => DataObject::class, ]; private static $has_many = [ @@ -40,6 +36,14 @@ class SubmittedForm extends DataObject private static $table_name = 'SubmittedForm'; + public function requireDefaultRecords() + { + parent::requireDefaultRecords(); + + // make sure to migrate the class across (prior to v5.x) + DB::query("UPDATE SubmittedForm SET ParentClass = 'Page' WHERE ParentClass IS NULL"); + } + /** * Returns the value of a relation or, in the case of this form, the value * of a given child {@link SubmittedFormField} @@ -138,10 +142,16 @@ class SubmittedForm extends DataObject public function canView($member = null) { $extended = $this->extendedCan(__FUNCTION__, $member); + if ($extended !== null) { return $extended; } - return $this->Parent()->canView(); + + if ($this->Parent()) { + return $this->Parent()->canView($member); + } + + return parent::canView($member); } /** @@ -152,10 +162,16 @@ class SubmittedForm extends DataObject public function canEdit($member = null) { $extended = $this->extendedCan(__FUNCTION__, $member); + if ($extended !== null) { return $extended; } - return $this->Parent()->canEdit(); + + if ($this->Parent()) { + return $this->Parent()->canEdit($member); + } + + return parent::canEdit($member); } /** @@ -166,15 +182,21 @@ class SubmittedForm extends DataObject public function canDelete($member = null) { $extended = $this->extendedCan(__FUNCTION__, $member); + if ($extended !== null) { return $extended; } - return $this->Parent()->canDelete(); + + if ($this->Parent()) { + return $this->Parent()->canDelete($member); + } + + return parent::canDelete($member); } /** - * Before we delete this form make sure we delete all the - * field values so that we don't leave old data round + * Before we delete this form make sure we delete all the field values so + * that we don't leave old data round. * * @return void */ diff --git a/code/Model/UserDefinedForm.php b/code/Model/UserDefinedForm.php index c16aa59..6dc479c 100755 --- a/code/Model/UserDefinedForm.php +++ b/code/Model/UserDefinedForm.php @@ -3,46 +3,16 @@ namespace SilverStripe\UserForms\Model; use Page; -use Colymba\BulkManager\BulkManager; -use SilverStripe\Core\Injector\Injector; -use SilverStripe\Core\Manifest\ModuleLoader; -use SilverStripe\Forms\CheckboxField; -use SilverStripe\Forms\CompositeField; -use SilverStripe\Forms\FieldList; -use SilverStripe\Forms\GridField\GridField; -use SilverStripe\Forms\GridField\GridFieldAddNewButton; -use SilverStripe\Forms\GridField\GridFieldButtonRow; -use SilverStripe\Forms\GridField\GridFieldConfig; -use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; -use SilverStripe\Forms\GridField\GridFieldDataColumns; -use SilverStripe\Forms\GridField\GridFieldDeleteAction; -use SilverStripe\Forms\GridField\GridFieldDetailForm; -use SilverStripe\Forms\GridField\GridFieldEditButton; -use SilverStripe\Forms\GridField\GridFieldExportButton; -use SilverStripe\Forms\GridField\GridFieldPageCount; -use SilverStripe\Forms\GridField\GridFieldPaginator; -use SilverStripe\Forms\GridField\GridFieldPrintButton; -use SilverStripe\Forms\GridField\GridFieldSortableHeader; -use SilverStripe\Forms\GridField\GridFieldToolbarHeader; -use SilverStripe\Forms\HTMLEditor\HTMLEditorField; -use SilverStripe\Forms\LabelField; -use SilverStripe\Forms\LiteralField; -use SilverStripe\Forms\TextField; -use SilverStripe\ORM\ArrayList; -use SilverStripe\ORM\DB; -use SilverStripe\UserForms\Extension\UserFormFieldEditorExtension; -use SilverStripe\UserForms\Extension\UserFormValidator; -use SilverStripe\UserForms\Form\UserFormsGridFieldFilterHeader; -use SilverStripe\UserForms\Model\Recipient\EmailRecipient; -use SilverStripe\UserForms\Model\Recipient\UserFormRecipientItemRequest; -use SilverStripe\UserForms\Model\Submission\SubmittedForm; -use SilverStripe\View\Requirements; + +use SilverStripe\UserForms\UserForm; /** * @package userforms */ class UserDefinedForm extends Page { + use UserForm; + /** * @var string */ @@ -53,352 +23,8 @@ class UserDefinedForm extends Page */ private static $description = 'Adds a customizable form.'; - /** - * @var string Required Identifier - */ - private static $required_identifier = null; - /** * @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; - - /** - * Set this to true to disable automatic inclusion of CSS files - * @config - * @var bool - */ - private static $block_default_userforms_css = false; - - /** - * Set this to true to disable automatic inclusion of JavaScript files - * @config - * @var bool - */ - private static $block_default_userforms_js = false; - private static $table_name = 'UserDefinedForm'; - - /** - * Built in extensions required by this page - * @config - * @var array - */ - private static $extensions = [ - UserFormFieldEditorExtension::class - ]; - - /** - * @var array Fields on the user defined form page. - */ - private static $db = [ - 'SubmitButtonText' => 'Varchar', - 'ClearButtonText' => 'Varchar', - 'OnCompleteMessage' => 'HTMLText', - 'ShowClearButton' => 'Boolean', - 'DisableSaveSubmissions' => 'Boolean', - 'EnableLiveValidation' => 'Boolean', - 'DisplayErrorMessagesAtTop' => 'Boolean', - 'DisableAuthenicatedFinishAction' => 'Boolean', - 'DisableCsrfSecurityToken' => 'Boolean' - ]; - - /** - * @var array Default values of variables when this page is created - */ - private static $defaults = [ - 'Content' => '$UserDefinedForm', - 'DisableSaveSubmissions' => 0, - 'OnCompleteMessage' => '

Thanks, we\'ve received your submission.

' - ]; - - /** - * @var array - */ - private static $has_many = [ - 'Submissions' => SubmittedForm::class, - 'EmailRecipients' => EmailRecipient::class - ]; - - private static $cascade_deletes = [ - 'EmailRecipients', - ]; - - /** - * @var array - * @config - */ - private static $casting = [ - '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 - * @config - */ - private static $recipients_warning_enabled = false; - - private static $non_live_permissions = ['SITETREE_VIEW_ALL']; - - /** - * Temporary storage of field ids when the form is duplicated. - * Example layout: array('EditableCheckbox3' => 'EditableCheckbox14') - * @var array - */ - protected $fieldsFromTo = []; - - /** - * @return FieldList - */ - public function getCMSFields() - { - Requirements::css( - ModuleLoader::getModule('silverstripe/userforms') - ->getRelativeResourcePath('client/dist/styles/userforms-cms.css') - ); - - $this->beforeUpdateCMSFields(function ($fields) { - // define tabs - $fields->findOrMakeTab('Root.FormOptions', _t(__CLASS__.'.CONFIGURATION', 'Configuration')); - $fields->findOrMakeTab('Root.Recipients', _t(__CLASS__.'.RECIPIENTS', 'Recipients')); - $fields->findOrMakeTab('Root.Submissions', _t(__CLASS__.'.SUBMISSIONS', 'Submissions')); - - // text to show on complete - $onCompleteFieldSet = CompositeField::create( - $label = LabelField::create( - 'OnCompleteMessageLabel', - _t(__CLASS__.'.ONCOMPLETELABEL', 'Show on completion') - ), - $editor = HTMLEditorField::create( - 'OnCompleteMessage', - '', - _t(__CLASS__.'.ONCOMPLETEMESSAGE', $this->OnCompleteMessage) - ) - ); - - $onCompleteFieldSet->addExtraClass('field'); - - $editor->setRows(3); - $label->addExtraClass('left'); - - // Define config for email recipients - $emailRecipientsConfig = GridFieldConfig_RecordEditor::create(10); - $emailRecipientsConfig->getComponentByType(GridFieldAddNewButton::class) - ->setButtonName( - _t(__CLASS__.'.ADDEMAILRECIPIENT', 'Add Email Recipient') - ); - - // who do we email on submission - $emailRecipients = GridField::create( - 'EmailRecipients', - _t(__CLASS__.'.EMAILRECIPIENTS', 'Email Recipients'), - $this->EmailRecipients(), - $emailRecipientsConfig - ); - $emailRecipients - ->getConfig() - ->getComponentByType(GridFieldDetailForm::class) - ->setItemRequestClass(UserFormRecipientItemRequest::class); - - $fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet); - $fields->addFieldToTab('Root.Recipients', $emailRecipients); - $fields->addFieldsToTab('Root.FormOptions', $this->getFormOptions()); - - - // view the submissions - // make sure a numeric not a empty string is checked against this int column for SQL server - $parentID = (!empty($this->ID)) ? (int) $this->ID : 0; - - // get a list of all field names and values used for print and export CSV views of the GridField below. - $columnSQL = <<map() as $name => $title) { - $columns[$name] = trim(strtr($title, '.', ' ')); - } - - $config = GridFieldConfig::create(); - $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')); - - // show user form items in the summary tab - $summaryarray = array( - 'ID' => 'ID', - 'Created' => 'Created', - 'LastEdited' => 'Last Edited' - ); - foreach (EditableFormField::get()->filter(array('ParentID' => $parentID)) as $eff) { - if ($eff->ShowInSummary) { - $summaryarray[$eff->Name] = $eff->Title ?: $eff->Name; - } - } - - $config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($summaryarray); - - /** - * Support for {@link https://github.com/colymba/GridFieldBulkEditingTools} - */ - if (class_exists(BulkManager::class)) { - $config->addComponent(new BulkManager); - } - - $sort->setThrowExceptionOnBadDataType(false); - $filter->setThrowExceptionOnBadDataType(false); - $pagination->setThrowExceptionOnBadDataType(false); - - // attach every column to the print view form - $columns['Created'] = 'Created'; - $columns['SubmittedBy.Email'] = 'Submitter'; - $filter->setColumns($columns); - - // print configuration - - $print->setPrintHasHeader(true); - $print->setPrintColumns($columns); - - // export configuration - $export->setCsvHasHeader(true); - $export->setExportColumns($columns); - - $submissions = GridField::create( - 'Submissions', - _t(__CLASS__.'.SUBMISSIONS', 'Submissions'), - $this->Submissions()->sort('Created', 'DESC'), - $config - ); - $fields->addFieldToTab('Root.Submissions', $submissions); - $fields->addFieldToTab( - 'Root.FormOptions', - CheckboxField::create( - 'DisableSaveSubmissions', - _t(__CLASS__.'.SAVESUBMISSIONS', 'Disable Saving Submissions to Server') - ) - ); - }); - - $fields = parent::getCMSFields(); - - if ($this->EmailRecipients()->Count() == 0 && static::config()->recipients_warning_enabled) { - $fields->addFieldToTab('Root.Main', LiteralField::create( - 'EmailRecipientsWarning', - '

' . _t( - __CLASS__.'.NORECIPIENTS', - 'Warning: You have not configured any recipients. Form submissions may be missed.' - ) - . '

' - ), 'Title'); - } - - 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 = ArrayList::create($this->EmailRecipients()->toArray()); - - // Filter by rules - $recipients = $recipients->filterByCallback(function ($recipient) use ($data, $form) { - /** @var EmailRecipient $recipient */ - return $recipient->canSend($data, $form); - }); - - $this->extend('updateFilteredEmailRecipients', $recipients, $data, $form); - - 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(__CLASS__.'.SUBMITBUTTON', 'Submit'); - $clear = ($this->ClearButtonText) ? $this->ClearButtonText : _t(__CLASS__.'.CLEARBUTTON', 'Clear'); - - $options = FieldList::create( - TextField::create('SubmitButtonText', _t(__CLASS__.'.TEXTONSUBMIT', 'Text on submit button:'), $submit), - TextField::create('ClearButtonText', _t(__CLASS__.'.TEXTONCLEAR', 'Text on clear button:'), $clear), - CheckboxField::create('ShowClearButton', _t(__CLASS__.'.SHOWCLEARFORM', 'Show Clear Form Button'), $this->ShowClearButton), - CheckboxField::create('EnableLiveValidation', _t(__CLASS__.'.ENABLELIVEVALIDATION', 'Enable live validation')), - CheckboxField::create('DisplayErrorMessagesAtTop', _t(__CLASS__.'.DISPLAYERRORMESSAGESATTOP', 'Display error messages above the form?')), - CheckboxField::create('DisableCsrfSecurityToken', _t(__CLASS__.'.DISABLECSRFSECURITYTOKEN', 'Disable CSRF Token')), - CheckboxField::create('DisableAuthenicatedFinishAction', _t(__CLASS__.'.DISABLEAUTHENICATEDFINISHACTION', 'Disable Authentication on finish action')) - ); - - $this->extend('updateFormOptions', $options); - - return $options; - } - - /** - * Get the HTML id of the error container displayed above the form. - * - * @return string - */ - public function getErrorContainerID() - { - return $this->config()->get('error_container_id'); - } - - - /** - * Validate formfields - */ - public function getCMSValidator() - { - return UserFormValidator::create(); - } } diff --git a/code/UserForm.php b/code/UserForm.php new file mode 100644 index 0000000..0145b5c --- /dev/null +++ b/code/UserForm.php @@ -0,0 +1,403 @@ + 'Varchar', + 'ClearButtonText' => 'Varchar', + 'OnCompleteMessage' => 'HTMLText', + 'ShowClearButton' => 'Boolean', + 'DisableSaveSubmissions' => 'Boolean', + 'EnableLiveValidation' => 'Boolean', + 'DisplayErrorMessagesAtTop' => 'Boolean', + 'DisableAuthenicatedFinishAction' => 'Boolean', + 'DisableCsrfSecurityToken' => 'Boolean' + ]; + + /** + * @var array Default values of variables when this page is created + */ + private static $defaults = [ + 'Content' => '$UserDefinedForm', + 'DisableSaveSubmissions' => 0, + 'OnCompleteMessage' => '

Thanks, we\'ve received your submission.

' + ]; + + /** + * @var array + */ + private static $has_many = [ + 'Submissions' => SubmittedForm::class, + 'EmailRecipients' => EmailRecipient::class + ]; + + private static $cascade_deletes = [ + 'EmailRecipients', + ]; + + /** + * @var array + * @config + */ + private static $casting = [ + '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 + * @config + */ + private static $recipients_warning_enabled = false; + + private static $non_live_permissions = ['SITETREE_VIEW_ALL']; + + /** + * Temporary storage of field ids when the form is duplicated. + * Example layout: array('EditableCheckbox3' => 'EditableCheckbox14') + * @var array + */ + protected $fieldsFromTo = []; + + /** + * @return FieldList + */ + public function getCMSFields() + { + Requirements::css( + ModuleLoader::getModule('silverstripe/userforms') + ->getRelativeResourcePath('client/dist/styles/userforms-cms.css') + ); + + $this->beforeUpdateCMSFields(function ($fields) { + + // remove + $fields->removeByName('OnCompleteMessageLabel'); + $fields->removeByName('OnCompleteMessage'); + $fields->removeByName('Fields'); + $fields->removeByName('EmailRecipients'); + + // define tabs + $fields->findOrMakeTab('Root.FormOptions', _t(__CLASS__.'.CONFIGURATION', 'Configuration')); + $fields->findOrMakeTab('Root.Recipients', _t(__CLASS__.'.RECIPIENTS', 'Recipients')); + $fields->findOrMakeTab('Root.Submissions', _t(__CLASS__.'.SUBMISSIONS', 'Submissions')); + + + // text to show on complete + $onCompleteFieldSet = CompositeField::create( + $label = LabelField::create( + 'OnCompleteMessageLabel', + _t(__CLASS__.'.ONCOMPLETELABEL', 'Show on completion') + ), + $editor = HTMLEditorField::create( + 'OnCompleteMessage', + '', + _t(__CLASS__.'.ONCOMPLETEMESSAGE', $this->OnCompleteMessage) + ) + ); + + $onCompleteFieldSet->addExtraClass('field'); + + $editor->setRows(3); + $label->addExtraClass('left'); + + // Define config for email recipients + $emailRecipientsConfig = GridFieldConfig_RecordEditor::create(10); + $emailRecipientsConfig->getComponentByType(GridFieldAddNewButton::class) + ->setButtonName( + _t(__CLASS__.'.ADDEMAILRECIPIENT', 'Add Email Recipient') + ); + + // who do we email on submission + $emailRecipients = GridField::create( + 'EmailRecipients', + '', + $this->EmailRecipients(), + $emailRecipientsConfig + ); + $emailRecipients + ->getConfig() + ->getComponentByType(GridFieldDetailForm::class) + ->setItemRequestClass(UserFormRecipientItemRequest::class); + + $fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet); + $fields->addFieldToTab('Root.Recipients', $emailRecipients); + $fields->addFieldsToTab('Root.FormOptions', $this->getFormOptions()); + + + // view the submissions + // make sure a numeric not a empty string is checked against this int column for SQL server + $parentID = (!empty($this->ID)) ? (int) $this->ID : 0; + + // get a list of all field names and values used for print and export CSV views of the GridField below. + $columnSQL = <<map() as $name => $title) { + $columns[$name] = trim(strtr($title, '.', ' ')); + } + + $config = GridFieldConfig::create(); + $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')); + + // show user form items in the summary tab + $summaryarray = array( + 'ID' => 'ID', + 'Created' => 'Created', + 'LastEdited' => 'Last Edited' + ); + + foreach (EditableFormField::get()->filter(array('ParentID' => $parentID)) as $eff) { + if ($eff->ShowInSummary) { + $summaryarray[$eff->Name] = $eff->Title ?: $eff->Name; + } + } + + $config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($summaryarray); + + /** + * Support for {@link https://github.com/colymba/GridFieldBulkEditingTools} + */ + if (class_exists(BulkManager::class)) { + $config->addComponent(new BulkManager); + } + + $sort->setThrowExceptionOnBadDataType(false); + $filter->setThrowExceptionOnBadDataType(false); + $pagination->setThrowExceptionOnBadDataType(false); + + // attach every column to the print view form + $columns['Created'] = 'Created'; + $columns['SubmittedBy.Email'] = 'Submitter'; + $filter->setColumns($columns); + + // print configuration + + $print->setPrintHasHeader(true); + $print->setPrintColumns($columns); + + // export configuration + $export->setCsvHasHeader(true); + $export->setExportColumns($columns); + + $submissions = GridField::create( + 'Submissions', + '', + $this->Submissions()->sort('Created', 'DESC'), + $config + ); + $fields->addFieldToTab('Root.Submissions', $submissions); + $fields->addFieldToTab( + 'Root.FormOptions', + CheckboxField::create( + 'DisableSaveSubmissions', + _t(__CLASS__.'.SAVESUBMISSIONS', 'Disable Saving Submissions to Server') + ) + ); + }); + + $fields = parent::getCMSFields(); + + if ($this->EmailRecipients()->Count() == 0 && static::config()->recipients_warning_enabled) { + $fields->addFieldToTab('Root.Main', LiteralField::create( + 'EmailRecipientsWarning', + '

' . _t( + __CLASS__.'.NORECIPIENTS', + 'Warning: You have not configured any recipients. Form submissions may be missed.' + ) + . '

' + ), 'Title'); + } + + 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 = ArrayList::create($this->EmailRecipients()->toArray()); + + // Filter by rules + $recipients = $recipients->filterByCallback(function ($recipient) use ($data, $form) { + /** @var EmailRecipient $recipient */ + return $recipient->canSend($data, $form); + }); + + $this->extend('updateFilteredEmailRecipients', $recipients, $data, $form); + + 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(__CLASS__.'.SUBMITBUTTON', 'Submit'); + $clear = ($this->ClearButtonText) ? $this->ClearButtonText : _t(__CLASS__.'.CLEARBUTTON', 'Clear'); + + $options = FieldList::create( + TextField::create('SubmitButtonText', _t(__CLASS__.'.TEXTONSUBMIT', 'Text on submit button:'), $submit), + TextField::create('ClearButtonText', _t(__CLASS__.'.TEXTONCLEAR', 'Text on clear button:'), $clear), + CheckboxField::create('ShowClearButton', _t(__CLASS__.'.SHOWCLEARFORM', 'Show Clear Form Button'), $this->ShowClearButton), + CheckboxField::create('EnableLiveValidation', _t(__CLASS__.'.ENABLELIVEVALIDATION', 'Enable live validation')), + CheckboxField::create('DisplayErrorMessagesAtTop', _t(__CLASS__.'.DISPLAYERRORMESSAGESATTOP', 'Display error messages above the form?')), + CheckboxField::create('DisableCsrfSecurityToken', _t(__CLASS__.'.DISABLECSRFSECURITYTOKEN', 'Disable CSRF Token')), + CheckboxField::create('DisableAuthenicatedFinishAction', _t(__CLASS__.'.DISABLEAUTHENICATEDFINISHACTION', 'Disable Authentication on finish action')) + ); + + $this->extend('updateFormOptions', $options); + + return $options; + } + + /** + * Get the HTML id of the error container displayed above the form. + * + * @return string + */ + public function getErrorContainerID() + { + return $this->config()->get('error_container_id'); + } + + /** + * Validate formfields + */ + public function getCMSValidator() + { + return UserFormValidator::create(); + } +} diff --git a/tests/Model/UserDefinedFormControllerTest.php b/tests/Control/UserDefinedFormControllerTest.php similarity index 98% rename from tests/Model/UserDefinedFormControllerTest.php rename to tests/Control/UserDefinedFormControllerTest.php index d2cbbe9..630913f 100644 --- a/tests/Model/UserDefinedFormControllerTest.php +++ b/tests/Control/UserDefinedFormControllerTest.php @@ -1,6 +1,6 @@ [UserFormFieldEditorExtension::class], diff --git a/tests/Model/UserDefinedFormTest.yml b/tests/UserFormsTest.yml similarity index 100% rename from tests/Model/UserDefinedFormTest.yml rename to tests/UserFormsTest.yml diff --git a/tests/templates/SilverStripe/UserForms/Tests/Model/UserDefinedFormControllerTest.ss b/tests/templates/SilverStripe/UserForms/Tests/Control/UserDefinedFormControllerTest.ss similarity index 100% rename from tests/templates/SilverStripe/UserForms/Tests/Model/UserDefinedFormControllerTest.ss rename to tests/templates/SilverStripe/UserForms/Tests/Control/UserDefinedFormControllerTest.ss