Passed
Pull Request — master (#722)
by Andrew
08:47
created

EmailRecipient::canCreate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\UserForms\Model\Recipient;
4
5
use SilverStripe\Assets\FileFinder;
6
use SilverStripe\CMS\Controllers\CMSMain;
7
use SilverStripe\CMS\Controllers\CMSPageEditController;
8
use SilverStripe\CMS\Model\SiteTree;
9
use SilverStripe\Control\Controller;
10
use SilverStripe\Control\Email\Email;
11
use SilverStripe\Core\Manifest\ModuleResource;
12
use SilverStripe\Core\Manifest\ModuleResourceLoader;
13
use SilverStripe\Forms\CheckboxField;
14
use SilverStripe\Forms\DropdownField;
15
use SilverStripe\Forms\FieldGroup;
16
use SilverStripe\Forms\FieldList;
17
use SilverStripe\Forms\Form;
18
use SilverStripe\Forms\GridField\GridField;
19
use SilverStripe\Forms\GridField\GridFieldButtonRow;
20
use SilverStripe\Forms\GridField\GridFieldConfig;
21
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
22
use SilverStripe\Forms\GridField\GridFieldToolbarHeader;
23
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
24
use SilverStripe\Forms\LiteralField;
25
use SilverStripe\Forms\TabSet;
26
use SilverStripe\Forms\TextareaField;
27
use SilverStripe\Forms\TextField;
28
use SilverStripe\ORM\ArrayList;
29
use SilverStripe\ORM\DataList;
30
use SilverStripe\ORM\DataObject;
31
use SilverStripe\ORM\DB;
32
use SilverStripe\ORM\FieldType\DBField;
33
use SilverStripe\ORM\ValidationResult;
34
use SilverStripe\UserForms\Model\EditableFormField;
35
use SilverStripe\UserForms\Model\EditableFormField\EditableEmailField;
36
use SilverStripe\UserForms\Model\EditableFormField\EditableMultipleOptionField;
37
use SilverStripe\UserForms\Model\EditableFormField\EditableTextField;
38
use SilverStripe\UserForms\Model\UserDefinedForm;
39
use SilverStripe\View\Requirements;
40
use Symbiote\GridFieldExtensions\GridFieldAddNewInlineButton;
41
use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
42
43
/**
44
 * A Form can have multiply members / emails to email the submission
45
 * to and custom subjects
46
 *
47
 * @package userforms
48
 */
49
class EmailRecipient extends DataObject
50
{
51
    private static $db = [
52
        'EmailAddress' => 'Varchar(200)',
53
        'EmailSubject' => 'Varchar(200)',
54
        'EmailFrom' => 'Varchar(200)',
55
        'EmailReplyTo' => 'Varchar(200)',
56
        'EmailBody' => 'Text',
57
        'EmailBodyHtml' => 'HTMLText',
58
        'EmailTemplate' => 'Varchar',
59
        'SendPlain' => 'Boolean',
60
        'HideFormData' => 'Boolean',
61
        'CustomRulesCondition' => 'Enum("And,Or")'
62
    ];
63
64
    private static $has_one = [
65
        'Form' => DataObject::class,
66
        'SendEmailFromField' => EditableFormField::class,
67
        'SendEmailToField' => EditableFormField::class,
68
        'SendEmailSubjectField' => EditableFormField::class
69
    ];
70
71
    private static $has_many = [
72
        'CustomRules' => EmailRecipientCondition::class,
73
    ];
74
75
    private static $owns = [
76
        'CustomRules',
77
    ];
78
79
    private static $cascade_deletes = [
80
        'CustomRules',
81
    ];
82
83
    private static $summary_fields = [
84
        'EmailAddress',
85
        'EmailSubject',
86
        'EmailFrom'
87
    ];
88
89
    private static $table_name = 'UserDefinedForm_EmailRecipient';
90
91
    /**
92
     * Setting this to true will allow you to select "risky" fields as
93
     * email recipient, such as free-text entry fields.
94
     *
95
     * It's advisable to leave this off.
96
     *
97
     * @config
98
     * @var bool
99
     */
100
    private static $allow_unbound_recipient_fields = false;
101
102
    public function requireDefaultRecords()
103
    {
104
        parent::requireDefaultRecords();
105
106
        // make sure to migrate the class across (prior to v5.x)
107
        DB::query("UPDATE UserDefinedForm_EmailRecipient SET FormClass = 'Page' WHERE FormClass IS NULL");
108
    }
109
110
    public function summaryFields()
111
    {
112
        $fields = parent::summaryFields();
113
        if (isset($fields['EmailAddress'])) {
114
            /** @skipUpgrade */
115
            $fields['EmailAddress'] = _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILADDRESS', 'Email');
116
        }
117
        if (isset($fields['EmailSubject'])) {
118
            $fields['EmailSubject'] = _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILSUBJECT', 'Subject');
119
        }
120
        if (isset($fields['EmailFrom'])) {
121
            $fields['EmailFrom'] = _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILFROM', 'From');
122
        }
123
        return $fields;
124
    }
125
126
    /**
127
     * Get instance of UserForm when editing in getCMSFields
128
     *
129
     * @return UserDefinedForm
130
     */
131
    protected function getFormParent()
132
    {
133
        // LeftAndMain::sessionNamespace is protected. @todo replace this with a non-deprecated equivalent.
134
        $sessionNamespace = $this->config()->get('session_namespace') ?: CMSMain::class;
135
136
        $formID = $this->FormID ?: Controller::curr()->getRequest()->getSession()->get($sessionNamespace . '.currentPage');
0 ignored issues
show
Bug Best Practice introduced by
The property FormID does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
137
        $formClass = $this->FormClass ?: UserDefinedForm::class;
0 ignored issues
show
Bug Best Practice introduced by
The property FormClass does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
138
139
        return $formClass::get()->byID($formID);
140
    }
141
142
    public function getTitle()
143
    {
144
        if ($this->EmailAddress) {
0 ignored issues
show
Bug Best Practice introduced by
The property EmailAddress does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
145
            return $this->EmailAddress;
146
        }
147
        if ($this->EmailSubject) {
0 ignored issues
show
Bug Best Practice introduced by
The property EmailSubject does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
148
            return $this->EmailSubject;
149
        }
150
        return parent::getTitle();
151
    }
152
153
    /**
154
     * Generate a gridfield config for editing filter rules
155
     *
156
     * @return GridFieldConfig
157
     */
158
    protected function getRulesConfig()
159
    {
160
        if (!$this->getFormParent()) {
161
            return null;
162
        }
163
        $formFields = $this->getFormParent()->Fields();
164
165
        $config = GridFieldConfig::create()
166
            ->addComponents(
167
                new GridFieldButtonRow('before'),
168
                new GridFieldToolbarHeader(),
169
                new GridFieldAddNewInlineButton(),
170
                new GridFieldDeleteAction(),
171
                $columns = new GridFieldEditableColumns()
172
            );
173
174
        $columns->setDisplayFields(array(
175
            'ConditionFieldID' => function ($record, $column, $grid) use ($formFields) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid is not used and could be removed. ( Ignorable by Annotation )

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

175
            'ConditionFieldID' => function ($record, $column, /** @scrutinizer ignore-unused */ $grid) use ($formFields) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
176
                return DropdownField::create($column, false, $formFields->map('ID', 'Title'));
0 ignored issues
show
Bug introduced by
false of type false 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

176
                return DropdownField::create($column, /** @scrutinizer ignore-type */ false, $formFields->map('ID', 'Title'));
Loading history...
177
            },
178
            'ConditionOption' => function ($record, $column, $grid) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid is not used and could be removed. ( Ignorable by Annotation )

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

178
            'ConditionOption' => function ($record, $column, /** @scrutinizer ignore-unused */ $grid) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
179
                $options = EmailRecipientCondition::config()->condition_options;
180
                return DropdownField::create($column, false, $options);
0 ignored issues
show
Bug introduced by
false of type false 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

180
                return DropdownField::create($column, /** @scrutinizer ignore-type */ false, $options);
Loading history...
181
            },
182
            'ConditionValue' => function ($record, $column, $grid) {
0 ignored issues
show
Unused Code introduced by
The parameter $grid is not used and could be removed. ( Ignorable by Annotation )

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

182
            'ConditionValue' => function ($record, $column, /** @scrutinizer ignore-unused */ $grid) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
183
                return TextField::create($column);
184
            }
185
        ));
186
187
        return $config;
188
    }
189
190
    /**
191
     * @return FieldList
192
     */
193
    public function getCMSFields()
194
    {
195
        Requirements::javascript('silverstripe/userforms:client/dist/js/userforms-cms.js');
196
197
        // Build fieldlist
198
        $fields = FieldList::create(Tabset::create('Root')->addExtraClass('EmailRecipientForm'));
0 ignored issues
show
Bug introduced by
'Root' 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

198
        $fields = FieldList::create(Tabset::create(/** @scrutinizer ignore-type */ 'Root')->addExtraClass('EmailRecipientForm'));
Loading history...
199
200
        // Configuration fields
201
        $fields->addFieldsToTab('Root.EmailDetails', [
202
            $this->getSubjectCMSFields(),
203
            $this->getEmailToCMSFields(),
204
            $this->getEmailFromCMSFields(),
205
            $this->getEmailReplyToCMSFields(),
206
        ]);
207
        $fields->fieldByName('Root.EmailDetails')->setTitle(_t(__CLASS__ . '.EMAILDETAILSTAB', 'Email Details'));
208
209
        // Only show the preview link if the recipient has been saved.
210
        if (!empty($this->EmailTemplate)) {
0 ignored issues
show
Bug Best Practice introduced by
The property EmailTemplate does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
211
            $pageEditController = singleton(CMSPageEditController::class);
212
            $pageEditController
213
                ->getRequest()
214
                ->setSession(Controller::curr()->getRequest()->getSession());
215
216
            $preview = sprintf(
217
                '<p><a href="%s" target="_blank" class="btn btn-outline-secondary">%s</a></p><em>%s</em>',
218
                Controller::join_links(
219
                    $pageEditController->getEditForm()->FormAction(),
220
                    "field/EmailRecipients/item/{$this->ID}/preview"
221
                ),
222
                _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.PREVIEW_EMAIL', 'Preview email'),
223
                _t(
224
                    'SilverStripe\\UserForms\\Model\\UserDefinedForm.PREVIEW_EMAIL_DESCRIPTION',
225
                    'Note: Unsaved changes will not appear in the preview.'
226
                )
227
            );
228
        } else {
229
            $preview = sprintf(
230
                '<em>%s</em>',
231
                _t(
232
                    'SilverStripe\\UserForms\\Model\\UserDefinedForm.PREVIEW_EMAIL_UNAVAILABLE',
233
                    'You can preview this email once you have saved the Recipient.'
234
                )
235
            );
236
        }
237
238
        // Email templates
239
        $fields->addFieldsToTab('Root.EmailContent', [
240
            CheckboxField::create(
241
                'HideFormData',
242
                _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.HIDEFORMDATA', 'Hide form data from email?')
243
            ),
244
            CheckboxField::create(
245
                'SendPlain',
246
                _t(
247
                    'SilverStripe\\UserForms\\Model\\UserDefinedForm.SENDPLAIN',
248
                    'Send email as plain text? (HTML will be stripped)'
249
                )
250
            ),
251
            HTMLEditorField::create(
252
                'EmailBodyHtml',
253
                _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILBODYHTML', 'Body')
254
            )
255
                ->addExtraClass('toggle-html-only'),
256
            TextareaField::create(
257
                'EmailBody',
258
                _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILBODY', 'Body')
259
            )
260
                ->addExtraClass('toggle-plain-only'),
261
            LiteralField::create('EmailPreview', $preview)
262
        ]);
263
264
        $templates = $this->getEmailTemplateDropdownValues();
265
266
        if ($templates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $templates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
267
            $fields->insertBefore(
268
                DropdownField::create(
269
                    'EmailTemplate',
270
                    _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILTEMPLATE', 'Email template'),
271
                    $templates
272
                )->addExtraClass('toggle-html-only'),
273
                'EmailBodyHtml'
274
            );
275
        }
276
277
        $fields->fieldByName('Root.EmailContent')->setTitle(_t(__CLASS__ . '.EMAILCONTENTTAB', 'Email Content'));
278
279
        // Custom rules for sending this field
280
        $grid = GridField::create(
281
            'CustomRules',
282
            _t('SilverStripe\\UserForms\\Model\\EditableFormField.CUSTOMRULES', 'Custom Rules'),
283
            $this->CustomRules(),
0 ignored issues
show
Bug introduced by
The method CustomRules() does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

283
            $this->/** @scrutinizer ignore-call */ 
284
                   CustomRules(),
Loading history...
284
            $this->getRulesConfig()
0 ignored issues
show
Bug introduced by
$this->getRulesConfig() of type SilverStripe\Forms\GridField\GridFieldConfig 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

284
            /** @scrutinizer ignore-type */ $this->getRulesConfig()
Loading history...
285
        );
286
        $grid->setDescription(_t(
287
            'SilverStripe\\UserForms\\Model\\UserDefinedForm.RulesDescription',
288
            '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.'
289
        ));
290
        $fields->addFieldsToTab('Root.CustomRules', [
291
            DropdownField::create(
292
                'CustomRulesCondition',
293
                _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.SENDIF', 'Send condition'),
294
                [
295
                    'Or' => _t(
296
                        'SilverStripe\\UserForms\\Model\\UserDefinedForm.SENDIFOR',
297
                        'Any conditions are true'
298
                    ),
299
                    'And' => _t(
300
                        'SilverStripe\\UserForms\\Model\\UserDefinedForm.SENDIFAND',
301
                        'All conditions are true'
302
                    )
303
                ]
304
            ),
305
            $grid
306
        ]);
307
308
            $fields->fieldByName('Root.CustomRules')->setTitle(_t(__CLASS__ . '.CUSTOMRULESTAB', 'Custom Rules'));
309
310
        $this->extend('updateCMSFields', $fields);
311
        return $fields;
312
    }
313
314
    /**
315
     * Return whether a user can create an object of this type
316
     *
317
     * @param Member $member
0 ignored issues
show
Bug introduced by
The type SilverStripe\UserForms\Model\Recipient\Member 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...
318
     * @param array $context Virtual parameter to allow context to be passed in to check
319
     * @return bool
320
     */
321
    public function canCreate($member = null, $context = [])
322
    {
323
        // Check parent page
324
        $parent = $this->getCanCreateContext(func_get_args());
325
        if ($parent) {
0 ignored issues
show
introduced by
The condition $parent can never be true.
Loading history...
326
            return $parent->canEdit($member);
327
        }
328
329
        // Fall back to secure admin permissions
330
        return parent::canCreate($member);
331
    }
332
333
    /**
334
     * Helper method to check the parent for this object
335
     *
336
     * @param array $args List of arguments passed to canCreate
337
     * @return SiteTree Parent page instance
338
     */
339
    protected function getCanCreateContext($args)
340
    {
341
        // Inspect second parameter to canCreate for a 'Parent' context
342
        if (isset($args[1][Form::class])) {
343
            return $args[1][Form::class];
344
        }
345
        // Hack in currently edited page if context is missing
346
        if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
347
            return Controller::curr()->currentPage();
348
        }
349
350
        // No page being edited
351
        return null;
352
    }
353
354
    public function canView($member = null)
355
    {
356
        if ($form = $this->getFormParent()) {
357
            return $form->canView($member);
358
        }
359
        return parent::canView($member);
360
    }
361
362
    public function canEdit($member = null)
363
    {
364
        if ($form = $this->getFormParent()) {
365
            return $form->canEdit($member);
366
        }
367
368
        return parent::canEdit($member);
369
    }
370
371
    /**
372
     * @param Member
373
     *
374
     * @return boolean
375
     */
376
    public function canDelete($member = null)
377
    {
378
        return $this->canEdit($member);
379
    }
380
381
    /**
382
     * Determine if this recipient may receive notifications for this submission
383
     *
384
     * @param array $data
385
     * @param Form $form
386
     * @return bool
387
     */
388
    public function canSend($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed. ( Ignorable by Annotation )

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

388
    public function canSend($data, /** @scrutinizer ignore-unused */ $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
389
    {
390
        // Skip if no rules configured
391
        $customRules = $this->CustomRules();
392
        if (!$customRules->count()) {
393
            return true;
394
        }
395
396
        // Check all rules
397
        $isAnd = $this->CustomRulesCondition === 'And';
0 ignored issues
show
Bug Best Practice introduced by
The property CustomRulesCondition does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
398
        foreach ($customRules as $customRule) {
399
            /** @var EmailRecipientCondition  $customRule */
400
            $matches = $customRule->matches($data);
401
            if ($isAnd && !$matches) {
402
                return false;
403
            }
404
            if (!$isAnd && $matches) {
405
                return true;
406
            }
407
        }
408
409
        // Once all rules are checked
410
        return $isAnd;
411
    }
412
413
    /**
414
     * Make sure the email template saved against the recipient exists on the file system.
415
     *
416
     * @param string
417
     *
418
     * @return boolean
419
     */
420
    public function emailTemplateExists($template = '')
421
    {
422
        $t = ($template ? $template : $this->EmailTemplate);
0 ignored issues
show
Bug Best Practice introduced by
The property EmailTemplate does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
423
424
        return array_key_exists($t, (array) $this->getEmailTemplateDropdownValues());
425
    }
426
427
    /**
428
     * Get the email body for the current email format
429
     *
430
     * @return string
431
     */
432
    public function getEmailBodyContent()
433
    {
434
        if ($this->SendPlain) {
0 ignored issues
show
Bug Best Practice introduced by
The property SendPlain does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
435
            return DBField::create_field('HTMLText', $this->EmailBody)->Plain();
0 ignored issues
show
Bug Best Practice introduced by
The property EmailBody does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
436
        }
437
        return DBField::create_field('HTMLText', $this->EmailBodyHtml);
0 ignored issues
show
Bug Best Practice introduced by
The property EmailBodyHtml does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
438
    }
439
440
    /**
441
     * Gets a list of email templates suitable for populating the email template dropdown.
442
     *
443
     * @return array
444
     */
445
    public function getEmailTemplateDropdownValues()
446
    {
447
        $templates = [];
448
449
        $finder = new FileFinder();
450
        $finder->setOption('name_regex', '/^.*\.ss$/');
451
452
        $parent = $this->getFormParent();
453
454
        if (!$parent) {
0 ignored issues
show
introduced by
The condition ! $parent can never be false.
Loading history...
455
            return [];
456
        }
457
458
        $emailTemplateDirectory = $parent->config()->get('email_template_directory');
459
        $templateDirectory = ModuleResourceLoader::resourcePath($emailTemplateDirectory);
460
461
        if (!$templateDirectory) {
462
            return [];
463
        }
464
465
        $found = $finder->find(BASE_PATH . DIRECTORY_SEPARATOR . $templateDirectory);
466
467
        foreach ($found as $key => $value) {
468
            $template = pathinfo($value);
469
            $absoluteFilename = $template['dirname'] . DIRECTORY_SEPARATOR . $template['filename'];
470
471
            // Optionally remove vendor/ path prefixes
472
            $resource = ModuleResourceLoader::singleton()->resolveResource($emailTemplateDirectory);
473
            if ($resource instanceof ModuleResource && $resource->getModule()) {
474
                $prefixToStrip = $resource->getModule()->getPath();
475
            } else {
476
                $prefixToStrip = BASE_PATH;
477
            }
478
            $templatePath = substr($absoluteFilename, strlen($prefixToStrip) + 1);
479
480
            // Optionally remove "templates/" prefixes
481
            if (substr($templatePath, 0, 10)) {
482
                $templatePath = substr($templatePath, 10);
483
            }
484
485
            $templates[$templatePath] = $template['filename'];
486
        }
487
488
        return $templates;
489
    }
490
491
    /**
492
     * Validate that valid email addresses are being used
493
     *
494
     * @return ValidationResult
495
     */
496
    public function validate()
497
    {
498
        $result = parent::validate();
499
        $checkEmail = [
500
            'EmailAddress' => 'EMAILADDRESSINVALID',
501
            'EmailFrom' => 'EMAILFROMINVALID',
502
            'EmailReplyTo' => 'EMAILREPLYTOINVALID',
503
        ];
504
        foreach ($checkEmail as $check => $translation) {
505
            if ($this->$check) {
506
                //may be a comma separated list of emails
507
                $addresses = explode(',', $this->$check);
508
                foreach ($addresses as $address) {
509
                    $trimAddress = trim($address);
510
                    if ($trimAddress && !Email::is_valid_address($trimAddress)) {
511
                        $error = _t(
512
                            __CLASS__.".$translation",
513
                            "Invalid email address $trimAddress"
514
                        );
515
                        $result->addError($error . " ($trimAddress)");
516
                    }
517
                }
518
            }
519
        }
520
521
        // if there is no from address and no fallback, you'll have errors if this isn't defined
522
        if (!$this->EmailFrom && empty(Email::getSendAllEmailsFrom()) && empty(Email::config()->get('admin_email'))) {
0 ignored issues
show
Bug Best Practice introduced by
The property EmailFrom does not exist on SilverStripe\UserForms\M...ecipient\EmailRecipient. Since you implemented __get, consider adding a @property annotation.
Loading history...
523
            $result->addError(_t(__CLASS__.".EMAILFROMREQUIRED", '"Email From" address is required'));
524
        }
525
        return $result;
526
    }
527
528
    /**
529
     * @return FieldGroup|TextField
530
     */
531
    protected function getSubjectCMSFields()
532
    {
533
        $subjectTextField = TextField::create(
534
            'EmailSubject',
0 ignored issues
show
Bug introduced by
'EmailSubject' 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

534
            /** @scrutinizer ignore-type */ 'EmailSubject',
Loading history...
535
            _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.TYPESUBJECT', 'Type subject')
536
        )
537
            ->setAttribute('style', 'min-width: 400px;');
538
539
        if ($this->getFormParent() && $this->getValidSubjectFields()) {
540
            return FieldGroup::create(
541
                $subjectTextField,
542
                DropdownField::create(
543
                    'SendEmailSubjectFieldID',
544
                    _t(
545
                        'SilverStripe\\UserForms\\Model\\UserDefinedForm.SELECTAFIELDTOSETSUBJECT',
546
                        '.. or select a field to use as the subject'
547
                    ),
548
                    $this->getValidSubjectFields()->map('ID', 'Title')
0 ignored issues
show
Bug introduced by
$this->getValidSubjectFi...s()->map('ID', 'Title') of type SilverStripe\ORM\Map 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

548
                    /** @scrutinizer ignore-type */ $this->getValidSubjectFields()->map('ID', 'Title')
Loading history...
549
                )->setEmptyString('')
550
            )
551
                ->setTitle(_t('SilverStripe\\UserForms\\Model\\UserDefinedForm.EMAILSUBJECT', 'Email subject'));
552
        } else {
553
            return $subjectTextField;
554
        }
555
    }
556
557
    /**
558
     * @return FieldGroup|TextField
559
     */
560
    protected function getEmailToCMSFields()
561
    {
562
        $emailToTextField = TextField::create(
563
            'EmailAddress',
0 ignored issues
show
Bug introduced by
'EmailAddress' 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

563
            /** @scrutinizer ignore-type */ 'EmailAddress',
Loading history...
564
            _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.TYPETO', 'Type to address')
565
        )
566
            ->setAttribute('style', 'min-width: 400px;');
567
568
        if ($this->getFormParent() && $this->getValidEmailToFields()) {
569
            return FieldGroup::create(
570
                $emailToTextField,
571
                DropdownField::create(
572
                    'SendEmailToFieldID',
573
                    _t(
574
                        'SilverStripe\\UserForms\\Model\\UserDefinedForm.ORSELECTAFIELDTOUSEASTO',
575
                        '.. or select a field to use as the to address'
576
                    ),
577
                    $this->getValidEmailToFields()->map('ID', 'Title')
0 ignored issues
show
Bug introduced by
$this->getValidEmailToFi...s()->map('ID', 'Title') of type SilverStripe\ORM\Map 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

577
                    /** @scrutinizer ignore-type */ $this->getValidEmailToFields()->map('ID', 'Title')
Loading history...
578
                )->setEmptyString(' ')
579
            )
580
                ->setTitle(_t('SilverStripe\\UserForms\\Model\\UserDefinedForm.SENDEMAILTO', 'Send email to'))
581
                ->setDescription(_t(
582
                    'SilverStripe\\UserForms\\Model\\UserDefinedForm.SENDEMAILTO_DESCRIPTION',
583
                    'You may enter multiple email addresses as a comma separated list.'
584
                ));
585
        } else {
586
            return $emailToTextField;
587
        }
588
    }
589
590
    /**
591
     * @return TextField
592
     */
593
    protected function getEmailFromCMSFields()
594
    {
595
        return TextField::create(
596
            'EmailFrom',
0 ignored issues
show
Bug introduced by
'EmailFrom' 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

596
            /** @scrutinizer ignore-type */ 'EmailFrom',
Loading history...
597
            _t('SilverStripe\\UserForms\\Model\\UserDefinedForm.FROMADDRESS', 'Send email from')
598
        )
599
            ->setDescription(_t(
600
                'SilverStripe\\UserForms\\Model\\UserDefinedForm.EmailFromContent',
601
                "The from address allows you to set who the email comes from. On most servers this " .
602
                "will need to be set to an email address on the same domain name as your site. " .
603
                "For example on yoursite.com the from address may need to be [email protected]. " .
604
                "You can however, set any email address you wish as the reply to address."
605
            ));
606
    }
607
608
    /**
609
     * @return FieldGroup|TextField
610
     */
611
    protected function getEmailReplyToCMSFields()
612
    {
613
        $replyToTextField = TextField::create('EmailReplyTo', _t(
0 ignored issues
show
Bug introduced by
'EmailReplyTo' 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

613
        $replyToTextField = TextField::create(/** @scrutinizer ignore-type */ 'EmailReplyTo', _t(
Loading history...
614
            'SilverStripe\\UserForms\\Model\\UserDefinedForm.TYPEREPLY',
615
            'Type reply address'
616
        ))
617
            ->setAttribute('style', 'min-width: 400px;');
618
        if ($this->getFormParent() && $this->getValidEmailFromFields()) {
619
            return FieldGroup::create(
620
                $replyToTextField,
621
                DropdownField::create(
622
                    'SendEmailFromFieldID',
623
                    _t(
624
                        'SilverStripe\\UserForms\\Model\\UserDefinedForm.ORSELECTAFIELDTOUSEASFROM',
625
                        '.. or select a field to use as reply to address'
626
                    ),
627
                    $this->getValidEmailFromFields()->map('ID', 'Title')
0 ignored issues
show
Bug introduced by
$this->getValidEmailFrom...s()->map('ID', 'Title') of type SilverStripe\ORM\Map 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

627
                    /** @scrutinizer ignore-type */ $this->getValidEmailFromFields()->map('ID', 'Title')
Loading history...
628
                )->setEmptyString(' ')
629
            )
630
                ->setTitle(_t(
631
                    'SilverStripe\\UserForms\\Model\\UserDefinedForm.REPLYADDRESS',
632
                    'Email for reply to'
633
                ))
634
                ->setDescription(_t(
635
                    'SilverStripe\\UserForms\\Model\\UserDefinedForm.REPLYADDRESS_DESCRIPTION',
636
                    'The email address which the recipient is able to \'reply\' to.'
637
                ));
638
        } else {
639
            return $replyToTextField;
640
        }
641
    }
642
643
    /**
644
     * @return DataList|null
645
     */
646
    protected function getMultiOptionFields()
647
    {
648
        if (!$form = $this->getFormParent()) {
649
            return null;
650
        }
651
        return EditableMultipleOptionField::get()->filter('ParentID', $form->ID);
652
    }
653
654
    /**
655
     * @return ArrayList|null
656
     */
657
    protected function getValidSubjectFields()
658
    {
659
        if (!$form = $this->getFormParent()) {
660
            return null;
661
        }
662
        // For the subject, only one-line entry boxes make sense
663
        $validSubjectFields = ArrayList::create(
664
            EditableTextField::get()
665
                ->filter('ParentID', $form->ID)
666
                ->exclude('Rows:GreaterThan', 1)
667
                ->toArray()
668
        );
669
        $validSubjectFields->merge($this->getMultiOptionFields());
670
        return $validSubjectFields;
671
    }
672
673
    /**
674
     * @return DataList|null
675
     */
676
    protected function getValidEmailFromFields()
677
    {
678
        if (!$form = $this->getFormParent()) {
679
            return null;
680
        }
681
682
        // if they have email fields then we could send from it
683
        return EditableEmailField::get()->filter('ParentID', $form->ID);
684
    }
685
686
    /**
687
     * @return ArrayList|DataList|null
688
     */
689
    protected function getValidEmailToFields()
690
    {
691
        if (!$form = $this->getFormParent()) {
0 ignored issues
show
Unused Code introduced by
The assignment to $form is dead and can be removed.
Loading history...
692
            return null;
693
        }
694
695
        // Check valid email-recipient fields
696
        if ($this->config()->get('allow_unbound_recipient_fields')) {
697
            // To address can only be email fields or multi option fields
698
            $validEmailToFields = ArrayList::create($this->getValidEmailFromFields()->toArray());
699
            $validEmailToFields->merge($this->getMultiOptionFields());
700
            return $validEmailToFields;
701
        } else {
702
            // To address cannot be unbound, so restrict to pre-defined lists
703
            return $this->getMultiOptionFields();
704
        }
705
    }
706
}
707