UserForm   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 358
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 156
c 4
b 0
f 0
dl 0
loc 358
rs 10
wmc 15

5 Methods

Rating   Name   Duplication   Size   Complexity  
A FilteredEmailRecipients() 0 13 1
A getErrorContainerID() 0 3 1
C getCMSFields() 0 164 9
A getFormOptions() 0 18 3
A getCMSValidator() 0 3 1
1
<?php
2
3
namespace SilverStripe\UserForms;
4
5
use Colymba\BulkManager\BulkManager;
0 ignored issues
show
Bug introduced by
The type Colymba\BulkManager\BulkManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use SilverStripe\Core\Injector\Injector;
7
use SilverStripe\Forms\CheckboxField;
8
use SilverStripe\Forms\CompositeField;
9
use SilverStripe\Forms\FieldList;
10
use SilverStripe\Forms\GridField\GridField;
11
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
12
use SilverStripe\Forms\GridField\GridFieldButtonRow;
13
use SilverStripe\Forms\GridField\GridFieldConfig;
14
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
15
use SilverStripe\Forms\GridField\GridFieldDataColumns;
16
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
17
use SilverStripe\Forms\GridField\GridFieldDetailForm;
18
use SilverStripe\Forms\GridField\GridFieldEditButton;
19
use SilverStripe\Forms\GridField\GridFieldExportButton;
20
use SilverStripe\Forms\GridField\GridFieldPageCount;
21
use SilverStripe\Forms\GridField\GridFieldPaginator;
22
use SilverStripe\Forms\GridField\GridFieldPrintButton;
23
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
24
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
25
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
26
use SilverStripe\Forms\LabelField;
27
use SilverStripe\Forms\LiteralField;
28
use SilverStripe\Forms\TextField;
29
use SilverStripe\ORM\ArrayList;
30
use SilverStripe\ORM\DB;
31
use SilverStripe\UserForms\Extension\UserFormFieldEditorExtension;
32
use SilverStripe\UserForms\Extension\UserFormValidator;
33
use SilverStripe\UserForms\Form\UserFormsGridFieldFilterHeader;
34
use SilverStripe\UserForms\Model\Recipient\EmailRecipient;
35
use SilverStripe\UserForms\Model\Recipient\UserFormRecipientItemRequest;
36
use SilverStripe\UserForms\Model\Submission\SubmittedForm;
37
use SilverStripe\UserForms\Model\EditableFormField;
38
use SilverStripe\View\Requirements;
39
use SilverStripe\Core\Config\Configurable;
40
41
/**
42
 * Defines the user defined functionality to be applied to any {@link DataObject}
43
 *
44
 * @mixin UserFormFieldEditorExtension
45
 */
46
trait UserForm
47
{
48
    use Configurable;
49
50
    /**
51
     * Built in extensions required by this page.
52
     *
53
     * @config
54
     * @var array
55
     */
56
    private static $extensions = [
57
        UserFormFieldEditorExtension::class
58
    ];
59
60
    /**
61
     * @var string Required Identifier
62
     */
63
    private static $required_identifier = null;
64
65
    /**
66
     * @var string
67
     */
68
    private static $email_template_directory = 'silverstripe/userforms:templates/email/';
69
70
    /**
71
     * Should this module automatically upgrade on dev/build?
72
     *
73
     * @config
74
     * @var bool
75
     */
76
    private static $upgrade_on_build = true;
77
78
    /**
79
     * Set this to true to disable automatic inclusion of CSS files
80
     * @config
81
     * @var bool
82
     */
83
    private static $block_default_userforms_css = false;
84
85
    /**
86
     * Set this to true to disable automatic inclusion of JavaScript files
87
     * @config
88
     * @var bool
89
     */
90
    private static $block_default_userforms_js = false;
91
92
    /**
93
     * @var array Fields on the user defined form page.
94
     */
95
    private static $db = [
96
        'SubmitButtonText' => 'Varchar',
97
        'ClearButtonText' => 'Varchar',
98
        'OnCompleteMessage' => 'HTMLText',
99
        'ShowClearButton' => 'Boolean',
100
        'DisableSaveSubmissions' => 'Boolean',
101
        'EnableLiveValidation' => 'Boolean',
102
        'DisplayErrorMessagesAtTop' => 'Boolean',
103
        'DisableAuthenicatedFinishAction' => 'Boolean',
104
        'DisableCsrfSecurityToken' => 'Boolean'
105
    ];
106
107
    /**
108
     * @var array Default values of variables when this page is created
109
     */
110
    private static $defaults = [
111
        'Content' => '$UserDefinedForm',
112
        'DisableSaveSubmissions' => 0,
113
        'OnCompleteMessage' => '<p>Thanks, we\'ve received your submission.</p>'
114
    ];
115
116
    /**
117
     * @var array
118
     */
119
    private static $has_many = [
120
        'Submissions' => SubmittedForm::class,
121
        'EmailRecipients' => EmailRecipient::class
122
    ];
123
124
    private static $cascade_deletes = [
125
        'EmailRecipients',
126
    ];
127
128
    private static $cascade_duplicates = false;
129
130
    /**
131
     * @var array
132
     * @config
133
     */
134
    private static $casting = [
135
        'ErrorContainerID' => 'Text'
136
    ];
137
138
    /**
139
     * Error container selector which matches the element for grouped messages
140
     *
141
     * @var string
142
     * @config
143
     */
144
    private static $error_container_id = 'error-container';
145
146
    /**
147
     * The configuration used to determine whether a confirmation message is to
148
     * appear when navigating away from a partially completed form.
149
     *
150
     * @var boolean
151
     * @config
152
     */
153
    private static $enable_are_you_sure = true;
154
155
    /**
156
     * @var bool
157
     * @config
158
     */
159
    private static $recipients_warning_enabled = false;
160
161
    private static $non_live_permissions = ['SITETREE_VIEW_ALL'];
162
163
    /**
164
     * Temporary storage of field ids when the form is duplicated.
165
     * Example layout: array('EditableCheckbox3' => 'EditableCheckbox14')
166
     * @var array
167
     */
168
    protected $fieldsFromTo = [];
169
170
    /**
171
     * @return FieldList
172
     */
173
    public function getCMSFields()
174
    {
175
        Requirements::css('silverstripe/userforms:client/dist/styles/userforms-cms.css');
176
177
        $this->beforeUpdateCMSFields(function ($fields) {
0 ignored issues
show
Bug introduced by
It seems like beforeUpdateCMSFields() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

177
        $this->/** @scrutinizer ignore-call */ 
178
               beforeUpdateCMSFields(function ($fields) {
Loading history...
178
179
            // remove
180
            $fields->removeByName('OnCompleteMessageLabel');
181
            $fields->removeByName('OnCompleteMessage');
182
            $fields->removeByName('Fields');
183
            $fields->removeByName('EmailRecipients');
184
185
            // define tabs
186
            $fields->findOrMakeTab('Root.FormOptions', _t(__CLASS__.'.CONFIGURATION', 'Configuration'));
187
            $fields->findOrMakeTab('Root.Recipients', _t(__CLASS__.'.RECIPIENTS', 'Recipients'));
188
            $fields->findOrMakeTab('Root.Submissions', _t(__CLASS__.'.SUBMISSIONS', 'Submissions'));
189
190
191
            // text to show on complete
192
            $onCompleteFieldSet = CompositeField::create(
193
                $label = LabelField::create(
194
                    'OnCompleteMessageLabel',
195
                    _t(__CLASS__.'.ONCOMPLETELABEL', 'Show on completion')
196
                ),
197
                $editor = HTMLEditorField::create(
198
                    'OnCompleteMessage',
199
                    '',
200
                    $this->OnCompleteMessage
201
                )
202
            );
203
204
            $onCompleteFieldSet->addExtraClass('field');
205
206
            $editor->setRows(3);
207
            $label->addExtraClass('left');
208
209
            // Define config for email recipients
210
            $emailRecipientsConfig = GridFieldConfig_RecordEditor::create(10);
211
            $emailRecipientsConfig->getComponentByType(GridFieldAddNewButton::class)
212
                ->setButtonName(
213
                    _t(__CLASS__.'.ADDEMAILRECIPIENT', 'Add Email Recipient')
214
                );
215
216
            // who do we email on submission
217
            $emailRecipients = GridField::create(
218
                'EmailRecipients',
219
                '',
220
                $this->EmailRecipients(),
0 ignored issues
show
Bug introduced by
The method EmailRecipients() does not exist on SilverStripe\UserForms\UserForm. Did you maybe mean FilteredEmailRecipients()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

220
                $this->/** @scrutinizer ignore-call */ 
221
                       EmailRecipients(),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
221
                $emailRecipientsConfig
222
            );
223
            $emailRecipients
224
                ->getConfig()
225
                ->getComponentByType(GridFieldDetailForm::class)
226
                ->setItemRequestClass(UserFormRecipientItemRequest::class);
227
228
            $fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet);
229
            $fields->addFieldToTab('Root.Recipients', $emailRecipients);
230
            $fields->addFieldsToTab('Root.FormOptions', $this->getFormOptions());
231
232
233
            // view the submissions
234
            // make sure a numeric not a empty string is checked against this int column for SQL server
235
            $parentID = (!empty($this->ID)) ? (int) $this->ID : 0;
236
237
            // get a list of all field names and values used for print and export CSV views of the GridField below.
238
            $columnSQL = <<<SQL
239
SELECT "SubmittedFormField"."Name" as "Name", COALESCE("EditableFormField"."Title", "SubmittedFormField"."Title") as "Title", COALESCE("EditableFormField"."Sort", 999) AS "Sort"
240
FROM "SubmittedFormField"
241
LEFT JOIN "SubmittedForm" ON "SubmittedForm"."ID" = "SubmittedFormField"."ParentID"
242
LEFT JOIN "EditableFormField" ON "EditableFormField"."Name" = "SubmittedFormField"."Name" AND "EditableFormField"."ParentID" = '$parentID'
243
WHERE "SubmittedForm"."ParentID" = '$parentID'
244
ORDER BY "Sort", "Title"
245
SQL;
246
            // Sanitise periods in title
247
            $columns = array();
248
249
            foreach (DB::query($columnSQL)->map() as $name => $title) {
250
                $columns[$name] = trim(strtr($title, '.', ' '));
251
            }
252
253
            $config = GridFieldConfig::create();
254
            $config->addComponent(new GridFieldToolbarHeader());
255
            $config->addComponent($sort = new GridFieldSortableHeader());
256
            $config->addComponent($filter = new UserFormsGridFieldFilterHeader());
257
            $config->addComponent(new GridFieldDataColumns());
258
            $config->addComponent(new GridFieldEditButton());
259
            $config->addComponent(new GridFieldDeleteAction());
260
            $config->addComponent(new GridFieldPageCount('toolbar-header-right'));
261
            $config->addComponent($pagination = new GridFieldPaginator(25));
262
            $config->addComponent(new GridFieldDetailForm(null, true, false));
263
            $config->addComponent(new GridFieldButtonRow('after'));
264
            $config->addComponent($export = new GridFieldExportButton('buttons-after-left'));
265
            $config->addComponent($print = new GridFieldPrintButton('buttons-after-left'));
266
267
            // show user form items in the summary tab
268
            $summaryarray = array(
269
                'ID' => 'ID',
270
                'Created' => 'Created',
271
                'LastEdited' => 'Last Edited'
272
            );
273
274
            foreach (EditableFormField::get()->filter(array('ParentID' => $parentID)) as $eff) {
275
                if ($eff->ShowInSummary) {
276
                    $summaryarray[$eff->Name] = $eff->Title ?: $eff->Name;
277
                }
278
            }
279
280
            $config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($summaryarray);
281
282
            /**
283
             * Support for {@link https://github.com/colymba/GridFieldBulkEditingTools}
284
             */
285
            if (class_exists(BulkManager::class)) {
286
                $config->addComponent(new BulkManager);
287
            }
288
289
            $sort->setThrowExceptionOnBadDataType(false);
290
            $filter->setThrowExceptionOnBadDataType(false);
291
            $pagination->setThrowExceptionOnBadDataType(false);
292
293
            // attach every column to the print view form
294
            $columns['Created'] = 'Created';
295
            $columns['SubmittedBy.Email'] = 'Submitter';
296
            $filter->setColumns($columns);
297
298
            // print configuration
299
300
            $print->setPrintHasHeader(true);
301
            $print->setPrintColumns($columns);
302
303
            // export configuration
304
            $export->setCsvHasHeader(true);
305
            $export->setExportColumns($columns);
306
307
            $submissions = GridField::create(
308
                'Submissions',
309
                '',
310
                $this->Submissions()->sort('Created', 'DESC'),
0 ignored issues
show
Bug introduced by
It seems like Submissions() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

310
                $this->/** @scrutinizer ignore-call */ 
311
                       Submissions()->sort('Created', 'DESC'),
Loading history...
311
                $config
312
            );
313
            $fields->addFieldToTab('Root.Submissions', $submissions);
314
            $fields->addFieldToTab(
315
                'Root.FormOptions',
316
                CheckboxField::create(
317
                    'DisableSaveSubmissions',
318
                    _t(__CLASS__.'.SAVESUBMISSIONS', 'Disable Saving Submissions to Server')
319
                )
320
            );
321
        });
322
323
        $fields = parent::getCMSFields();
324
325
        if ($this->EmailRecipients()->Count() == 0 && static::config()->recipients_warning_enabled) {
326
            $fields->addFieldToTab('Root.Main', LiteralField::create(
327
                'EmailRecipientsWarning',
328
                '<p class="message warning">' . _t(
329
                    __CLASS__.'.NORECIPIENTS',
330
                    'Warning: You have not configured any recipients. Form submissions may be missed.'
331
                )
332
                . '</p>'
333
            ), 'Title');
334
        }
335
336
        return $fields;
337
    }
338
339
    /**
340
     * Allow overriding the EmailRecipients on a {@link DataExtension}
341
     * so you can customise who receives an email.
342
     * Converts the RelationList to an ArrayList so that manipulation
343
     * of the original source data isn't possible.
344
     *
345
     * @return ArrayList
346
     */
347
    public function FilteredEmailRecipients($data = null, $form = null)
348
    {
349
        $recipients = ArrayList::create($this->EmailRecipients()->toArray());
350
351
        // Filter by rules
352
        $recipients = $recipients->filterByCallback(function ($recipient) use ($data, $form) {
353
            /** @var EmailRecipient $recipient */
354
            return $recipient->canSend($data, $form);
355
        });
356
357
        $this->extend('updateFilteredEmailRecipients', $recipients, $data, $form);
0 ignored issues
show
Bug introduced by
It seems like extend() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

357
        $this->/** @scrutinizer ignore-call */ 
358
               extend('updateFilteredEmailRecipients', $recipients, $data, $form);
Loading history...
358
359
        return $recipients;
360
    }
361
362
    /**
363
     * Custom options for the form. You can extend the built in options by
364
     * using {@link updateFormOptions()}
365
     *
366
     * @return FieldList
367
     */
368
    public function getFormOptions()
369
    {
370
        $submit = ($this->SubmitButtonText) ? $this->SubmitButtonText : _t(__CLASS__.'.SUBMITBUTTON', 'Submit');
371
        $clear = ($this->ClearButtonText) ? $this->ClearButtonText : _t(__CLASS__.'.CLEARBUTTON', 'Clear');
372
373
        $options = FieldList::create(
374
            TextField::create('SubmitButtonText', _t(__CLASS__.'.TEXTONSUBMIT', 'Text on submit button:'), $submit),
375
            TextField::create('ClearButtonText', _t(__CLASS__.'.TEXTONCLEAR', 'Text on clear button:'), $clear),
376
            CheckboxField::create('ShowClearButton', _t(__CLASS__.'.SHOWCLEARFORM', 'Show Clear Form Button'), $this->ShowClearButton),
377
            CheckboxField::create('EnableLiveValidation', _t(__CLASS__.'.ENABLELIVEVALIDATION', 'Enable live validation')),
378
            CheckboxField::create('DisplayErrorMessagesAtTop', _t(__CLASS__.'.DISPLAYERRORMESSAGESATTOP', 'Display error messages above the form?')),
379
            CheckboxField::create('DisableCsrfSecurityToken', _t(__CLASS__.'.DISABLECSRFSECURITYTOKEN', 'Disable CSRF Token')),
380
            CheckboxField::create('DisableAuthenicatedFinishAction', _t(__CLASS__.'.DISABLEAUTHENICATEDFINISHACTION', 'Disable Authentication on finish action'))
381
        );
382
383
        $this->extend('updateFormOptions', $options);
384
385
        return $options;
386
    }
387
388
    /**
389
     * Get the HTML id of the error container displayed above the form.
390
     *
391
     * @return string
392
     */
393
    public function getErrorContainerID()
394
    {
395
        return $this->config()->get('error_container_id');
396
    }
397
398
    /**
399
     * Validate formfields
400
     */
401
    public function getCMSValidator()
402
    {
403
        return UserFormValidator::create();
404
    }
405
}
406