Completed
Push — master ( 9dab44...8bd79e )
by Robbie
02:00
created

src/Forms/CommentForm.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SilverStripe\Comments\Forms;
4
5
use SilverStripe\Forms\CompositeField;
6
use SilverStripe\Forms\EmailField;
7
use SilverStripe\Forms\FieldList;
8
use SilverStripe\Forms\Form;
9
use SilverStripe\Forms\FormAction;
10
use SilverStripe\Forms\HiddenField;
11
use SilverStripe\Forms\ReadonlyField;
12
use SilverStripe\Forms\RequiredFields;
13
use SilverStripe\Forms\TextareaField;
14
use SilverStripe\Forms\TextField;
15
use SilverStripe\Security\Member;
16
use SilverStripe\Control\Cookie;
17
use SilverStripe\Core\Convert;
18
use SilverStripe\Security\Security;
19
use SilverStripe\Comments\Model\Comment;
20
use SilverStripe\Control\Controller;
21
use SilverStripe\Comments\Controllers\CommentingController;
22
use SilverStripe\Core\Config\Config;
23
24
class CommentForm extends Form
25
{
26
    /**
27
     * @param string $name
28
     * @param CommentingController $controller
29
     */
30
    public function __construct($name, CommentingController $controller)
31
    {
32
        $usePreview = $controller->getOption('use_preview');
33
        $nameRequired = _t('CommentInterface.YOURNAME_MESSAGE_REQUIRED', 'Please enter your name');
34
        $emailRequired = _t('CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED', 'Please enter your email address');
35
        $emailInvalid = _t('CommentInterface.EMAILADDRESS_MESSAGE_EMAIL', 'Please enter a valid email address');
36
        $urlInvalid = _t('CommentInterface.COMMENT_MESSAGE_URL', 'Please enter a valid URL');
37
        $commentRequired = _t('CommentInterface.COMMENT_MESSAGE_REQUIRED', 'Please enter your comment');
38
39
        $fields = FieldList::create(
40
            $dataFields = CompositeField::create(
41
                // Name
42
                $a = TextField::create('Name', _t('CommentInterface.YOURNAME', 'Your name'))
43
                    ->setCustomValidationMessage($nameRequired)
44
                    ->setAttribute('data-msg-required', $nameRequired),
45
                // Email
46
                EmailField::create(
47
                    'Email',
48
                    _t('SilverStripe\\Comments\\Controllers\\CommentingController.EMAILADDRESS', 'Your email address (will not be published)')
49
                )
50
                    ->setCustomValidationMessage($emailRequired)
51
                    ->setAttribute('data-msg-required', $emailRequired)
52
                    ->setAttribute('data-msg-email', $emailInvalid)
53
                    ->setAttribute('data-rule-email', true),
54
                // Url
55
                TextField::create('URL', _t('SilverStripe\\Comments\\Controllers\\CommentingController.WEBSITEURL', 'Your website URL'))
56
                    ->setAttribute('data-msg-url', $urlInvalid)
57
                    ->setAttribute('data-rule-url', true),
58
                // Comment
59
                TextareaField::create('Comment', _t('SilverStripe\\Comments\\Controllers\\CommentingController.COMMENTS', 'Comments'))
60
                    ->setCustomValidationMessage($commentRequired)
61
                    ->setAttribute('data-msg-required', $commentRequired)
62
            ),
63
            HiddenField::create('ParentID'),
64
            HiddenField::create('ParentClassName'),
65
            HiddenField::create('ReturnURL'),
66
            HiddenField::create('ParentCommentID')
67
        );
68
69
        // Preview formatted comment. Makes most sense when shortcodes or
70
        // limited HTML is allowed. Populated by JS/Ajax.
71
        if ($usePreview) {
72
            $fields->insertAfter(
73
                ReadonlyField::create('PreviewComment', _t('CommentInterface.PREVIEWLABEL', 'Preview'))
74
                    ->setAttribute('style', 'display: none'), // enable through JS
75
                'Comment'
76
            );
77
        }
78
79
        $dataFields->addExtraClass('data-fields');
80
81
        // save actions
82
        $actions = FieldList::create(
83
            $postAction = new FormAction('doPostComment', _t('CommentInterface.POST', 'Post'))
84
        );
85
86
        if ($usePreview) {
87
            $actions->push(
88
                FormAction::create('doPreviewComment', _t('CommentInterface.PREVIEW', 'Preview'))
89
                    ->addExtraClass('action-minor')
90
                    ->setAttribute('style', 'display: none') // enable through JS
91
            );
92
        }
93
94
        $required = new RequiredFields(
95
            $controller->config()->required_fields
96
        );
97
98
        parent::__construct($controller, $name, $fields, $actions, $required);
99
100
101
        // if the record exists load the extra required data
102
        if ($record = $controller->getOwnerRecord()) {
103
            // Load member data
104
            $member = Member::currentUser();
105
            if (($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $member) {
106
                $fields = $this->Fields();
107
108
                $fields->removeByName('Name');
109
                $fields->removeByName('Email');
110
                $fields->insertBefore(
111
                    new ReadonlyField(
112
                        'NameView',
113
                        _t('CommentInterface.YOURNAME', 'Your name'),
114
                        $member->getName()
115
                    ),
116
                    'URL'
117
                );
118
                $fields->push(new HiddenField('Name', '', $member->getName()));
119
                $fields->push(new HiddenField('Email', '', $member->Email));
120
            }
121
122
            // we do not want to read a new URL when the form has already been submitted
123
            // which in here, it hasn't been.
124
            $this->loadDataFrom(array(
125
                'ParentID'        => $record->ID,
126
                'ReturnURL'       => $controller->getRequest()->getURL(),
127
                'ParentClassName' => $controller->getParentClass()
128
            ));
129
        }
130
131
        // Set it so the user gets redirected back down to the form upon form fail
132
        $this->setRedirectToFormOnValidationError(true);
133
134
        // load any data from the cookies
135
        if ($data = Cookie::get('CommentsForm_UserData')) {
136
            $data = Convert::json2array($data);
137
138
            $this->loadDataFrom(array(
139
                'Name'  => isset($data['Name']) ? $data['Name'] : '',
140
                'URL'   => isset($data['URL']) ? $data['URL'] : '',
141
                'Email' => isset($data['Email']) ? $data['Email'] : ''
142
            ));
143
144
            // allow previous value to fill if comment not stored in cookie (i.e. validation error)
145
            $prevComment = Cookie::get('CommentsForm_Comment');
146
147
            if ($prevComment && $prevComment != '') {
148
                $this->loadDataFrom(array('Comment' => $prevComment));
149
            }
150
        }
151
    }
152
153
    /**
154
     * @param  array $data
155
     * @param  Form $form
156
     * @return HTTPResponse
0 ignored issues
show
Should the return type not be \SilverStripe\Control\HTTPResponse?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
157
     */
158
    public function doPreviewComment($data, $form)
159
    {
160
        $data['IsPreview'] = 1;
161
162
        return $this->doPostComment($data, $form);
163
    }
164
165
    /**
166
     * Process which creates a {@link Comment} once a user submits a comment from this form.
167
     *
168
     * @param  array $data
169
     * @param  Form $form
170
     * @return HTTPResponse
0 ignored issues
show
Should the return type not be \SilverStripe\Control\HTTPResponse?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
171
     */
172
    public function doPostComment($data, $form)
173
    {
174
        // Load class and parent from data
175
        if (isset($data['ParentClassName'])) {
176
            $this->controller->setParentClass($data['ParentClassName']);
177
        }
178
        if (isset($data['ParentID']) && ($class = $this->controller->getParentClass())) {
179
            $this->controller->setOwnerRecord($class::get()->byID($data['ParentID']));
180
        }
181
        if (!$this->controller->getOwnerRecord()) {
182
            return $this->getRequestHandler()->httpError(404);
183
        }
184
185
        // cache users data
186
        Cookie::set('CommentsForm_UserData', Convert::raw2json($data));
187
        Cookie::set('CommentsForm_Comment', $data['Comment']);
188
189
        // extend hook to allow extensions. Also see onAfterPostComment
190
        $this->controller->extend('onBeforePostComment', $form);
191
192
        // If commenting can only be done by logged in users, make sure the user is logged in
193
        if (!$this->controller->getOwnerRecord()->canPostComment()) {
194
            return Security::permissionFailure(
195
                $this,
196
                _t(
197
                    'SilverStripe\\Comments\\Controllers\\CommentingController.PERMISSIONFAILURE',
198
                    "You're not able to post comments to this page. Please ensure you are logged in and have an "
199
                    . 'appropriate permission level.'
200
                )
201
            );
202
        }
203
204
        if ($member = Security::getCurrentUser()) {
205
            $form->Fields()->push(new HiddenField('AuthorID', 'Author ID', $member->ID));
206
        }
207
208
        // What kind of moderation is required?
209
        switch ($this->controller->getOwnerRecord()->ModerationRequired) {
210
            case 'Required':
211
                $requireModeration = true;
212
                break;
213
            case 'NonMembersOnly':
214
                $requireModeration = empty($member);
215
                break;
216
            case 'None':
217
            default:
218
                $requireModeration = false;
219
                break;
220
        }
221
222
        $comment = Comment::create();
223
        $form->saveInto($comment);
224
225
        $comment->ParentID = $data['ParentID'];
226
        $comment->ParentClass = $data['ParentClassName'];
227
228
        $comment->AllowHtml = $this->controller->getOption('html_allowed');
229
        $comment->Moderated = !$requireModeration;
230
231
        // Save into DB, or call pre-save hooks to give accurate preview
232
        $usePreview = $this->controller->getOption('use_preview');
233
        $isPreview = $usePreview && !empty($data['IsPreview']);
234
        if ($isPreview) {
235
            $comment->extend('onBeforeWrite');
236
        } else {
237
            $comment->write();
238
239
            // extend hook to allow extensions. Also see onBeforePostComment
240
            $this->controller->extend('onAfterPostComment', $comment);
241
        }
242
243
        // we want to show a notification if comments are moderated
244
        if ($requireModeration && !$comment->IsSpam) {
245
            $this->getRequest()->getSession()->set('CommentsModerated', 1);
246
        }
247
248
        // clear the users comment since it passed validation
249
        Cookie::set('CommentsForm_Comment', false);
250
251
        // Find parent link
252
        if (!empty($data['ReturnURL'])) {
253
            $url = $data['ReturnURL'];
254
        } elseif ($parent = $comment->Parent()) {
255
            $url = $parent->Link();
256
        } else {
257
            return $this->controller->redirectBack();
258
        }
259
260
        // Given a redirect page exists, attempt to link to the correct anchor
261
        if ($comment->IsSpam) {
262
            // Link to the form with the error message contained
263
            $hash = $form->FormName();
264
        } elseif (!$comment->Moderated) {
265
            // Display the "awaiting moderation" text
266
            $hash = 'moderated';
267
        } else {
268
            // Link to the moderated, non-spam comment
269
            $hash = $comment->Permalink();
270
        }
271
272
        return $this->controller->redirect(Controller::join_links($url, "#{$hash}"));
273
    }
274
}
275