These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @package comments |
||
5 | */ |
||
6 | |||
7 | class CommentingController extends Controller { |
||
8 | |||
9 | private static $allowed_actions = array( |
||
0 ignored issues
–
show
Comprehensibility
introduced
by
Loading history...
|
|||
10 | 'delete', |
||
11 | 'spam', |
||
12 | 'ham', |
||
13 | 'approve', |
||
14 | 'rss', |
||
15 | 'CommentsForm', |
||
16 | 'reply', |
||
17 | 'doPostComment', |
||
18 | 'doPreviewComment' |
||
19 | ); |
||
20 | |||
21 | private static $url_handlers = array( |
||
0 ignored issues
–
show
|
|||
22 | 'reply/$ParentCommentID//$ID/$OtherID' => 'reply', |
||
23 | ); |
||
24 | |||
25 | /** |
||
26 | * Fields required for this form |
||
27 | * |
||
28 | * @var array |
||
29 | * @config |
||
30 | */ |
||
31 | private static $required_fields = array( |
||
32 | 'Name', |
||
33 | 'Email', |
||
34 | 'Comment' |
||
35 | ); |
||
36 | |||
37 | /** |
||
38 | * Base class this commenting form is for |
||
39 | * |
||
40 | * @var string |
||
41 | */ |
||
42 | private $baseClass = ""; |
||
43 | |||
44 | /** |
||
45 | * The record this commenting form is for |
||
46 | * |
||
47 | * @var DataObject |
||
48 | */ |
||
49 | private $ownerRecord = null; |
||
50 | |||
51 | /** |
||
52 | * Parent controller record |
||
53 | * |
||
54 | * @var Controller |
||
55 | */ |
||
56 | private $ownerController = null; |
||
57 | |||
58 | /** |
||
59 | * Backup url to return to |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | protected $fallbackReturnURL = null; |
||
64 | |||
65 | /** |
||
66 | * Set the base class to use |
||
67 | * |
||
68 | * @param string $class |
||
69 | */ |
||
70 | public function setBaseClass($class) { |
||
71 | $this->baseClass = $class; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * Get the base class used |
||
76 | * |
||
77 | * @return string |
||
78 | */ |
||
79 | public function getBaseClass() { |
||
80 | return $this->baseClass; |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * Set the record this controller is working on |
||
85 | * |
||
86 | * @param DataObject $record |
||
87 | */ |
||
88 | public function setOwnerRecord($record) { |
||
89 | $this->ownerRecord = $record; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Get the record |
||
94 | * |
||
95 | * @return DataObject |
||
96 | */ |
||
97 | public function getOwnerRecord() { |
||
98 | return $this->ownerRecord; |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * Set the parent controller |
||
103 | * |
||
104 | * @param Controller $controller |
||
105 | */ |
||
106 | public function setOwnerController($controller) { |
||
107 | $this->ownerController = $controller; |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Get the parent controller |
||
112 | * |
||
113 | * @return Controller |
||
114 | */ |
||
115 | public function getOwnerController() { |
||
116 | return $this->ownerController; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Get the commenting option for the current state |
||
121 | * |
||
122 | * @param string $key |
||
123 | * @return mixed Result if the setting is available, or null otherwise |
||
124 | */ |
||
125 | public function getOption($key) { |
||
126 | // If possible use the current record |
||
127 | if($record = $this->getOwnerRecord()) { |
||
128 | return $record->getCommentsOption($key); |
||
129 | } |
||
130 | |||
131 | // Otherwise a singleton of that record |
||
132 | if($class = $this->getBaseClass()) { |
||
133 | return singleton($class)->getCommentsOption($key); |
||
134 | } |
||
135 | |||
136 | // Otherwise just use the default options |
||
137 | return singleton('CommentsExtension')->getCommentsOption($key); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Workaround for generating the link to this controller |
||
142 | * |
||
143 | * @return string |
||
144 | */ |
||
145 | public function Link($action = '', $id = '', $other = '') { |
||
146 | return Controller::join_links(Director::baseURL(), __CLASS__ , $action, $id, $other); |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * Outputs the RSS feed of comments |
||
151 | * |
||
152 | * @return HTMLText |
||
153 | */ |
||
154 | public function rss() { |
||
155 | return $this->getFeed($this->request)->outputToBrowser(); |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Return an RSSFeed of comments for a given set of comments or all |
||
160 | * comments on the website. |
||
161 | * |
||
162 | * To maintain backwards compatibility with 2.4 this supports mapping |
||
163 | * of PageComment/rss?pageid= as well as the new RSS format for comments |
||
164 | * of CommentingController/rss/{classname}/{id} |
||
165 | * |
||
166 | * @param SS_HTTPRequest |
||
167 | * |
||
168 | * @return RSSFeed |
||
169 | */ |
||
170 | public function getFeed(SS_HTTPRequest $request) { |
||
171 | $link = $this->Link('rss'); |
||
172 | $class = $request->param('ID'); |
||
173 | $id = $request->param('OtherID'); |
||
174 | |||
175 | // Support old pageid param |
||
176 | if(!$id && !$class && ($id = $request->getVar('pageid'))) { |
||
177 | $class = 'SiteTree'; |
||
178 | } |
||
179 | |||
180 | $comments = Comment::get()->filter(array( |
||
181 | 'Moderated' => 1, |
||
182 | 'IsSpam' => 0, |
||
183 | )); |
||
184 | |||
185 | // Check if class filter |
||
186 | if($class) { |
||
187 | if(!is_subclass_of($class, 'DataObject') || !$class::has_extension('CommentsExtension')) { |
||
188 | return $this->httpError(404); |
||
189 | } |
||
190 | $this->setBaseClass($class); |
||
191 | $comments = $comments->filter('BaseClass', $class); |
||
192 | $link = Controller::join_links($link, $class); |
||
193 | |||
194 | // Check if id filter |
||
195 | if($id) { |
||
196 | $comments = $comments->filter('ParentID', $id); |
||
197 | $link = Controller::join_links($link, $id); |
||
198 | $this->setOwnerRecord(DataObject::get_by_id($class, $id)); |
||
199 | } |
||
200 | } |
||
201 | |||
202 | $title = _t('CommentingController.RSSTITLE', "Comments RSS Feed"); |
||
203 | |||
204 | $comments = new PaginatedList($comments, $request); |
||
0 ignored issues
–
show
$request is of type object<SS_HTTPRequest> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
205 | $comments->setPageLength($this->getOption('comments_per_page')); |
||
206 | |||
207 | return new RSSFeed( |
||
208 | $comments, |
||
209 | $link, |
||
210 | $title, |
||
211 | $link, |
||
212 | 'Title', 'EscapedComment', 'AuthorName' |
||
213 | ); |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * Deletes a given {@link Comment} via the URL. |
||
218 | */ |
||
219 | View Code Duplication | public function delete() { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
220 | $comment = $this->getComment(); |
||
221 | if(!$comment) return $this->httpError(404); |
||
222 | if(!$comment->canDelete()) { |
||
223 | return Security::permissionFailure($this, 'You do not have permission to delete this comment'); |
||
224 | } |
||
225 | if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); |
||
226 | |||
227 | $comment->delete(); |
||
228 | |||
229 | return $this->request->isAjax() |
||
230 | ? true |
||
231 | : $this->redirectBack(); |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * Marks a given {@link Comment} as spam. Removes the comment from display |
||
236 | */ |
||
237 | View Code Duplication | public function spam() { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
238 | $comment = $this->getComment(); |
||
239 | if(!$comment) return $this->httpError(404); |
||
240 | if(!$comment->canEdit()) { |
||
241 | return Security::permissionFailure($this, 'You do not have permission to edit this comment'); |
||
242 | } |
||
243 | if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); |
||
244 | |||
245 | $comment->markSpam(); |
||
246 | return $this->renderChangedCommentState($comment); |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Marks a given {@link Comment} as ham (not spam). |
||
251 | */ |
||
252 | View Code Duplication | public function ham() { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
253 | $comment = $this->getComment(); |
||
254 | if(!$comment) return $this->httpError(404); |
||
255 | if(!$comment->canEdit()) { |
||
256 | return Security::permissionFailure($this, 'You do not have permission to edit this comment'); |
||
257 | } |
||
258 | if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); |
||
259 | |||
260 | $comment->markApproved(); |
||
261 | return $this->renderChangedCommentState($comment); |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Marks a given {@link Comment} as approved. |
||
266 | */ |
||
267 | View Code Duplication | public function approve() { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
268 | $comment = $this->getComment(); |
||
269 | if(!$comment) return $this->httpError(404); |
||
270 | if(!$comment->canEdit()) { |
||
271 | return Security::permissionFailure($this, 'You do not have permission to approve this comment'); |
||
272 | } |
||
273 | if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); |
||
274 | |||
275 | $comment->markApproved(); |
||
276 | return $this->renderChangedCommentState($comment); |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Redirect back to referer if available, ensuring that only site URLs |
||
281 | * are allowed to avoid phishing. If it's an AJAX request render the |
||
282 | * comment in it's new state |
||
283 | */ |
||
284 | private function renderChangedCommentState($comment) { |
||
285 | $referer = $this->request->getHeader('Referer'); |
||
286 | |||
287 | // Render comment using AJAX |
||
288 | if ($this->request->isAjax()) { |
||
289 | return $comment->renderWith('CommentsInterface_singlecomment'); |
||
290 | } else { |
||
291 | // Redirect to either the comment or start of the page |
||
292 | if (empty($referer)) { |
||
293 | return $this->redirectBack(); |
||
294 | } else { |
||
295 | // Redirect to the comment, but check for phishing |
||
296 | $url = $referer . '#comment-' . $comment->ID; |
||
297 | // absolute redirection URLs not located on this site may cause phishing |
||
298 | if(Director::is_site_url($url)) { |
||
299 | return $this->redirect($url); |
||
300 | } else { |
||
301 | return false; |
||
302 | } |
||
303 | } |
||
304 | } |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Returns the comment referenced in the URL (by ID). Permission checking |
||
309 | * should be done in the callee. |
||
310 | * |
||
311 | * @return Comment|false |
||
312 | */ |
||
313 | public function getComment() { |
||
314 | $id = isset($this->urlParams['ID']) ? $this->urlParams['ID'] : false; |
||
315 | |||
316 | if($id) { |
||
317 | $comment = DataObject::get_by_id('Comment', $id); |
||
318 | |||
319 | if($comment) { |
||
320 | $this->fallbackReturnURL = $comment->Link(); |
||
321 | return $comment; |
||
322 | } |
||
323 | } |
||
324 | |||
325 | return false; |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Create a reply form for a specified comment |
||
330 | * |
||
331 | * @param Comment $comment |
||
332 | */ |
||
333 | public function ReplyForm($comment) { |
||
334 | // Enables multiple forms with different names to use the same handler |
||
335 | $form = $this->CommentsForm(); |
||
336 | $form->setName('ReplyForm_'.$comment->ID); |
||
337 | $form->addExtraClass('reply-form'); |
||
338 | |||
339 | // Load parent into reply form |
||
340 | $form->loadDataFrom(array( |
||
341 | 'ParentCommentID' => $comment->ID |
||
342 | )); |
||
343 | |||
344 | // Customise action |
||
345 | $form->setFormAction($this->Link('reply', $comment->ID)); |
||
346 | |||
347 | $this->extend('updateReplyForm', $form); |
||
348 | return $form; |
||
349 | } |
||
350 | |||
351 | |||
352 | /** |
||
353 | * Request handler for reply form. |
||
354 | * This method will disambiguate multiple reply forms in the same method |
||
355 | * |
||
356 | * @param SS_HTTPRequest $request |
||
357 | */ |
||
358 | public function reply(SS_HTTPRequest $request) { |
||
359 | // Extract parent comment from reply and build this way |
||
360 | if($parentID = $request->param('ParentCommentID')) { |
||
361 | $comment = DataObject::get_by_id('Comment', $parentID, true); |
||
362 | if($comment) { |
||
363 | return $this->ReplyForm($comment); |
||
0 ignored issues
–
show
$comment of type object<DataObject> is not a sub-type of object<Comment> . It seems like you assume a child class of the class DataObject to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
364 | } |
||
365 | } |
||
366 | return $this->httpError(404); |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Post a comment form |
||
371 | * |
||
372 | * @return Form |
||
373 | */ |
||
374 | public function CommentsForm() { |
||
375 | $usePreview = $this->getOption('use_preview'); |
||
376 | |||
377 | $nameRequired = _t('CommentInterface.YOURNAME_MESSAGE_REQUIRED', 'Please enter your name'); |
||
378 | $emailRequired = _t('CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED', 'Please enter your email address'); |
||
379 | $emailInvalid = _t('CommentInterface.EMAILADDRESS_MESSAGE_EMAIL', 'Please enter a valid email address'); |
||
380 | $urlInvalid = _t('CommentInterface.COMMENT_MESSAGE_URL', 'Please enter a valid URL'); |
||
381 | $commentRequired = _t('CommentInterface.COMMENT_MESSAGE_REQUIRED', 'Please enter your comment'); |
||
382 | |||
383 | $fields = new FieldList( |
||
384 | $dataFields = new CompositeField( |
||
385 | // Name |
||
386 | TextField::create("Name", _t('CommentInterface.YOURNAME', 'Your name')) |
||
387 | ->setCustomValidationMessage($nameRequired) |
||
388 | ->setAttribute('data-msg-required', $nameRequired), |
||
389 | |||
390 | |||
391 | EmailField::create( |
||
392 | "Email", |
||
393 | _t('CommentingController.EMAILADDRESS', "Your email address (will not be published)") |
||
394 | ) |
||
395 | ->setCustomValidationMessage($emailRequired) |
||
396 | ->setAttribute('data-msg-required', $emailRequired) |
||
397 | ->setAttribute('data-msg-email', $emailInvalid) |
||
398 | ->setAttribute('data-rule-email', true), |
||
0 ignored issues
–
show
true is of type boolean , but the function expects a string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
399 | |||
400 | // Url |
||
401 | TextField::create("URL", _t('CommentingController.WEBSITEURL', "Your website URL")) |
||
402 | ->setAttribute('data-msg-url', $urlInvalid) |
||
403 | ->setAttribute('data-rule-url', true), |
||
0 ignored issues
–
show
true is of type boolean , but the function expects a string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
404 | |||
405 | // Comment |
||
406 | TextareaField::create("Comment", _t('CommentingController.COMMENTS', "Comments")) |
||
407 | ->setCustomValidationMessage($commentRequired) |
||
408 | ->setAttribute('data-msg-required', $commentRequired) |
||
409 | ), |
||
410 | HiddenField::create("ParentID"), |
||
411 | HiddenField::create("ReturnURL"), |
||
412 | HiddenField::create("ParentCommentID"), |
||
413 | HiddenField::create("BaseClass") |
||
414 | ); |
||
415 | |||
416 | // Preview formatted comment. Makes most sense when shortcodes or |
||
417 | // limited HTML is allowed. Populated by JS/Ajax. |
||
418 | if($usePreview) { |
||
419 | $fields->insertAfter( |
||
420 | ReadonlyField::create('PreviewComment', _t('CommentInterface.PREVIEWLABEL', 'Preview')) |
||
421 | ->setAttribute('style', 'display: none'), // enable through JS |
||
422 | 'Comment' |
||
0 ignored issues
–
show
'Comment' is of type string , but the function expects a object<FormField> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
423 | ); |
||
424 | } |
||
425 | |||
426 | $dataFields->addExtraClass('data-fields'); |
||
427 | |||
428 | // save actions |
||
429 | $actions = new FieldList( |
||
430 | new FormAction("doPostComment", _t('CommentInterface.POST', 'Post')) |
||
431 | ); |
||
432 | if($usePreview) { |
||
433 | $actions->push( |
||
434 | FormAction::create('doPreviewComment', _t('CommentInterface.PREVIEW', 'Preview')) |
||
435 | ->addExtraClass('action-minor') |
||
436 | ->setAttribute('style', 'display: none') // enable through JS |
||
437 | ); |
||
438 | } |
||
439 | |||
440 | // required fields for server side |
||
441 | $required = new RequiredFields($this->config()->required_fields); |
||
442 | |||
443 | // create the comment form |
||
444 | $form = new Form($this, 'CommentsForm', $fields, $actions, $required); |
||
445 | |||
446 | // if the record exists load the extra required data |
||
447 | if($record = $this->getOwnerRecord()) { |
||
448 | |||
449 | // Load member data |
||
450 | $member = Member::currentUser(); |
||
451 | if(($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $member) { |
||
452 | $fields = $form->Fields(); |
||
453 | |||
454 | $fields->removeByName('Name'); |
||
455 | $fields->removeByName('Email'); |
||
456 | $fields->insertBefore(new ReadonlyField("NameView", _t('CommentInterface.YOURNAME', 'Your name'), $member->getName()), 'URL'); |
||
0 ignored issues
–
show
'URL' is of type string , but the function expects a object<FormField> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
457 | $fields->push(new HiddenField("Name", "", $member->getName())); |
||
458 | $fields->push(new HiddenField("Email", "", $member->Email)); |
||
459 | } |
||
460 | |||
461 | // we do not want to read a new URL when the form has already been submitted |
||
462 | // which in here, it hasn't been. |
||
463 | $form->loadDataFrom(array( |
||
464 | 'ParentID' => $record->ID, |
||
465 | 'ReturnURL' => $this->request->getURL(), |
||
466 | 'BaseClass' => $this->getBaseClass() |
||
467 | )); |
||
468 | } |
||
469 | |||
470 | // Set it so the user gets redirected back down to the form upon form fail |
||
471 | $form->setRedirectToFormOnValidationError(true); |
||
472 | |||
473 | // load any data from the cookies |
||
474 | if($data = Cookie::get('CommentsForm_UserData')) { |
||
475 | $data = Convert::json2array($data); |
||
476 | |||
477 | $form->loadDataFrom(array( |
||
478 | "Name" => isset($data['Name']) ? $data['Name'] : '', |
||
479 | "URL" => isset($data['URL']) ? $data['URL'] : '', |
||
480 | "Email" => isset($data['Email']) ? $data['Email'] : '' |
||
481 | )); |
||
482 | // allow previous value to fill if comment not stored in cookie (i.e. validation error) |
||
483 | $prevComment = Cookie::get('CommentsForm_Comment'); |
||
484 | if($prevComment && $prevComment != ''){ |
||
0 ignored issues
–
show
The expression
$prevComment of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
485 | $form->loadDataFrom(array("Comment" => $prevComment)); |
||
486 | } |
||
487 | } |
||
488 | |||
489 | if(!empty($member)) { |
||
490 | $form->loadDataFrom($member); |
||
491 | } |
||
492 | |||
493 | // hook to allow further extensions to alter the comments form |
||
494 | $this->extend('alterCommentForm', $form); |
||
495 | |||
496 | return $form; |
||
497 | } |
||
498 | |||
499 | /** |
||
500 | * Process which creates a {@link Comment} once a user submits a comment from this form. |
||
501 | * |
||
502 | * @param array $data |
||
503 | * @param Form $form |
||
504 | */ |
||
505 | public function doPostComment($data, $form) { |
||
506 | // Load class and parent from data |
||
507 | if(isset($data['BaseClass'])) { |
||
508 | $this->setBaseClass($data['BaseClass']); |
||
509 | } |
||
510 | if(isset($data['ParentID']) && ($class = $this->getBaseClass())) { |
||
511 | $this->setOwnerRecord($class::get()->byID($data['ParentID'])); |
||
512 | } |
||
513 | if(!$this->getOwnerRecord()) return $this->httpError(404); |
||
514 | |||
515 | // cache users data |
||
516 | Cookie::set("CommentsForm_UserData", Convert::raw2json($data)); |
||
517 | Cookie::set("CommentsForm_Comment", $data['Comment']); |
||
518 | |||
519 | // extend hook to allow extensions. Also see onAfterPostComment |
||
520 | $this->extend('onBeforePostComment', $form); |
||
521 | |||
522 | // If commenting can only be done by logged in users, make sure the user is logged in |
||
523 | if(!$this->getOwnerRecord()->canPostComment()) { |
||
524 | return Security::permissionFailure( |
||
525 | $this, |
||
526 | _t( |
||
527 | 'CommentingController.PERMISSIONFAILURE', |
||
528 | "You're not able to post comments to this page. Please ensure you are logged in and have an " |
||
529 | . "appropriate permission level." |
||
530 | ) |
||
531 | ); |
||
532 | } |
||
533 | |||
534 | if($member = Member::currentUser()) { |
||
535 | $form->Fields()->push(new HiddenField("AuthorID", "Author ID", $member->ID)); |
||
536 | } |
||
537 | |||
538 | // What kind of moderation is required? |
||
539 | switch($this->getOwnerRecord()->ModerationRequired) { |
||
540 | case 'Required': |
||
541 | $requireModeration = true; |
||
542 | break; |
||
543 | case 'NonMembersOnly': |
||
544 | $requireModeration = empty($member); |
||
545 | break; |
||
546 | case 'None': |
||
547 | default: |
||
548 | $requireModeration = false; |
||
549 | break; |
||
550 | } |
||
551 | |||
552 | $comment = new Comment(); |
||
553 | $form->saveInto($comment); |
||
554 | |||
555 | $comment->AllowHtml = $this->getOption('html_allowed'); |
||
556 | $comment->Moderated = !$requireModeration; |
||
557 | |||
558 | // Save into DB, or call pre-save hooks to give accurate preview |
||
559 | $usePreview = $this->getOption('use_preview'); |
||
560 | $isPreview = $usePreview && !empty($data['IsPreview']); |
||
561 | if($isPreview) { |
||
562 | $comment->extend('onBeforeWrite'); |
||
563 | } else { |
||
564 | $comment->write(); |
||
565 | |||
566 | // extend hook to allow extensions. Also see onBeforePostComment |
||
567 | $this->extend('onAfterPostComment', $comment); |
||
568 | } |
||
569 | |||
570 | // we want to show a notification if comments are moderated |
||
571 | if ($requireModeration && !$comment->IsSpam) { |
||
572 | Session::set('CommentsModerated', 1); |
||
573 | } |
||
574 | |||
575 | // clear the users comment since it passed validation |
||
576 | Cookie::set('CommentsForm_Comment', false); |
||
577 | |||
578 | // Find parent link |
||
579 | if(!empty($data['ReturnURL'])) { |
||
580 | $url = $data['ReturnURL']; |
||
581 | } elseif($parent = $comment->getParent()) { |
||
582 | $url = $parent->Link(); |
||
583 | } else { |
||
584 | return $this->redirectBack(); |
||
585 | } |
||
586 | |||
587 | // Given a redirect page exists, attempt to link to the correct anchor |
||
588 | if($comment->IsSpam) { |
||
589 | // Link to the form with the error message contained |
||
590 | $hash = $form->FormName(); |
||
591 | } else if(!$comment->Moderated) { |
||
592 | // Display the "awaiting moderation" text |
||
593 | $holder = $this->getOption('comments_holder_id'); |
||
594 | $hash = "{$holder}_PostCommentForm_error"; |
||
595 | } else { |
||
596 | // Link to the moderated, non-spam comment |
||
597 | $hash = $comment->Permalink(); |
||
598 | } |
||
599 | |||
600 | return $this->redirect(Controller::join_links($url, "#{$hash}")); |
||
601 | } |
||
602 | |||
603 | public function doPreviewComment($data, $form) { |
||
604 | $data['IsPreview'] = 1; |
||
605 | |||
606 | return $this->doPostComment($data, $form); |
||
607 | } |
||
608 | |||
609 | public function redirectBack() { |
||
610 | // Don't cache the redirect back ever |
||
611 | HTTP::set_cache_age(0); |
||
612 | |||
613 | $url = null; |
||
614 | |||
615 | // In edge-cases, this will be called outside of a handleRequest() context; in that case, |
||
616 | // redirect to the homepage - don't break into the global state at this stage because we'll |
||
617 | // be calling from a test context or something else where the global state is inappropraite |
||
618 | if($this->request) { |
||
619 | if($this->request->requestVar('BackURL')) { |
||
620 | $url = $this->request->requestVar('BackURL'); |
||
621 | } else if($this->request->isAjax() && $this->request->getHeader('X-Backurl')) { |
||
622 | $url = $this->request->getHeader('X-Backurl'); |
||
623 | } else if($this->request->getHeader('Referer')) { |
||
624 | $url = $this->request->getHeader('Referer'); |
||
625 | } |
||
626 | } |
||
627 | |||
628 | if(!$url) $url = $this->fallbackReturnURL; |
||
629 | if(!$url) $url = Director::baseURL(); |
||
630 | |||
631 | // absolute redirection URLs not located on this site may cause phishing |
||
632 | if(Director::is_site_url($url)) { |
||
633 | return $this->redirect($url); |
||
634 | } else { |
||
635 | return false; |
||
636 | } |
||
637 | |||
638 | } |
||
639 | } |
||
640 |