Completed
Push — master ( ef3e6d...5f8d2a )
by Robbie
06:20
created

getFieldConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * Editable Spam Protecter Field. Used with the User Defined Forms module (if
5
 * installed) to allow the user to have captcha fields with their custom forms
6
 *
7
 * @package spamprotection
8
 */
9
if (class_exists('EditableFormField')) {
10
    class EditableSpamProtectionField extends EditableFormField
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
11
    {
12
        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...
13
14
        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...
15
        /**
16
         * Fields to include spam detection for
17
         *
18
         * @var array
19
         * @config
20
         */
21
        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...
22
            'EditableEmailField',
23
            'EditableTextField',
24
            'EditableNumericField'
25
        );
26
27
        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...
28
            'SpamFieldSettings' => 'Text'
29
        );
30
31
        /**
32
         * @var FormField
33
         */
34
        protected $formField = null;
35
36
        public function getFormField()
37
        {
38
            if ($this->formField) {
39
                return $this->formField;
40
            }
41
42
            // Get protector
43
            $protector = FormSpamProtectionExtension::get_protector();
44
            if (!$protector) {
45
                return false;
46
            }
47
48
            // Extract saved field mappings and update this field.
49
            $fieldMapping = array();
50
            foreach ($this->getCandidateFields() as $otherField) {
51
                $mapSetting = "Map-{$otherField->Name}";
52
                $spamField = $this->spamMapValue($mapSetting);
53
                $fieldMapping[$otherField->Name] = $spamField;
54
            }
55
            $protector->setFieldMapping($fieldMapping);
56
57
            // Generate field
58
            return $protector->getFormField($this->Name, $this->Title, null);
59
        }
60
61
        /**
62
         * @param FormField $field
63
         * @return self
64
         */
65
        public function setFormField(FormField $field)
66
        {
67
            $this->formField = $field;
68
69
            return $this;
70
        }
71
72
        /**
73
         * Gets the list of all candidate spam detectable fields on this field's form
74
         *
75
         * @return DataList
76
         */
77
        protected function getCandidateFields()
78
        {
79
80
            // Get list of all configured classes available for spam detection
81
            $types = self::config()->check_fields;
82
            $typesInherit = array();
83
            foreach ($types as $type) {
84
                $subTypes = ClassInfo::subclassesFor($type);
85
                $typesInherit = array_merge($typesInherit, $subTypes);
86
            }
87
88
            // Get all candidates of the above types
89
            return $this
90
                ->Parent()
91
                ->Fields()
92
                ->filter('ClassName', $typesInherit)
93
                ->exclude('Title', ''); // Ignore this field and those without titles
94
        }
95
96
        /**
97
         * This method is in place for userforms 2.x
98
         *
99
         * @deprecated 3.0 Please use {@link getCMSFields()} instead
100
         */
101
        public function getFieldConfiguration()
102
        {
103
            return $this->getCMSFields();
104
        }
105
106
        /**
107
         * Write the spam field mapping values to a serialised DB field
108
         *
109
         * {@inheritDoc}
110
         */
111
        public function onBeforeWrite()
112
        {
113
            $fieldMap = Convert::json2array($this->SpamFieldSettings);
114
            if (empty($fieldMap)) {
115
                $fieldMap = array();
116
            }
117
118
            foreach ($this->record as $key => $value) {
119
                if (substr($key, 0, 8) === 'spammap-') {
120
                    $fieldMap[substr($key, 8)] = $value;
121
                }
122
            }
123
            $this->setField('SpamFieldSettings', Convert::raw2json($fieldMap));
124
125
            return parent::onBeforeWrite();
126
        }
127
128
        /**
129
         * Used in userforms 3.x and above
130
         *
131
         * {@inheritDoc}
132
         */
133
        public function getCMSFields()
134
        {
135
            /** @var FieldList $fields */
136
            $fields = parent::getCMSFields();
137
138
            // Get protector
139
            $protector = FormSpamProtectionExtension::get_protector();
140
            if (!$protector) {
141
                return $fields;
142
            }
143
144
            if ($this->Parent()->Fields() instanceof UnsavedRelationList) {
145
                return $fields;
146
            }
147
148
            // Each other text field in this group can be assigned a field mapping
149
            $mapGroup = FieldGroup::create()
150
                ->setTitle(_t('EditableSpamProtectionField.SPAMFIELDMAPPING', 'Spam Field Mapping'))
151
                ->setName('SpamFieldMapping')
152
                ->setDescription(_t(
153
                    'EditableSpamProtectionField.SPAMFIELDMAPPINGDESCRIPTION',
154
                    'Select the form fields that correspond to any relevant spam protection identifiers'
155
                ));
156
157
            // Generate field specific settings
158
            $mappableFields = Config::inst()->get('FormSpamProtectionExtension', 'mappable_fields');
159
            $mappableFieldsMerged = array_combine($mappableFields, $mappableFields);
160
            foreach ($this->getCandidateFields() as $otherField) {
161
                $mapSetting = "Map-{$otherField->Name}";
162
                $fieldOption = DropdownField::create(
163
                    'spammap-' . $mapSetting,
164
                    $otherField->Title,
165
                    $mappableFieldsMerged,
166
                    $this->spamMapValue($mapSetting)
167
                )->setEmptyString('');
168
                $mapGroup->push($fieldOption);
169
            }
170
            $fields->addFieldToTab('Root.Main', $mapGroup);
171
172
            return $fields;
173
        }
174
175
        /**
176
         * Try to retrieve a value for the given spam field map name from the serialised data
177
         *
178
         * @param string $mapSetting
179
         * @return string
180
         */
181
        public function spamMapValue($mapSetting)
182
        {
183
            $map = Convert::json2array($this->SpamFieldSettings);
184
            if (empty($map)) {
185
                $map = array();
186
            }
187
188
            if (array_key_exists($mapSetting, $map)) {
189
                return $map[$mapSetting];
190
            }
191
            return '';
192
        }
193
194
        /**
195
         * Using custom validateField method
196
         * as Spam Protection Field implementations may have their own error messages
197
         * and may not be based on the field being required, e.g. Honeypot Field
198
         *
199
         * @param array $data
200
         * @param Form $form
201
         * @return void
202
         */
203
        public function validateField($data, $form)
204
        {
205
            $formField = $this->getFormField();
206
            $formField->setForm($form);
207
208
            if (isset($data[$this->Name])) {
209
                $formField->setValue($data[$this->Name]);
210
            }
211
212
            $validator = $form->getValidator();
213
            if (!$formField->validate($validator)) {
0 ignored issues
show
Bug introduced by
It seems like $validator defined by $form->getValidator() on line 212 can be null; however, FormField::validate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
214
                $errors = $validator->getErrors();
215
                $foundError = false;
216
217
                // field validate implementation may not add error to validator
218
                if (count($errors) > 0) {
219
                    // check if error already added from fields' validate method
220
                    foreach ($errors as $error) {
221
                        if ($error['fieldName'] == $this->Name) {
222
                            $foundError = $error;
223
                            break;
224
                        }
225
                    }
226
                }
227
228
                if ($foundError !== false) {
229
                    // use error messaging already set from validate method
230
                    $form->addErrorMessage($this->Name, $foundError['message'], $foundError['messageType'], false);
231
                } else {
232
                    // fallback to custom message set in CMS or default message if none set
233
                    $form->addErrorMessage($this->Name, $this->getErrorMessage()->HTML(), 'error', false);
234
                }
235
            }
236
        }
237
238
        public function getFieldValidationOptions()
239
        {
240
            return new FieldList();
241
        }
242
243
        public function getRequired()
244
        {
245
            return false;
246
        }
247
248
        public function getIcon()
249
        {
250
            return 'spamprotection/images/' . strtolower($this->class) . '.png';
251
        }
252
253
        public function showInReports()
254
        {
255
            return false;
256
        }
257
    }
258
}
259