CommentForm   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 276
Duplicated Lines 0 %

Importance

Changes 7
Bugs 1 Features 0
Metric Value
eloc 147
c 7
b 1
f 0
dl 0
loc 276
rs 9.6
wmc 35

3 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 136 15
F doPostComment() 0 111 19
A doPreviewComment() 0 5 1
1
<?php
2
3
namespace SilverStripe\Comments\Forms;
4
5
use SilverStripe\Comments\Controllers\CommentingController;
6
use SilverStripe\Comments\Model\Comment;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Control\HTTPResponse;
9
use SilverStripe\Core\Convert;
10
use SilverStripe\Forms\CompositeField;
11
use SilverStripe\Forms\EmailField;
12
use SilverStripe\Forms\FieldList;
13
use SilverStripe\Forms\Form;
14
use SilverStripe\Forms\FormAction;
15
use SilverStripe\Forms\HiddenField;
16
use SilverStripe\Forms\ReadonlyField;
17
use SilverStripe\Forms\RequiredFields;
18
use SilverStripe\Forms\TextareaField;
19
use SilverStripe\Forms\TextField;
20
use SilverStripe\Security\Security;
21
22
class CommentForm extends Form
23
{
24
    /**
25
     * @param string $name
26
     * @param CommentingController $controller
27
     */
28
    public function __construct($name, CommentingController $controller)
29
    {
30
        $usePreview = $controller->getOption('use_preview');
31
        $nameRequired = _t('CommentInterface.YOURNAME_MESSAGE_REQUIRED', 'Please enter your name');
32
        $emailRequired = _t('CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED', 'Please enter your email address');
33
        $emailInvalid = _t('CommentInterface.EMAILADDRESS_MESSAGE_EMAIL', 'Please enter a valid email address');
34
        $urlInvalid = _t('CommentInterface.COMMENT_MESSAGE_URL', 'Please enter a valid URL');
35
        $commentRequired = _t('CommentInterface.COMMENT_MESSAGE_REQUIRED', 'Please enter your comment');
36
37
        $fields = FieldList::create(
38
            $dataFields = CompositeField::create(
39
                // Name
40
                $a = TextField::create('Name', _t('CommentInterface.YOURNAME', 'Your name'))
41
                    ->setCustomValidationMessage($nameRequired)
42
                    ->setAttribute('data-msg-required', $nameRequired),
43
                // Email
44
                EmailField::create(
45
                    'Email',
46
                    _t(
47
                        'SilverStripe\\Comments\\Controllers\\CommentingController.EMAILADDRESS',
48
                        'Your email address (will not be published)'
49
                    )
50
                )
51
                    ->setCustomValidationMessage($emailRequired)
52
                    ->setAttribute('data-msg-required', $emailRequired)
53
                    ->setAttribute('data-msg-email', $emailInvalid)
54
                    ->setAttribute('data-rule-email', true),
55
                // Url
56
                TextField::create('URL', _t(
57
                    'SilverStripe\\Comments\\Controllers\\CommentingController.WEBSITEURL',
58
                    'Your website URL'
59
                ))
60
                    ->setAttribute('data-msg-url', $urlInvalid)
61
                    ->setAttribute('data-rule-url', true),
62
                // Comment
63
                TextareaField::create('Comment', _t(
64
                    'SilverStripe\\Comments\\Controllers\\CommentingController.COMMENTS',
65
                    'Comments'
66
                ))
67
                    ->setCustomValidationMessage($commentRequired)
68
                    ->setAttribute('data-msg-required', $commentRequired)
69
            ),
70
            HiddenField::create('ParentID'),
71
            HiddenField::create('ParentClassName'),
72
            HiddenField::create('ReturnURL'),
73
            HiddenField::create('ParentCommentID')
74
        );
75
76
        // Preview formatted comment. Makes most sense when shortcodes or
77
        // limited HTML is allowed. Populated by JS/Ajax.
78
        if ($usePreview) {
79
            $fields->insertAfter(
80
                ReadonlyField::create('PreviewComment', _t('CommentInterface.PREVIEWLABEL', 'Preview'))
81
                    ->setAttribute('style', 'display: none'), // enable through JS
82
                'Comment'
83
            );
84
        }
85
86
        $dataFields->addExtraClass('data-fields');
87
88
        // save actions
89
        $actions = FieldList::create(
90
            $postAction = new FormAction('doPostComment', _t('CommentInterface.POST', 'Post'))
91
        );
92
93
        if ($usePreview) {
94
            $actions->push(
95
                FormAction::create('doPreviewComment', _t('CommentInterface.PREVIEW', 'Preview'))
96
                    ->addExtraClass('action-minor')
97
                    ->setAttribute('style', 'display: none') // enable through JS
98
            );
99
        }
100
101
        $required = RequiredFields::create(
102
            $controller->config()->required_fields
103
        );
104
105
        parent::__construct($controller, $name, $fields, $actions, $required);
106
107
108
        // if the record exists load the extra required data
109
        if ($record = $controller->getOwnerRecord()) {
110
            // Load member data
111
            $member = Security::getCurrentUser();
112
            if (($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $member) {
113
                $fields = $this->Fields();
114
115
                $fields->removeByName('Name');
116
                $fields->removeByName('Email');
117
                $fields->insertBefore(
118
                    ReadonlyField::create(
119
                        'NameView',
120
                        _t('CommentInterface.YOURNAME', 'Your name'),
121
                        $member->getName()
122
                    ),
123
                    'URL'
0 ignored issues
show
Bug introduced by
'URL' of type string is incompatible with the type SilverStripe\Forms\FormField expected by parameter $item of SilverStripe\Forms\FieldList::insertBefore(). ( Ignorable by Annotation )

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

123
                    /** @scrutinizer ignore-type */ 'URL'
Loading history...
124
                );
125
                $fields->push(HiddenField::create('Name', '', $member->getName()));
126
                $fields->push(HiddenField::create('Email', '', $member->Email));
127
            }
128
129
            // we do not want to read a new URL when the form has already been submitted
130
            // which in here, it hasn't been.
131
            $this->loadDataFrom([
132
                'ParentID'        => $record->ID,
133
                'ReturnURL'       => $controller->getRequest()->getURL(),
134
                'ParentClassName' => $controller->getParentClass()
135
            ]);
136
        }
137
138
        // Set it so the user gets redirected back down to the form upon form fail
139
        $this->setRedirectToFormOnValidationError(true);
140
141
        // load any data from the session
142
        $data = $this->getSessionData();
143
        if (!is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
144
            return;
145
        }
146
147
        // load user data from previous form request back into form.
148
        if (array_key_exists('UserData', $data)) {
149
            $formData = json_decode($data['UserData'], true);
150
151
            $this->loadDataFrom([
152
                'Name' => isset($formData['Name']) ? $formData['Name'] : '',
153
                'URL' => isset($formData['URL']) ? $formData['URL'] : '',
154
                'Email' => isset($formData['Email']) ? $formData['Email'] : ''
155
            ]);
156
        }
157
158
        // allow previous value to fill if comment
159
        if (array_key_exists('Comment', $data)) {
160
            $prevComment = $data['Comment'];
161
162
            if ($prevComment && $prevComment != '') {
163
                $this->loadDataFrom(['Comment' => $prevComment]);
164
            }
165
        }
166
    }
167
168
    /**
169
     * @param  array $data
170
     * @param  Form $form
171
     * @return HTTPResponse
172
     */
173
    public function doPreviewComment($data, $form)
174
    {
175
        $data['IsPreview'] = 1;
176
177
        return $this->doPostComment($data, $form);
178
    }
179
180
    /**
181
     * Process which creates a {@link Comment} once a user submits a comment from this form.
182
     *
183
     * @param  array $data
184
     * @param  Form $form
185
     * @return HTTPResponse
186
     */
187
    public function doPostComment($data, $form)
188
    {
189
        // Load class and parent from data
190
        if (isset($data['ParentClassName'])) {
191
            $this->controller->setParentClass($data['ParentClassName']);
192
        }
193
        if (isset($data['ParentID']) && ($class = $this->controller->getParentClass())) {
194
            $this->controller->setOwnerRecord($class::get()->byID($data['ParentID']));
195
        }
196
        if (!$this->controller->getOwnerRecord()) {
197
            return $this->getRequestHandler()->httpError(404);
198
        }
199
200
        // cache users data
201
        $form->setSessionData([
202
            'UserData' => json_encode($data),
203
            'Comment' =>  $data['Comment']
204
        ]);
205
206
        // extend hook to allow extensions. Also see onAfterPostComment
207
        $this->controller->extend('onBeforePostComment', $form);
208
209
        // If commenting can only be done by logged in users, make sure the user is logged in
210
        if (!$this->controller->getOwnerRecord()->canPostComment()) {
211
            return Security::permissionFailure(
212
                $this->controller,
213
                _t(
214
                    'SilverStripe\\Comments\\Controllers\\CommentingController.PERMISSIONFAILURE',
215
                    "You're not able to post comments to this page. Please ensure you are logged in and have an "
216
                    . 'appropriate permission level.'
217
                )
218
            );
219
        }
220
221
        if ($member = Security::getCurrentUser()) {
222
            $form->Fields()->push(HiddenField::create('AuthorID', 'Author ID', $member->ID));
223
        }
224
225
        // What kind of moderation is required?
226
        switch ($this->controller->getOwnerRecord()->ModerationRequired) {
227
            case 'Required':
228
                $requireModeration = true;
229
                break;
230
            case 'NonMembersOnly':
231
                $requireModeration = empty($member);
232
                break;
233
            case 'None':
234
            default:
235
                $requireModeration = false;
236
                break;
237
        }
238
239
        $comment = Comment::create();
240
        $form->saveInto($comment);
241
242
        $comment->ParentID = $data['ParentID'];
243
        $comment->ParentClass = $data['ParentClassName'];
244
245
        $comment->AllowHtml = $this->controller->getOption('html_allowed');
246
        $comment->Moderated = !$requireModeration;
247
248
        // Save into DB, or call pre-save hooks to give accurate preview
249
        $usePreview = $this->controller->getOption('use_preview');
250
        $isPreview = $usePreview && !empty($data['IsPreview']);
251
        if ($isPreview) {
252
            $comment->extend('onBeforeWrite');
253
        } else {
254
            $comment->write();
255
256
            // extend hook to allow extensions. Also see onBeforePostComment
257
            $this->controller->extend('onAfterPostComment', $comment);
258
        }
259
260
        // we want to show a notification if comments are moderated
261
        if ($requireModeration && !$comment->IsSpam) {
262
            $this->getRequest()->getSession()->set('CommentsModerated', 1);
263
        }
264
265
        // clear the users comment since the comment was successful.
266
        if ($comment->exists()) {
267
            // Remove the comment data as it's been saved already.
268
            unset($data['Comment']);
269
        }
270
271
        // cache users data (name, email, etc to prepopulate on other forms).
272
        $form->setSessionData([
273
            'UserData' => json_encode($data),
274
        ]);
275
276
        // Find parent link
277
        if (!empty($data['ReturnURL'])) {
278
            $url = $data['ReturnURL'];
279
        } elseif ($parent = $comment->Parent()) {
280
            $url = $parent->Link();
281
        } else {
282
            return $this->controller->redirectBack();
283
        }
284
285
        // Given a redirect page exists, attempt to link to the correct anchor
286
        if ($comment->IsSpam) {
287
            // Link to the form with the error message contained
288
            $hash = $form->FormName();
289
        } elseif (!$comment->Moderated) {
290
            // Display the "awaiting moderation" text
291
            $hash = 'moderated';
292
        } else {
293
            // Link to the moderated, non-spam comment
294
            $hash = $comment->Permalink();
295
        }
296
297
        return $this->controller->redirect(Controller::join_links($url, "#{$hash}"));
298
    }
299
}
300