Completed
Pull Request — master (#13)
by Nathan
12:53 queued 40s
created

HoneypotField::createHoneypotField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
ccs 0
cts 0
cp 0
rs 9.4285
cc 1
eloc 9
nc 1
nop 0
crap 2
1
<?php namespace StudioBonito\SilverStripe\SpamProtection\Honeypot\FormField;
2
3
use SilverStripe\View\HTML;
4
use SilverStripe\Core\Config\Config;
5
use SilverStripe\Forms\TextField;
6
7
class HoneypotField extends TextField
8
{
9
    /**
10
     * The number of seconds before you can submit a valid request.
11
     *
12
     * @var int
13
     * @config
14
     */
15
    private static $time_limit = 5;
0 ignored issues
show
Unused Code introduced by
The property $time_limit 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...
16
17
    /**
18
     * Reject the field if the honeypot has been filled or if the form has been submitted to quickly.
19
     *
20
     * @param $validator
21
     *
22 6
     * @return bool
23
     */
24 6
    public function validate($validator)
25
    {
26 6
        $timeLimit = $this->config()->time_limit;
27
28 6
        $timestamp = $this->getForm()->getController()->getRequest()->postVar($this->getName() . '_Timestamp');
29 3
30 3
        if (!empty($this->value) || ($timeLimit > 0 && ($timestamp + $timeLimit) > time())) {
31 3
            $validator->validationError(
32 3
                $this->name,
33
                _t(
34 3
                    'HoneypotField.SPAM',
35
                    'Your submission has been rejected because it was treated as spam.'
36 3
                ),
37
                'error'
38 3
            );
39
40
            return false;
41 3
        }
42
43
        return true;
44
    }
45
46
    /**
47
     * Since this isn't a hidden field, the title will continue to show in the form.
48
     * This prevents that from happening, since a hidden field will not show the validation message.
49
     *
50
     * @codeCoverageIgnore
51
     *
52
     * @return string
53
     */
54
    public function Title()
55
    {
56
        return '';
57
    }
58
59
    /**
60
     * Override the Type to remove the class namespace.
61
     *
62
     * @codeCoverageIgnore
63
     *
64
     * @return string
65
     */
66
    public function Type()
67
    {
68
        return 'honeypotspamprotector';
69
    }
70
71
    /**
72
     * Override the Field to add the Captcha and Timestamp fields.
73
     *
74
     * @codeCoverageIgnore
75
     *
76
     * @param array $properties
77
     *
78
     * @return string
79
     */
80
    public function Field($properties = array())
81
    {
82
        return $this->createHoneypotField() . $this->createTimestampField();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->createHone...createTimestampField(); (string) is incompatible with the return type of the parent method SilverStripe\Forms\FormField::Field of type SilverStripe\ORM\FieldType\DBHTMLText.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
83
    }
84
85
    /**
86
     * Create the Captcha Field.
87
     *
88
     * @codeCoverageIgnore
89
     *
90
     * @return string
91
     */
92
    protected function createHoneypotField()
93
    {
94
        return HTML::createTag(
95
            'input',
96
            array(
97
                'type'  => 'text',
98
                'id'    => $this->ID(),
99
                'name'  => $this->getName(),
100
                'value' => $this->Value(),
101
                'style' => $this->getFieldStyle(),
102
            )
103
        );
104
    }
105
106
    /**
107
     * Create the Timestamp Field.
108
     *
109
     * @codeCoverageIgnore
110
     *
111
     * @return string
112
     */
113
    protected function createTimestampField()
114
    {
115
        return HTML::createTag(
116
            'input',
117
            array(
118
                'type'  => 'text',
119
                'id'    => $this->ID() . '_Timestamp',
120
                'name'  => $this->getName() . '_Timestamp',
121
                'value' => time(),
122
                'style' => $this->getFieldStyle(),
123
            )
124
        );
125
    }
126
    
127
    /**
128
     * Return a configured style rule for the fields, if none is configured use a default display:none rule
129
     *
130
     * @codeCoverageIgnore
131
     *
132
     * @return string
133
     */
134
    public function getFieldStyle()
135
    {
136
        $default_css_rule = 'display:none!important';
137
        $css_rule = Config::inst()->get(__CLASS__, 'field_style_rule');
138
        if (!$css_rule) {
139
            return $default_css_rule;
140
        } else {
141
            return $css_rule;
142
        }
143
    }
144
}
145