Passed
Pull Request — master (#688)
by Robbie
03:46
created

UserForm::getCMSValidator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
40
/**
41
 * Defines the user defined functionality to be applied to any {@link DataObject}
42
 *
43
 */
44
trait UserForm
45
{
46
    /**
47
     * Built in extensions required by this page.
48
     *
49
     * @config
50
     * @var array
51
     */
52
    private static $extensions = [
53
        UserFormFieldEditorExtension::class
54
    ];
55
56
    /**
57
     * @var string Required Identifier
58
     */
59
    private static $required_identifier = null;
60
61
    /**
62
     * @var string
63
     */
64
    private static $email_template_directory = 'userforms/templates/email/';
65
66
    /**
67
     * Should this module automatically upgrade on dev/build?
68
     *
69
     * @config
70
     * @var bool
71
     */
72
    private static $upgrade_on_build = true;
73
74
    /**
75
     * Set this to true to disable automatic inclusion of CSS files
76
     * @config
77
     * @var bool
78
     */
79
    private static $block_default_userforms_css = false;
80
81
    /**
82
     * Set this to true to disable automatic inclusion of JavaScript files
83
     * @config
84
     * @var bool
85
     */
86
    private static $block_default_userforms_js = false;
87
88
    /**
89
     * @var array Fields on the user defined form page.
90
     */
91
    private static $db = [
92
        'SubmitButtonText' => 'Varchar',
93
        'ClearButtonText' => 'Varchar',
94
        'OnCompleteMessage' => 'HTMLText',
95
        'ShowClearButton' => 'Boolean',
96
        'DisableSaveSubmissions' => 'Boolean',
97
        'EnableLiveValidation' => 'Boolean',
98
        'DisplayErrorMessagesAtTop' => 'Boolean',
99
        'DisableAuthenicatedFinishAction' => 'Boolean',
100
        'DisableCsrfSecurityToken' => 'Boolean'
101
    ];
102
103
    /**
104
     * @var array Default values of variables when this page is created
105
     */
106
    private static $defaults = [
107
        'Content' => '$UserDefinedForm',
108
        'DisableSaveSubmissions' => 0,
109
        'OnCompleteMessage' => '<p>Thanks, we\'ve received your submission.</p>'
110
    ];
111
112
    /**
113
     * @var array
114
     */
115
    private static $has_many = [
116
        'Submissions' => SubmittedForm::class,
117
        'EmailRecipients' => EmailRecipient::class
118
    ];
119
120
    private static $cascade_deletes = [
121
        'EmailRecipients',
122
    ];
123
124
    /**
125
     * @var array
126
     * @config
127
     */
128
    private static $casting = [
129
        'ErrorContainerID' => 'Text'
130
    ];
131
132
    /**
133
     * Error container selector which matches the element for grouped messages
134
     *
135
     * @var string
136
     * @config
137
     */
138
    private static $error_container_id = 'error-container';
139
140
    /**
141
     * The configuration used to determine whether a confirmation message is to
142
     * appear when navigating away from a partially completed form.
143
     *
144
     * @var boolean
145
     * @config
146
     */
147
    private static $enable_are_you_sure = true;
148
149
    /**
150
     * @var bool
151
     * @config
152
     */
153
    private static $recipients_warning_enabled = false;
154
155
    private static $non_live_permissions = ['SITETREE_VIEW_ALL'];
156
157
    /**
158
     * Temporary storage of field ids when the form is duplicated.
159
     * Example layout: array('EditableCheckbox3' => 'EditableCheckbox14')
160
     * @var array
161
     */
162
    protected $fieldsFromTo = [];
163
164
    /**
165
     * @return FieldList
166
     */
167
    public function getCMSFields()
168
    {
169
        Requirements::css('silverstripe/userforms:client/dist/styles/userforms-cms.css');
170
171
        $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

171
        $this->/** @scrutinizer ignore-call */ 
172
               beforeUpdateCMSFields(function ($fields) {
Loading history...
172
173
            // remove
174
            $fields->removeByName('OnCompleteMessageLabel');
175
            $fields->removeByName('OnCompleteMessage');
176
            $fields->removeByName('Fields');
177
            $fields->removeByName('EmailRecipients');
178
179
            // define tabs
180
            $fields->findOrMakeTab('Root.FormOptions', _t(__CLASS__.'.CONFIGURATION', 'Configuration'));
181
            $fields->findOrMakeTab('Root.Recipients', _t(__CLASS__.'.RECIPIENTS', 'Recipients'));
182
            $fields->findOrMakeTab('Root.Submissions', _t(__CLASS__.'.SUBMISSIONS', 'Submissions'));
183
184
185
            // text to show on complete
186
            $onCompleteFieldSet = CompositeField::create(
187
                $label = LabelField::create(
188
                    'OnCompleteMessageLabel',
0 ignored issues
show
Bug introduced by
'OnCompleteMessageLabel' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

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

188
                    /** @scrutinizer ignore-type */ 'OnCompleteMessageLabel',
Loading history...
189
                    _t(__CLASS__.'.ONCOMPLETELABEL', 'Show on completion')
190
                ),
191
                $editor = HTMLEditorField::create(
192
                    'OnCompleteMessage',
193
                    '',
194
                    _t(__CLASS__.'.ONCOMPLETEMESSAGE', $this->OnCompleteMessage)
0 ignored issues
show
Bug Best Practice introduced by
The property OnCompleteMessage does not exist on SilverStripe\UserForms\UserForm. Did you maybe forget to declare it?
Loading history...
195
                )
196
            );
197
198
            $onCompleteFieldSet->addExtraClass('field');
199
200
            $editor->setRows(3);
201
            $label->addExtraClass('left');
202
203
            // Define config for email recipients
204
            $emailRecipientsConfig = GridFieldConfig_RecordEditor::create(10);
0 ignored issues
show
Bug introduced by
10 of type integer is incompatible with the type array expected by parameter $args of SilverStripe\Forms\GridF...idFieldConfig::create(). ( Ignorable by Annotation )

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

204
            $emailRecipientsConfig = GridFieldConfig_RecordEditor::create(/** @scrutinizer ignore-type */ 10);
Loading history...
205
            $emailRecipientsConfig->getComponentByType(GridFieldAddNewButton::class)
206
                ->setButtonName(
207
                    _t(__CLASS__.'.ADDEMAILRECIPIENT', 'Add Email Recipient')
208
                );
209
210
            // who do we email on submission
211
            $emailRecipients = GridField::create(
212
                'EmailRecipients',
213
                '',
214
                $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

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

304
                $this->/** @scrutinizer ignore-call */ 
305
                       Submissions()->sort('Created', 'DESC'),
Loading history...
305
                $config
306
            );
307
            $fields->addFieldToTab('Root.Submissions', $submissions);
308
            $fields->addFieldToTab(
309
                'Root.FormOptions',
310
                CheckboxField::create(
311
                    'DisableSaveSubmissions',
312
                    _t(__CLASS__.'.SAVESUBMISSIONS', 'Disable Saving Submissions to Server')
313
                )
314
            );
315
        });
316
317
        $fields = parent::getCMSFields();
318
319
        if ($this->EmailRecipients()->Count() == 0 && static::config()->recipients_warning_enabled) {
320
            $fields->addFieldToTab('Root.Main', LiteralField::create(
321
                'EmailRecipientsWarning',
0 ignored issues
show
Bug introduced by
'EmailRecipientsWarning' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

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

321
                /** @scrutinizer ignore-type */ 'EmailRecipientsWarning',
Loading history...
322
                '<p class="message warning">' . _t(
323
                    __CLASS__.'.NORECIPIENTS',
324
                    'Warning: You have not configured any recipients. Form submissions may be missed.'
325
                )
326
                . '</p>'
327
            ), 'Title');
328
        }
329
330
        return $fields;
331
    }
332
333
    /**
334
     * Allow overriding the EmailRecipients on a {@link DataExtension}
335
     * so you can customise who receives an email.
336
     * Converts the RelationList to an ArrayList so that manipulation
337
     * of the original source data isn't possible.
338
     *
339
     * @return ArrayList
340
     */
341
    public function FilteredEmailRecipients($data = null, $form = null)
342
    {
343
        $recipients = ArrayList::create($this->EmailRecipients()->toArray());
344
345
        // Filter by rules
346
        $recipients = $recipients->filterByCallback(function ($recipient) use ($data, $form) {
347
            /** @var EmailRecipient $recipient */
348
            return $recipient->canSend($data, $form);
349
        });
350
351
        $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

351
        $this->/** @scrutinizer ignore-call */ 
352
               extend('updateFilteredEmailRecipients', $recipients, $data, $form);
Loading history...
352
353
        return $recipients;
354
    }
355
356
    /**
357
     * Custom options for the form. You can extend the built in options by
358
     * using {@link updateFormOptions()}
359
     *
360
     * @return FieldList
361
     */
362
    public function getFormOptions()
363
    {
364
        $submit = ($this->SubmitButtonText) ? $this->SubmitButtonText : _t(__CLASS__.'.SUBMITBUTTON', 'Submit');
0 ignored issues
show
Bug Best Practice introduced by
The property SubmitButtonText does not exist on SilverStripe\UserForms\UserForm. Did you maybe forget to declare it?
Loading history...
365
        $clear = ($this->ClearButtonText) ? $this->ClearButtonText : _t(__CLASS__.'.CLEARBUTTON', 'Clear');
0 ignored issues
show
Bug Best Practice introduced by
The property ClearButtonText does not exist on SilverStripe\UserForms\UserForm. Did you maybe forget to declare it?
Loading history...
366
367
        $options = FieldList::create(
368
            TextField::create('SubmitButtonText', _t(__CLASS__.'.TEXTONSUBMIT', 'Text on submit button:'), $submit),
0 ignored issues
show
Bug introduced by
'SubmitButtonText' of type string is incompatible with the type array expected by parameter $args of SilverStripe\View\ViewableData::create(). ( Ignorable by Annotation )

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

368
            TextField::create(/** @scrutinizer ignore-type */ 'SubmitButtonText', _t(__CLASS__.'.TEXTONSUBMIT', 'Text on submit button:'), $submit),
Loading history...
369
            TextField::create('ClearButtonText', _t(__CLASS__.'.TEXTONCLEAR', 'Text on clear button:'), $clear),
370
            CheckboxField::create('ShowClearButton', _t(__CLASS__.'.SHOWCLEARFORM', 'Show Clear Form Button'), $this->ShowClearButton),
0 ignored issues
show
Bug Best Practice introduced by
The property ShowClearButton does not exist on SilverStripe\UserForms\UserForm. Did you maybe forget to declare it?
Loading history...
371
            CheckboxField::create('EnableLiveValidation', _t(__CLASS__.'.ENABLELIVEVALIDATION', 'Enable live validation')),
372
            CheckboxField::create('DisplayErrorMessagesAtTop', _t(__CLASS__.'.DISPLAYERRORMESSAGESATTOP', 'Display error messages above the form?')),
373
            CheckboxField::create('DisableCsrfSecurityToken', _t(__CLASS__.'.DISABLECSRFSECURITYTOKEN', 'Disable CSRF Token')),
374
            CheckboxField::create('DisableAuthenicatedFinishAction', _t(__CLASS__.'.DISABLEAUTHENICATEDFINISHACTION', 'Disable Authentication on finish action'))
375
        );
376
377
        $this->extend('updateFormOptions', $options);
378
379
        return $options;
380
    }
381
382
    /**
383
     * Get the HTML id of the error container displayed above the form.
384
     *
385
     * @return string
386
     */
387
    public function getErrorContainerID()
388
    {
389
        return $this->config()->get('error_container_id');
0 ignored issues
show
Bug introduced by
It seems like config() 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

389
        return $this->/** @scrutinizer ignore-call */ config()->get('error_container_id');
Loading history...
390
    }
391
392
    /**
393
     * Validate formfields
394
     */
395
    public function getCMSValidator()
396
    {
397
        return UserFormValidator::create();
398
    }
399
}
400