Completed
Push — master ( 4e2d22...187618 )
by Will
14:40
created

src/Model/Comment.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\Model;
4
5
use HTMLPurifier_Config;
6
use HTMLPurifier;
7
use SilverStripe\Comments\Controllers\CommentingController;
8
use SilverStripe\Comments\Extensions\CommentsExtension;
9
use SilverStripe\Comments\Model\Comment\SecurityToken;
10
use SilverStripe\Control\Controller;
11
use SilverStripe\Control\Director;
12
use SilverStripe\Core\Email\Email;
13
use SilverStripe\Core\Injector\Injector;
14
use SilverStripe\Forms\CheckboxField;
15
use SilverStripe\Forms\EmailField;
16
use SilverStripe\Forms\FieldGroup;
17
use SilverStripe\Forms\FieldList;
18
use SilverStripe\Forms\HeaderField;
19
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
20
use SilverStripe\Forms\TextareaField;
21
use SilverStripe\Forms\TextField;
22
use SilverStripe\ORM\ArrayList;
23
use SilverStripe\ORM\DataObject;
24
use SilverStripe\ORM\DB;
25
use SilverStripe\ORM\PaginatedList;
26
use SilverStripe\Security\Member;
27
use SilverStripe\Security\Permission;
28
29
/**
30
 * Represents a single comment object.
31
 *
32
 * @property string  $Name
33
 * @property string  $Comment
34
 * @property string  $Email
35
 * @property string  $URL
36
 * @property string  $BaseClass
37
 * @property boolean $Moderated
38
 * @property boolean $IsSpam      True if the comment is known as spam
39
 * @property integer $ParentID    ID of the parent page / dataobject
40
 * @property boolean $AllowHtml   If true, treat $Comment as HTML instead of plain text
41
 * @property string  $SecretToken Secret admin token required to provide moderation links between sessions
42
 * @property integer $Depth       Depth of this comment in the nested chain
43
 *
44
 * @method HasManyList ChildComments() List of child comments
45
 * @method Member Author() Member object who created this comment
46
 * @method Comment ParentComment() Parent comment this is a reply to
47
 * @package comments
48
 */
49
class Comment extends DataObject
50
{
51
    /**
52
     * {@inheritDoc}
53
     */
54
    private static $db = array(
55
        'Name' => 'Varchar(200)',
56
        'Comment' => 'Text',
57
        'Email' => 'Varchar(200)',
58
        'URL' => 'Varchar(255)',
59
        'Moderated' => 'Boolean(0)',
60
        'IsSpam' => 'Boolean(0)',
61
        'AllowHtml' => 'Boolean',
62
        'SecretToken' => 'Varchar(255)',
63
        'Depth' => 'Int'
64
    );
65
66
    /**
67
     * {@inheritDoc}
68
     */
69
    private static $has_one = array(
70
        'Author' => Member::class,
71
        'ParentComment' => self::class,
72
        'Parent' => DataObject::class
73
    );
74
75
    /**
76
     * {@inheritDoc}
77
     */
78
    private static $has_many = array(
79
        'ChildComments' => self::class
80
    );
81
82
    /**
83
     * {@inheritDoc}
84
     */
85
    private static $default_sort = '"Created" DESC';
86
87
    /**
88
     * {@inheritDoc}
89
     */
90
    private static $defaults = array(
91
        'Moderated' => 0,
92
        'IsSpam' => 0,
93
    );
94
95
    /**
96
     * {@inheritDoc}
97
     */
98
    private static $casting = array(
99
        'Title' => 'Varchar',
100
        'ParentTitle' => 'Varchar',
101
        'ParentClassName' => 'Varchar',
102
        'AuthorName' => 'Varchar',
103
        'RSSName' => 'Varchar',
104
        'DeleteLink' => 'Varchar',
105
        'SpamLink' => 'Varchar',
106
        'HamLink' => 'Varchar',
107
        'ApproveLink' => 'Varchar',
108
        'Permalink' => 'Varchar'
109
    );
110
111
    /**
112
     * {@inheritDoc}
113
     */
114
    private static $searchable_fields = array(
115
        'Name',
116
        'Email',
117
        'Comment',
118
        'Created'
119
    );
120
121
    /**
122
     * {@inheritDoc}
123
     */
124
    private static $summary_fields = array(
125
        'Name' => 'Submitted By',
126
        'Email' => 'Email',
127
        'Comment.LimitWordCount' => 'Comment',
128
        'Created' => 'Date Posted',
129
        'Parent.Title' => 'Post',
130
        'IsSpam' => 'Is Spam'
131
    );
132
133
    /**
134
     * {@inheritDoc}
135
     */
136
    private static $field_labels = array(
137
        'Author' => 'Author Member'
138
    );
139
140
    /**
141
     * {@inheritDoc}
142
     */
143
    private static $table_name = 'Comment';
144
145
    /**
146
     * {@inheritDoc}
147
     */
148
    public function onBeforeWrite()
149
    {
150
        parent::onBeforeWrite();
151
152
        // Sanitize HTML, because its expected to be passed to the template unescaped later
153
        if ($this->AllowHtml) {
154
            $this->Comment = $this->purifyHtml($this->Comment);
155
        }
156
157
        // Check comment depth
158
        $this->updateDepth();
159
    }
160
161
    /**
162
     * {@inheritDoc}
163
     */
164
    public function onBeforeDelete()
165
    {
166
        parent::onBeforeDelete();
167
168
        // Delete all children
169
        foreach ($this->ChildComments() as $comment) {
170
            $comment->delete();
171
        }
172
    }
173
174
    /**
175
     * @return Comment_SecurityToken
176
     */
177
    public function getSecurityToken()
178
    {
179
        return Injector::inst()->createWithArgs(SecurityToken::class, array($this));
180
    }
181
182
    /**
183
     * Migrates the old {@link PageComment} objects to {@link Comment}
184
     */
185
    public function requireDefaultRecords()
186
    {
187
        parent::requireDefaultRecords();
188
189
        if (DB::get_schema()->hasTable('PageComment')) {
190
            $comments = DB::query('SELECT * FROM "PageComment"');
191
192
            if ($comments) {
193
                while ($pageComment = $comments->next()) {
194
                    // create a new comment from the older page comment
195
                    $comment = new Comment();
196
                    $comment->update($pageComment);
197
198
                    // set the variables which have changed
199
                    $comment->BaseClass = SiteTree::class;
200
                    $comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : '';
201
                    if ((int) $pageComment['NeedsModeration'] == 0) {
202
                        $comment->Moderated = true;
203
                    }
204
205
                    $comment->write();
206
                }
207
            }
208
209
            DB::alteration_message('Migrated PageComment to Comment', 'changed');
210
            DB::get_schema()->dontRequireTable('PageComment');
211
        }
212
    }
213
214
    /**
215
     * Return a link to this comment
216
     *
217
     * @param string $action
218
     *
219
     * @return string link to this comment.
220
     */
221
    public function Link($action = '')
222
    {
223
        if ($parent = $this->Parent()) {
224
            return $parent->Link($action) . '#' . $this->Permalink();
225
        }
226
    }
227
228
    /**
229
     * Returns the permalink for this {@link Comment}. Inserted into
230
     * the ID tag of the comment
231
     *
232
     * @return string
233
     */
234
    public function Permalink()
235
    {
236
        $prefix = $this->getOption('comment_permalink_prefix');
237
        return $prefix . $this->ID;
238
    }
239
240
    /**
241
     * Translate the form field labels for the CMS administration
242
     *
243
     * @param boolean $includerelations
244
     *
245
     * @return array
246
     */
247
    public function fieldLabels($includerelations = true)
248
    {
249
        $labels = parent::fieldLabels($includerelations);
250
251
        $labels['Name'] = _t('Comment.NAME', 'Author Name');
252
        $labels['Comment'] = _t('Comment.COMMENT', 'Comment');
253
        $labels['Email'] = _t('Comment.EMAIL', 'Email');
254
        $labels['URL'] = _t('Comment.URL', 'URL');
255
        $labels['IsSpam'] = _t('Comment.ISSPAM', 'Spam?');
256
        $labels['Moderated'] = _t('Comment.MODERATED', 'Moderated?');
257
        $labels['ParentTitle'] = _t('Comment.PARENTTITLE', 'Parent');
258
        $labels['Created'] = _t('Comment.CREATED', 'Date posted');
259
260
        return $labels;
261
    }
262
263
    /**
264
     * Get the commenting option
265
     *
266
     * @param string $key
267
     *
268
     * @return mixed Result if the setting is available, or null otherwise
269
     */
270
    public function getOption($key)
271
    {
272
        // If possible use the current record
273
        $record = $this->Parent();
274
275
        if (!$record && $this->Parent()) {
276
            // Otherwise a singleton of that record
277
            $record = singleton($this->Parent()->dataClass());
278
        } elseif (!$record) {
279
            // Otherwise just use the default options
280
            $record = singleton(CommentsExtension::class);
281
        }
282
283
        return ($record instanceof CommentsExtension || $record->hasExtension(CommentsExtension::class))
284
            ? $record->getCommentsOption($key)
285
            : null;
286
    }
287
288
    /**
289
     * Returns the parent {@link DataObject} this comment is attached too
290
     *
291
     * @deprecated 4.0.0 Use $this->Parent() instead
292
     * @return DataObject
293
     */
294
    public function getParent()
295
    {
296
        return $this->BaseClass && $this->ParentID
297
            ? DataObject::get_by_id($this->BaseClass, $this->ParentID, true)
298
            : null;
299
    }
300
301
302
    /**
303
     * Returns a string to help identify the parent of the comment
304
     *
305
     * @return string
306
     */
307
    public function getParentTitle()
308
    {
309
        if ($parent = $this->Parent()) {
310
            return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID);
311
        }
312
    }
313
314
    /**
315
     * Comment-parent classnames obviously vary, return the parent classname
316
     *
317
     * @return string
318
     */
319
    public function getParentClassName()
320
    {
321
        return $this->Parent()->getClassName();
322
    }
323
324
    /**
325
     * {@inheritDoc}
326
     */
327
    public function castingHelper($field)
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
328
    {
329
        // Safely escape the comment
330
        if (in_array($field, ['EscapedComment', 'Comment'], true)) {
331
            return $this->AllowHtml ? 'HTMLText' : 'Text';
332
        }
333
        return parent::castingHelper($field);
334
    }
335
336
    /**
337
     * Content to be safely escaped on the frontend
338
     *
339
     * @return string
340
     */
341
    public function getEscapedComment()
342
    {
343
        return $this->Comment;
344
    }
345
346
    /**
347
     * Return whether this comment is a preview (has not been written to the db)
348
     *
349
     * @return boolean
350
     */
351
    public function isPreview()
352
    {
353
        return !$this->exists();
354
    }
355
356
    /**
357
     * @todo needs to compare to the new {@link Commenting} configuration API
358
     *
359
     * @param Member $member
360
     * @param array  $context
361
     * @return bool
362
     */
363
    public function canCreate($member = null, $context = [])
364
    {
365
        return false;
366
    }
367
368
    /**
369
     * Checks for association with a page, and {@link SiteTree->ProvidePermission}
370
     * flag being set to true.
371
     *
372
     * @param Member $member
373
     * @return Boolean
374
     */
375
    public function canView($member = null)
376
    {
377
        $member = $this->getMember($member);
378
379
        $extended = $this->extendedCan('canView', $member);
380
        if ($extended !== null) {
381
            return $extended;
382
        }
383
384
        if (Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')) {
385
            return true;
386
        }
387
388
        if ($parent = $this->Parent()) {
389
            return $parent->canView($member)
390
                && $parent->hasExtension(CommentsExtension::class)
391
                && $parent->CommentsEnabled;
392
        }
393
394
        return false;
395
    }
396
397
    /**
398
     * Checks if the comment can be edited.
399
     *
400
     * @param null|int|Member $member
401
     * @return Boolean
402
     */
403
    public function canEdit($member = null)
404
    {
405
        $member = $this->getMember($member);
406
407
        if (!$member) {
408
            return false;
409
        }
410
411
        $extended = $this->extendedCan('canEdit', $member);
412
        if ($extended !== null) {
413
            return $extended;
414
        }
415
416
        if (Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')) {
417
            return true;
418
        }
419
420
        if ($parent = $this->Parent()) {
421
            return $parent->canEdit($member);
422
        }
423
424
        return false;
425
    }
426
427
    /**
428
     * Checks if the comment can be deleted.
429
     *
430
     * @param null|int|Member $member
431
     * @return Boolean
432
     */
433
    public function canDelete($member = null)
434
    {
435
        $member = $this->getMember($member);
436
437
        if (!$member) {
438
            return false;
439
        }
440
441
        $extended = $this->extendedCan('canDelete', $member);
442
        if ($extended !== null) {
443
            return $extended;
444
        }
445
446
        return $this->canEdit($member);
447
    }
448
449
    /**
450
     * Resolves Member object.
451
     *
452
     * @param Member|int|null $member
453
     * @return Member|null
454
     */
455
    protected function getMember($member = null)
456
    {
457
        if (!$member) {
458
            $member = Member::currentUser();
459
        }
460
461
        if (is_numeric($member)) {
462
            $member = DataObject::get_by_id(Member::class, $member, true);
463
        }
464
465
        return $member;
466
    }
467
468
    /**
469
     * Return the authors name for the comment
470
     *
471
     * @return string
472
     */
473
    public function getAuthorName()
474
    {
475
        if ($this->Name) {
476
            return $this->Name;
477
        } elseif ($author = $this->Author()) {
478
            return $author->getName();
479
        }
480
    }
481
482
    /**
483
     * Generate a secure admin-action link authorised for the specified member
484
     *
485
     * @param string $action An action on CommentingController to link to
486
     * @param Member $member The member authorised to invoke this action
487
     *
488
     * @return string
489
     */
490
    protected function actionLink($action, $member = null)
491
    {
492
        if (!$member) {
493
            $member = Member::currentUser();
494
        }
495
        if (!$member) {
496
            return false;
497
        }
498
499
        /**
500
         * @todo: How do we handle "DataObject" instances that don't have a Link to reject/spam/delete?? This may
501
         * we have to make CMS a hard dependency instead.
502
         */
503
        // if (!$this->Parent()->hasMethod('Link')) {
504
        //     return false;
505
        // }
506
507
        $url = Controller::join_links(
508
            Director::baseURL(),
509
            'comments',
510
            $action,
511
            $this->ID
512
        );
513
514
        // Limit access for this user
515
        $token = $this->getSecurityToken();
516
        return $token->addToUrl($url, $member);
517
    }
518
519
    /**
520
     * Link to delete this comment
521
     *
522
     * @param Member $member
523
     *
524
     * @return string
525
     */
526
    public function DeleteLink($member = null)
527
    {
528
        if ($this->canDelete($member)) {
529
            return $this->actionLink('delete', $member);
530
        }
531
    }
532
533
    /**
534
     * Link to mark as spam
535
     *
536
     * @param Member $member
537
     *
538
     * @return string
539
     */
540
    public function SpamLink($member = null)
541
    {
542
        if ($this->canEdit($member) && !$this->IsSpam) {
543
            return $this->actionLink('spam', $member);
544
        }
545
    }
546
547
    /**
548
     * Link to mark as not-spam (ham)
549
     *
550
     * @param Member $member
551
     *
552
     * @return string
553
     */
554
    public function HamLink($member = null)
555
    {
556
        if ($this->canEdit($member) && $this->IsSpam) {
557
            return $this->actionLink('ham', $member);
558
        }
559
    }
560
561
    /**
562
     * Link to approve this comment
563
     *
564
     * @param Member $member
565
     *
566
     * @return string
567
     */
568
    public function ApproveLink($member = null)
569
    {
570
        if ($this->canEdit($member) && !$this->Moderated) {
571
            return $this->actionLink('approve', $member);
572
        }
573
    }
574
575
    /**
576
     * Mark this comment as spam
577
     */
578
    public function markSpam()
579
    {
580
        $this->IsSpam = true;
581
        $this->Moderated = true;
582
        $this->write();
583
        $this->extend('afterMarkSpam');
584
    }
585
586
    /**
587
     * Mark this comment as approved
588
     */
589
    public function markApproved()
590
    {
591
        $this->IsSpam = false;
592
        $this->Moderated = true;
593
        $this->write();
594
        $this->extend('afterMarkApproved');
595
    }
596
597
    /**
598
     * Mark this comment as unapproved
599
     */
600
    public function markUnapproved()
601
    {
602
        $this->Moderated = false;
603
        $this->write();
604
        $this->extend('afterMarkUnapproved');
605
    }
606
607
    /**
608
     * @return string
609
     */
610
    public function SpamClass()
611
    {
612
        if ($this->IsSpam) {
613
            return 'spam';
614
        } elseif (!$this->Moderated) {
615
            return 'unmoderated';
616
        } else {
617
            return 'notspam';
618
        }
619
    }
620
621
    /**
622
     * @return string
623
     */
624
    public function getTitle()
625
    {
626
        $title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName());
627
628
        if ($parent = $this->Parent()) {
629
            if ($parent->Title) {
630
                $title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title);
631
            }
632
        }
633
634
        return $title;
635
    }
636
637
    /*
638
     * Modify the default fields shown to the user
639
     */
640
    public function getCMSFields()
641
    {
642
        $commentField = $this->AllowHtml ? HTMLEditorField::class : TextareaField::class;
643
        $fields = new FieldList(
644
            $this
645
                ->obj('Created')
646
                ->scaffoldFormField($this->fieldLabel('Created'))
647
                ->performReadonlyTransformation(),
648
            TextField::create('Name', $this->fieldLabel('Name')),
649
            $commentField::create('Comment', $this->fieldLabel('Comment')),
650
            EmailField::create('Email', $this->fieldLabel('Email')),
651
            TextField::create('URL', $this->fieldLabel('URL')),
652
            FieldGroup::create(array(
653
                CheckboxField::create('Moderated', $this->fieldLabel('Moderated')),
654
                CheckboxField::create('IsSpam', $this->fieldLabel('IsSpam')),
655
            ))
656
                ->setTitle(_t('Comment.OPTIONS', 'Options'))
657
                ->setDescription(_t(
658
                    'Comment.OPTION_DESCRIPTION',
659
                    'Unmoderated and spam comments will not be displayed until approved'
660
                ))
661
        );
662
663
        // Show member name if given
664
        if (($author = $this->Author()) && $author->exists()) {
665
            $fields->insertAfter(
666
                TextField::create('AuthorMember', $this->fieldLabel('Author'), $author->Title)
667
                    ->performReadonlyTransformation(),
668
                'Name'
669
            );
670
        }
671
672
        // Show parent comment if given
673
        if (($parent = $this->ParentComment()) && $parent->exists()) {
674
            $fields->push(new HeaderField(
675
                'ParentComment_Title',
676
                _t('Comment.ParentComment_Title', 'This comment is a reply to the below')
677
            ));
678
            // Created date
679
            // FIXME - the method setName in DatetimeField is not chainable, hence
680
            // the lack of chaining here
681
            $createdField = $parent
682
                ->obj('Created')
683
                ->scaffoldFormField($parent->fieldLabel('Created'));
684
            $createdField->setName('ParentComment_Created');
685
            $createdField->setValue($parent->Created);
686
            $createdField->performReadonlyTransformation();
687
            $fields->push($createdField);
688
689
            // Name (could be member or string value)
690
            $fields->push(
691
                $parent
692
                    ->obj('AuthorName')
693
                    ->scaffoldFormField($parent->fieldLabel('AuthorName'))
694
                    ->setName('ParentComment_AuthorName')
695
                    ->setValue($parent->getAuthorName())
696
                    ->performReadonlyTransformation()
697
            );
698
699
            // Comment body
700
            $fields->push(
701
                $parent
702
                    ->obj('EscapedComment')
703
                    ->scaffoldFormField($parent->fieldLabel(self::class))
704
                    ->setName('ParentComment_EscapedComment')
705
                    ->setValue($parent->Comment)
706
                    ->performReadonlyTransformation()
707
            );
708
        }
709
710
        $this->extend('updateCMSFields', $fields);
711
        return $fields;
712
    }
713
714
    /**
715
     * @param  string $dirtyHtml
716
     *
717
     * @return string
718
     */
719
    public function purifyHtml($dirtyHtml)
720
    {
721
        $purifier = $this->getHtmlPurifierService();
722
        return $purifier->purify($dirtyHtml);
723
    }
724
725
    /**
726
     * @return HTMLPurifier (or anything with a "purify()" method)
727
     */
728
    public function getHtmlPurifierService()
729
    {
730
        $config = HTMLPurifier_Config::createDefault();
731
        $allowedElements = (array) $this->getOption('html_allowed_elements');
732
        if (!empty($allowedElements)) {
733
            $config->set('HTML.AllowedElements', $allowedElements);
734
        }
735
736
        // This injector cannot be set unless the 'p' element is allowed
737
        if (in_array('p', $allowedElements)) {
738
            $config->set('AutoFormat.AutoParagraph', true);
739
        }
740
741
        $config->set('AutoFormat.Linkify', true);
742
        $config->set('URI.DisableExternalResources', true);
743
        $config->set('Cache.SerializerPath', getTempFolder());
744
        return new HTMLPurifier($config);
745
    }
746
747
    /**
748
     * Calculate the Gravatar link from the email address
749
     *
750
     * @return string
751
     */
752
    public function Gravatar()
753
    {
754
        $gravatar = '';
755
        $use_gravatar = $this->getOption('use_gravatar');
756
        if ($use_gravatar) {
757
            $gravatar = 'http://www.gravatar.com/avatar/' . md5(strtolower(trim($this->Email)));
758
            $gravatarsize = $this->getOption('gravatar_size');
759
            $gravatardefault = $this->getOption('gravatar_default');
760
            $gravatarrating = $this->getOption('gravatar_rating');
761
            $gravatar .= '?s=' . $gravatarsize . '&d=' . $gravatardefault . '&r=' . $gravatarrating;
762
        }
763
764
        return $gravatar;
765
    }
766
767
    /**
768
     * Determine if replies are enabled for this instance
769
     *
770
     * @return boolean
771
     */
772
    public function getRepliesEnabled()
773
    {
774
        // Check reply option
775
        if (!$this->getOption('nested_comments')) {
776
            return false;
777
        }
778
779
        // Check if depth is limited
780
        $maxLevel = $this->getOption('nested_depth');
781
        $notSpam = ($this->SpamClass() == 'notspam');
782
        return $notSpam && (!$maxLevel || $this->Depth < $maxLevel);
783
    }
784
785
    /**
786
     * Returns the list of all replies
787
     *
788
     * @return SS_List
789
     */
790
    public function AllReplies()
791
    {
792
        // No replies if disabled
793
        if (!$this->getRepliesEnabled()) {
794
            return new ArrayList();
795
        }
796
797
        // Get all non-spam comments
798
        $order = $this->getOption('order_replies_by')
799
            ?: $this->getOption('order_comments_by');
800
        $list = $this
801
            ->ChildComments()
802
            ->sort($order);
803
804
        $this->extend('updateAllReplies', $list);
805
        return $list;
806
    }
807
808
    /**
809
     * Returns the list of replies, with spam and unmoderated items excluded, for use in the frontend
810
     *
811
     * @return SS_List
812
     */
813
    public function Replies()
814
    {
815
        // No replies if disabled
816
        if (!$this->getRepliesEnabled()) {
817
            return new ArrayList();
818
        }
819
        $list = $this->AllReplies();
820
821
        // Filter spam comments for non-administrators if configured
822
        $parent = $this->Parent();
823
        $showSpam = $this->getOption('frontend_spam') && $parent && $parent->canModerateComments();
824
        if (!$showSpam) {
825
            $list = $list->filter('IsSpam', 0);
826
        }
827
828
        // Filter un-moderated comments for non-administrators if moderation is enabled
829
        $showUnmoderated = $parent && (
830
            ($parent->ModerationRequired === 'None')
831
            || ($this->getOption('frontend_moderation') && $parent->canModerateComments())
832
        );
833
        if (!$showUnmoderated) {
834
            $list = $list->filter('Moderated', 1);
835
        }
836
837
        $this->extend('updateReplies', $list);
838
        return $list;
839
    }
840
841
    /**
842
     * Returns the list of replies paged, with spam and unmoderated items excluded, for use in the frontend
843
     *
844
     * @return PaginatedList
845
     */
846 View Code Duplication
    public function PagedReplies()
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...
847
    {
848
        $list = $this->Replies();
849
850
        // Add pagination
851
        $list = new PaginatedList($list, Controller::curr()->getRequest());
852
        $list->setPaginationGetVar('repliesstart' . $this->ID);
853
        $list->setPageLength($this->getOption('comments_per_page'));
854
855
        $this->extend('updatePagedReplies', $list);
856
        return $list;
857
    }
858
859
    /**
860
     * Generate a reply form for this comment
861
     *
862
     * @return Form
863
     */
864
    public function ReplyForm()
865
    {
866
        // Ensure replies are enabled
867
        if (!$this->getRepliesEnabled()) {
868
            return null;
869
        }
870
871
        // Check parent is available
872
        $parent = $this->Parent();
873
        if (!$parent || !$parent->exists()) {
874
            return null;
875
        }
876
877
        // Build reply controller
878
        $controller = CommentingController::create();
879
        $controller->setOwnerRecord($parent);
880
        $controller->setParentClass($parent->ClassName);
881
        $controller->setOwnerController(Controller::curr());
882
883
        return $controller->ReplyForm($this);
884
    }
885
886
    /**
887
     * Refresh of this comment in the hierarchy
888
     */
889
    public function updateDepth()
890
    {
891
        $parent = $this->ParentComment();
892
        if ($parent && $parent->exists()) {
893
            $parent->updateDepth();
894
            $this->Depth = $parent->Depth + 1;
895
        } else {
896
            $this->Depth = 1;
897
        }
898
    }
899
}
900