Completed
Push — master ( 8d1cc4...078b0f )
by Damian
12:41 queued 06:19
created

EditableSpamProtectionField::validateField()   C

Complexity

Conditions 7
Paths 18

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 7
eloc 17
nc 18
nop 2
dl 0
loc 33
rs 6.7272
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
        /**
28
         * @var FormField
29
         */
30
        protected $formField = null;
31
32
        public function getFormField()
33
        {
34
            if ($this->formField) {
35
                return $this->formField;
36
            }
37
38
            // Get protector
39
            $protector = FormSpamProtectionExtension::get_protector();
40
            if (!$protector) {
41
                return false;
42
            }
43
44
            // Extract saved field mappings and update this field.
45
            $fieldMapping = array();
46
            foreach ($this->getCandidateFields() as $otherField) {
47
                $mapSetting = "Map-{$otherField->Name}";
48
                $spamField = $this->getSetting($mapSetting);
49
                $fieldMapping[$otherField->Name] = $spamField;
50
            }
51
            $protector->setFieldMapping($fieldMapping);
52
53
            // Generate field
54
            return $protector->getFormField($this->Name, $this->Title, null);
55
        }
56
57
        /**
58
         * @param FormField $field
59
         * @return self
60
         */
61
        public function setFormField(FormField $field)
62
        {
63
            $this->formField = $field;
64
65
            return $this;
66
        }
67
68
        /**
69
         * Gets the list of all candidate spam detectable fields on this field's form
70
         *
71
         * @return DataList
72
         */
73
        protected function getCandidateFields()
74
        {
75
76
            // Get list of all configured classes available for spam detection
77
            $types = self::config()->check_fields;
78
            $typesInherit = array();
79
            foreach ($types as $type) {
80
                $subTypes = ClassInfo::subclassesFor($type);
81
                $typesInherit = array_merge($typesInherit, $subTypes);
82
            }
83
84
            // Get all candidates of the above types
85
            return $this
86
                ->Parent()
87
                ->Fields()
88
                ->filter('ClassName', $typesInherit)
89
                ->exclude('Title', ''); // Ignore this field and those without titles
90
        }
91
92
        public function getFieldConfiguration()
93
        {
94
            $fields = parent::getFieldConfiguration();
95
96
            // Get protector
97
            $protector = FormSpamProtectionExtension::get_protector();
98
            if (!$protector) {
99
                return $fields;
100
            }
101
102
            if ($this->Parent()->Fields() instanceof UnsavedRelationList) {
103
                return $fields;
104
            }
105
106
            // Each other text field in this group can be assigned a field mapping
107
            $mapGroup = FieldGroup::create(_t(
108
                'EditableSpamProtectionField.SPAMFIELDMAPPING',
109
                'Spam Field Mapping'
110
            ))->setDescription(_t(
111
                'EditableSpamProtectionField.SPAMFIELDMAPPINGDESCRIPTION',
112
                'Select the form fields that correspond to any relevant spam protection identifiers'
113
            ));
114
115
            // Generate field specific settings
116
            $mappableFields = Config::inst()->get('FormSpamProtectionExtension', 'mappable_fields');
117
            $mappableFieldsMerged = array_combine($mappableFields, $mappableFields);
118
            foreach ($this->getCandidateFields() as $otherField) {
119
                $mapSetting = "Map-{$otherField->Name}";
120
                $fieldOption = DropdownField::create(
121
                    $this->getSettingName($mapSetting),
122
                    $otherField->Title,
123
                    $mappableFieldsMerged,
124
                    $this->getSetting($mapSetting)
125
                )->setEmptyString('');
126
                $mapGroup->push($fieldOption);
127
            }
128
            $fields->insertBefore($mapGroup, $this->getSettingName('ExtraClass'));
129
130
            return $fields;
131
        }
132
133
        /**
134
         * Using custom validateField method
135
         * as Spam Protection Field implementations may have their own error messages
136
         * and may not be based on the field being required, e.g. Honeypot Field
137
         * 
138
         * @param array $data
139
         * @param Form $form
140
         * @return void
141
         */
142
        public function validateField($data, $form) 
143
        {
144
            $formField = $this->getFormField();
145
            
146
            if (isset($data[$this->Name])) {
147
                $formField->setValue($data[$this->Name]);
148
            }
149
150
            $validator = $form->getValidator();
151
            if (!$formField->validate($validator)) {
0 ignored issues
show
Bug introduced by
It seems like $validator defined by $form->getValidator() on line 150 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...
152
                $errors = $validator->getErrors();
153
                $foundError = false;
154
155
                // field validate implementation may not add error to validator
156
                if (count($errors) > 0) {
157
                    // check if error already added from fields' validate method
158
                    foreach ($errors as $error) {
159
                        if ($error['fieldName'] == $this->Name) {
160
                            $foundError = $error;
161
                            break;
162
                        }
163
                    }
164
                }
165
166
                if ($foundError !== false) {
167
                    // use error messaging already set from validate method
168
                    $form->addErrorMessage($this->Name, $foundError['message'], $foundError['messageType'], false);
169
                } else {
170
                    // fallback to custom message set in CMS or default message if none set
171
                    $form->addErrorMessage($this->Name, $this->getErrorMessage()->HTML(), 'error', false);
172
                }
173
            }
174
        }
175
176
        public function getFieldValidationOptions()
177
        {
178
            return new FieldList();
179
        }
180
181
        public function getRequired()
182
        {
183
            return false;
184
        }
185
186
        public function getIcon()
187
        {
188
            return 'spamprotection/images/' . strtolower($this->class) . '.png';
189
        }
190
191
        public function showInReports()
192
        {
193
            return false;
194
        }
195
    }
196
}
197