Completed
Push — master ( 5f8d2a...42c733 )
by Franco
11s
created

EditableSpamProtectionField::getFormField()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
cc 4
eloc 13
nc 4
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 31 and the first side effect is on line 22.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
namespace SilverStripe\SpamProtection;
4
5
use SilverStripe\Core\ClassInfo;
6
use SilverStripe\Core\Convert;
7
use SilverStripe\Forms\DropdownField;
8
use SilverStripe\Forms\FieldGroup;
9
use SilverStripe\Forms\FieldList;
10
use SilverStripe\Forms\FormField;
11
use SilverStripe\ORM\UnsavedRelationList;
12
use SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension;
13
use SilverStripe\UserForms\Model\EditableFormField;
14
use SilverStripe\UserForms\Model\EditableFormField\EditableEmailField;
15
use SilverStripe\UserForms\Model\EditableFormField\EditableNumericField;
16
use SilverStripe\UserForms\Model\EditableFormField\EditableTextField;
17
18
/**
19
 * @todo The userforms namespaces may still change, as the branch is not merged in yet
20
 */
21
if (!class_exists(EditableFormField::class)) {
22
    return;
23
}
24
25
/**
26
 * Editable Spam Protecter Field. Used with the User Defined Forms module (if
27
 * installed) to allow the user to have captcha fields with their custom forms
28
 *
29
 * @package spamprotection
30
 */
31
class EditableSpamProtectionField extends EditableFormField
32
{
33
    private static $singular_name = 'Spam Protection Field';
0 ignored issues
show
Unused Code introduced by
The property $singular_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
34
35
    private static $plural_name = 'Spam Protection Fields';
0 ignored issues
show
Unused Code introduced by
The property $plural_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
36
37
    private static $table_name = 'EditableSpamProtectionField';
0 ignored issues
show
Unused Code introduced by
The property $table_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
38
39
    /**
40
     * Fields to include spam detection for
41
     *
42
     * @var array
43
     * @config
44
     */
45
    private static $check_fields = array(
0 ignored issues
show
Unused Code introduced by
The property $check_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
46
        EditableEmailField::class,
47
        EditableTextField::class,
48
        EditableNumericField::class
49
    );
50
51
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
52
        'SpamFieldSettings' => 'Text'
53
    );
54
55
    /**
56
     * @var FormField
57
     */
58
    protected $formField = null;
59
60
    public function getFormField()
61
    {
62
        if ($this->formField) {
63
            return $this->formField;
64
        }
65
66
        // Get protector
67
        $protector = FormSpamProtectionExtension::get_protector();
68
        if (!$protector) {
69
            return false;
70
        }
71
72
        // Extract saved field mappings and update this field.
73
        $fieldMapping = array();
74
        foreach ($this->getCandidateFields() as $otherField) {
75
            $mapSetting = "Map-{$otherField->Name}";
76
            $spamField = $this->spamMapValue($mapSetting);
77
            $fieldMapping[$otherField->Name] = $spamField;
78
        }
79
        $protector->setFieldMapping($fieldMapping);
80
81
        // Generate field
82
        return $protector->getFormField($this->Name, $this->Title, null);
83
    }
84
85
    /**
86
     * @param FormField $field
87
     * @return self
88
     */
89
    public function setFormField(FormField $field)
90
    {
91
        $this->formField = $field;
92
93
        return $this;
94
    }
95
96
    /**
97
     * Gets the list of all candidate spam detectable fields on this field's form
98
     *
99
     * @return DataList
100
     */
101
    protected function getCandidateFields()
102
    {
103
104
        // Get list of all configured classes available for spam detection
105
        $types = $this->config()->get('check_fields');
106
        $typesInherit = array();
107
        foreach ($types as $type) {
108
            $subTypes = ClassInfo::subclassesFor($type);
109
            $typesInherit = array_merge($typesInherit, $subTypes);
110
        }
111
112
        // Get all candidates of the above types
113
        return $this
114
            ->Parent()
115
            ->Fields()
116
            ->filter('ClassName', $typesInherit)
117
            ->exclude('Title', ''); // Ignore this field and those without titles
118
    }
119
120
    /**
121
     * Write the spam field mapping values to a serialised DB field
122
     *
123
     * {@inheritDoc}
124
     */
125
    public function onBeforeWrite()
126
    {
127
        $fieldMap = Convert::json2array($this->SpamFieldSettings);
128
        if (empty($fieldMap)) {
129
            $fieldMap = array();
130
        }
131
132
        foreach ($this->record as $key => $value) {
133
            if (substr($key, 0, 8) === 'spammap-') {
134
                $fieldMap[substr($key, 8)] = $value;
135
            }
136
        }
137
        $this->setField('SpamFieldSettings', Convert::raw2json($fieldMap));
138
139
        return parent::onBeforeWrite();
140
    }
141
142
    /**
143
     * Used in userforms 3.x and above
144
     *
145
     * {@inheritDoc}
146
     */
147
    public function getCMSFields()
148
    {
149
        /** @var FieldList $fields */
150
        $fields = parent::getCMSFields();
151
152
        // Get protector
153
        $protector = FormSpamProtectionExtension::get_protector();
154
        if (!$protector) {
155
            var_dump('a');
0 ignored issues
show
Security Debugging Code introduced by
var_dump('a'); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
156
            return $fields;
157
        }
158
159
        if ($this->Parent()->Fields() instanceof UnsavedRelationList) {
160
            var_dump('b');
161
            return $fields;
162
        }
163
164
        // Each other text field in this group can be assigned a field mapping
165
        $mapGroup = FieldGroup::create()
166
            ->setTitle(_t(__CLASS__.'.SPAMFIELDMAPPING', 'Spam Field Mapping'))
167
            ->setName('SpamFieldMapping')
168
            ->setDescription(_t(
169
                __CLASS__.'.SPAMFIELDMAPPINGDESCRIPTION',
170
                'Select the form fields that correspond to any relevant spam protection identifiers'
171
            ));
172
173
        // Generate field specific settings
174
        $mappableFields = FormSpamProtectionExtension::config()->get('mappable_fields');
175
        $mappableFieldsMerged = array_combine($mappableFields, $mappableFields);
176
        foreach ($this->getCandidateFields() as $otherField) {
177
            $mapSetting = "Map-{$otherField->Name}";
178
            $fieldOption = DropdownField::create(
179
                'spammap-' . $mapSetting,
180
                $otherField->Title,
181
                $mappableFieldsMerged,
182
                $this->spamMapValue($mapSetting)
183
            )->setEmptyString('');
184
            $mapGroup->push($fieldOption);
185
        }
186
        $fields->addFieldToTab('Root.Main', $mapGroup);
187
188
        return $fields;
189
    }
190
191
    /**
192
     * Try to retrieve a value for the given spam field map name from the serialised data
193
     *
194
     * @param string $mapSetting
195
     * @return string
196
     */
197
    public function spamMapValue($mapSetting)
198
    {
199
        $map = Convert::json2array($this->SpamFieldSettings);
200
        if (empty($map)) {
201
            $map = array();
202
        }
203
204
        if (array_key_exists($mapSetting, $map)) {
205
            return $map[$mapSetting];
206
        }
207
        return '';
208
    }
209
210
    /**
211
     * Using custom validateField method
212
     * as Spam Protection Field implementations may have their own error messages
213
     * and may not be based on the field being required, e.g. Honeypot Field
214
     *
215
     * @param array $data
216
     * @param Form $form
217
     * @return void
218
     */
219
    public function validateField($data, $form)
220
    {
221
        $formField = $this->getFormField();
222
        $formField->setForm($form);
223
224
        if (isset($data[$this->Name])) {
225
            $formField->setValue($data[$this->Name]);
226
        }
227
228
        $validator = $form->getValidator();
229
        if (!$formField->validate($validator)) {
230
            $errors = $validator->getErrors();
231
            $foundError = false;
232
233
            // field validate implementation may not add error to validator
234
            if (count($errors) > 0) {
235
                // check if error already added from fields' validate method
236
                foreach ($errors as $error) {
237
                    if ($error['fieldName'] == $this->Name) {
238
                        $foundError = $error;
239
                        break;
240
                    }
241
                }
242
            }
243
244
            if ($foundError !== false) {
245
                // use error messaging already set from validate method
246
                $form->sessionMessage($foundError['message'], $foundError['messageType']);
247
            } else {
248
                // fallback to custom message set in CMS or default message if none set
249
                $form->sessionError($this->getErrorMessage()->HTML());
250
            }
251
        }
252
    }
253
254
    public function getFieldValidationOptions()
255
    {
256
        return FieldList::create();
257
    }
258
259
    public function getRequired()
260
    {
261
        return false;
262
    }
263
264
    public function getIcon()
265
    {
266
        return 'spamprotection/images/' . strtolower($this->class) . '.png';
267
    }
268
269
    public function showInReports()
270
    {
271
        return false;
272
    }
273
}
274