Completed
Pull Request — master (#196)
by Robbie
13:10
created

CommentsExtension   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 555
Duplicated Lines 7.75 %

Coupling/Cohesion

Components 1
Dependencies 22

Importance

Changes 0
Metric Value
wmc 62
lcom 1
cbo 22
dl 43
loc 555
rs 1.7098
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
C populateDefaults() 10 29 8
C updateSettingsFields() 0 44 7
A getModerationRequired() 0 12 4
A getCommentsRequireLogin() 0 8 2
A AllComments() 9 9 1
B AllVisibleComments() 0 20 6
A Comments() 12 12 2
A PagedComments() 12 12 1
A getCommentsEnabled() 0 14 3
A getCommentHolderID() 0 4 1
A getPostingRequiredPermission() 0 4 1
C canPostComment() 0 27 7
A canModerateComments() 0 10 2
A getCommentRSSLink() 0 4 1
A getCommentRSSLinkPage() 0 8 1
B CommentsForm() 0 33 4
A attachedToSiteTree() 0 6 2
A getCommentsOption() 0 16 4
A updateModerationFields() 0 55 2
A updateCMSFields() 0 12 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like CommentsExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CommentsExtension, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SilverStripe\Comments\Extensions;
4
5
use SilverStripe\Comments\Admin\CommentsGridField;
6
use SilverStripe\Comments\Admin\CommentsGridFieldConfig;
7
use SilverStripe\Comments\Controllers\CommentingController;
8
use SilverStripe\Comments\Model\Comment;
9
use SilverStripe\Control\Controller;
10
use SilverStripe\Control\Director;
11
use SilverStripe\Control\Session;
12
use SilverStripe\Core\Config\Config;
13
use SilverStripe\Dev\Deprecation;
14
use SilverStripe\Forms\CheckboxField;
15
use SilverStripe\Forms\DropdownField;
16
use SilverStripe\Forms\FieldGroup;
17
use SilverStripe\Forms\FieldList;
18
use SilverStripe\Forms\Tab;
19
use SilverStripe\Forms\TabSet;
20
use SilverStripe\ORM\DataExtension;
21
use SilverStripe\ORM\PaginatedList;
22
use SilverStripe\Security\Member;
23
use SilverStripe\Security\Permission;
24
use SilverStripe\View\Requirements;
25
26
/**
27
 * Extension to {@link DataObject} to enable tracking comments.
28
 *
29
 * @package comments
30
 */
31
class CommentsExtension extends DataExtension
32
{
33
    /**
34
     * Default configuration values
35
     *
36
     * enabled:                     Allows commenting to be disabled even if the extension is present
37
     * enabled_cms:                 Allows commenting to be enabled or disabled via the CMS
38
     * require_login:               Boolean, whether a user needs to login (required for required_permission)
39
     * require_login_cms:           Allows require_login to be set via the CMS
40
     * required_permission:         Permission (or array of permissions) required to comment
41
     * include_js:                  Enhance operation by ajax behaviour on moderation links (required for use_preview)
42
     * use_gravatar:                Set to true to show gravatar icons
43
     * gravatar_default:            Theme for 'not found' gravatar {@see http://gravatar.com/site/implement/images}
44
     * gravatar_rating:             Gravatar rating (same as the standard default)
45
     * show_comments_when_disabled: Show older comments when commenting has been disabled.
46
     * order_comments_by:           Default sort order.
47
     * order_replies_by:            Sort order for replies.
48
     * comments_holder_id:          ID for the comments holder
49
     * comment_permalink_prefix:    ID prefix for each comment
50
     * require_moderation:          Require moderation for all comments
51
     * require_moderation_cms:      Ignore other comment moderation config settings and set via CMS
52
     * frontend_moderation:         Display unmoderated comments in the frontend, if the user can moderate them.
53
     * frontend_spam:               Display spam comments in the frontend, if the user can moderate them.
54
     * html_allowed:                Allow for sanitized HTML in comments
55
     * use_preview:                 Preview formatted comment (when allowing HTML)
56
     * nested_comments:             Enable nested comments
57
     * nested_depth:                Max depth of nested comments in levels (where root is 1 depth) 0 means no limit.
58
     *
59
     * @var array
60
     *
61
     * @config
62
     */
63
    private static $comments = array(
0 ignored issues
show
Unused Code introduced by
The property $comments 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...
64
        'enabled' => true,
65
        'enabled_cms' => false,
66
        'require_login' => false,
67
        'require_login_cms' => false,
68
        'required_permission' => false,
69
        'include_js' => true,
70
        'use_gravatar' => false,
71
        'gravatar_size' => 80,
72
        'gravatar_default' => 'identicon',
73
        'gravatar_rating' => 'g',
74
        'show_comments_when_disabled' => false,
75
        'order_comments_by' => '"Created" DESC',
76
        'order_replies_by' => false,
77
        'comments_per_page' => 10,
78
        'comments_holder_id' => 'comments-holder',
79
        'comment_permalink_prefix' => 'comment-',
80
        'require_moderation' => false,
81
        'require_moderation_nonmembers' => false,
82
        'require_moderation_cms' => false,
83
        'frontend_moderation' => false,
84
        'frontend_spam' => false,
85
        'html_allowed' => false,
86
        'html_allowed_elements' => array('a', 'img', 'i', 'b'),
87
        'use_preview' => false,
88
        'nested_comments' => false,
89
        'nested_depth' => 2,
90
    );
91
92
    /**
93
     * @var array
94
     */
95
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db 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...
96
        'ProvideComments' => 'Boolean',
97
        'ModerationRequired' => 'Enum(\'None,Required,NonMembersOnly\',\'None\')',
98
        'CommentsRequireLogin' => 'Boolean',
99
    );
100
101
    /**
102
     * {@inheritDoc}
103
     */
104
    private static $has_many = [
0 ignored issues
show
Unused Code introduced by
The property $has_many 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...
105
        'Commments' => 'SilverStripe\\Comments\\Model\\Comment.Parent'
106
    ];
107
108
    /**
109
     * CMS configurable options should default to the config values, but respect
110
     * default values specified by the object
111
     */
112
    public function populateDefaults()
113
    {
114
        $defaults = $this->owner->config()->defaults;
115
116
        // Set if comments should be enabled by default
117 View Code Duplication
        if (isset($defaults['ProvideComments'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
118
            $this->owner->ProvideComments = $defaults['ProvideComments'];
119
        } else {
120
            $this->owner->ProvideComments = $this->owner->getCommentsOption('enabled') ? 1 : 0;
121
        }
122
123
        // If moderation options should be configurable via the CMS then
124
        if (isset($defaults['ModerationRequired'])) {
125
            $this->owner->ModerationRequired = $defaults['ModerationRequired'];
126
        } elseif ($this->owner->getCommentsOption('require_moderation')) {
127
            $this->owner->ModerationRequired = 'Required';
128
        } elseif ($this->owner->getCommentsOption('require_moderation_nonmembers')) {
129
            $this->owner->ModerationRequired = 'NonMembersOnly';
130
        } else {
131
            $this->owner->ModerationRequired = 'None';
132
        }
133
134
        // Set login required
135 View Code Duplication
        if (isset($defaults['CommentsRequireLogin'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
136
            $this->owner->CommentsRequireLogin = $defaults['CommentsRequireLogin'];
137
        } else {
138
            $this->owner->CommentsRequireLogin = $this->owner->getCommentsOption('require_login') ? 1 : 0;
139
        }
140
    }
141
142
143
    /**
144
     * If this extension is applied to a {@link SiteTree} record then
145
     * append a Provide Comments checkbox to allow authors to trigger
146
     * whether or not to display comments
147
     *
148
     * @todo Allow customization of other {@link Commenting} configuration
149
     *
150
     * @param FieldList $fields
151
     */
152
    public function updateSettingsFields(FieldList $fields)
153
    {
154
        $options = FieldGroup::create()->setTitle(_t('CommentsExtension.COMMENTOPTIONS', 'Comments'));
155
156
        // Check if enabled setting should be cms configurable
157
        if ($this->owner->getCommentsOption('enabled_cms')) {
158
            $options->push(new CheckboxField('ProvideComments', _t('Comment.ALLOWCOMMENTS', 'Allow Comments')));
159
        }
160
161
        // Check if we should require users to login to comment
162
        if ($this->owner->getCommentsOption('require_login_cms')) {
163
            $options->push(
164
                new CheckboxField(
165
                    'CommentsRequireLogin',
166
                    _t('Comments.COMMENTSREQUIRELOGIN', 'Require login to comment')
167
                )
168
            );
169
        }
170
171
        if ($options->FieldList()->count()) {
172
            if ($fields->hasTabSet()) {
173
                $fields->addFieldsToTab('Root.Settings', $options);
0 ignored issues
show
Documentation introduced by
$options is of type object<SilverStripe\Forms\FieldGroup>, 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...
174
            } else {
175
                $fields->push($options);
176
            }
177
        }
178
179
        // Check if moderation should be enabled via cms configurable
180
        if ($this->owner->getCommentsOption('require_moderation_cms')) {
181
            $moderationField = new DropdownField('ModerationRequired', 'Comment Moderation', array(
182
                'None' => _t('CommentsExtension.MODERATIONREQUIRED_NONE', 'No moderation required'),
183
                'Required' => _t('CommentsExtension.MODERATIONREQUIRED_REQUIRED', 'Moderate all comments'),
184
                'NonMembersOnly' => _t(
185
                    'CommentsExtension.MODERATIONREQUIRED_NONMEMBERSONLY',
186
                    'Only moderate non-members'
187
                ),
188
            ));
189
            if ($fields->hasTabSet()) {
190
                $fields->addFieldsToTab('Root.Settings', $moderationField);
0 ignored issues
show
Documentation introduced by
$moderationField is of type object<SilverStripe\Forms\DropdownField>, 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...
191
            } else {
192
                $fields->push($moderationField);
193
            }
194
        }
195
    }
196
197
    /**
198
     * Get comment moderation rules for this parent
199
     *
200
     * None:           No moderation required
201
     * Required:       All comments
202
     * NonMembersOnly: Only anonymous users
203
     *
204
     * @return string
205
     */
206
    public function getModerationRequired()
207
    {
208
        if ($this->owner->getCommentsOption('require_moderation_cms')) {
209
            return $this->owner->getField('ModerationRequired');
210
        } elseif ($this->owner->getCommentsOption('require_moderation')) {
211
            return 'Required';
212
        } elseif ($this->owner->getCommentsOption('require_moderation_nonmembers')) {
213
            return 'NonMembersOnly';
214
        } else {
215
            return 'None';
216
        }
217
    }
218
219
    /**
220
     * Determine if users must be logged in to post comments
221
     *
222
     * @return boolean
223
     */
224
    public function getCommentsRequireLogin()
225
    {
226
        if ($this->owner->getCommentsOption('require_login_cms')) {
227
            return (bool) $this->owner->getField('CommentsRequireLogin');
228
        } else {
229
            return (bool) $this->owner->getCommentsOption('require_login');
230
        }
231
    }
232
233
    /**
234
     * Returns the RelationList of all comments against this object. Can be used as a data source
235
     * for a gridfield with write access.
236
     *
237
     * @return DataList
238
     */
239 View Code Duplication
    public function AllComments()
0 ignored issues
show
Duplication introduced by
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...
240
    {
241
        $order = $this->owner->getCommentsOption('order_comments_by');
242
        $comments = Comment::get()
243
            ->filter('ParentID', $this->owner->ID)
244
            ->sort($order);
245
        $this->owner->extend('updateAllComments', $comments);
246
        return $comments;
247
    }
248
249
    /**
250
     * Returns all comments against this object, with with spam and unmoderated items excluded, for use in the frontend
251
     *
252
     * @return DataList
253
     */
254
    public function AllVisibleComments()
255
    {
256
        $list = $this->AllComments();
257
258
        // Filter spam comments for non-administrators if configured
259
        $showSpam = $this->owner->getCommentsOption('frontend_spam') && $this->owner->canModerateComments();
260
        if (!$showSpam) {
261
            $list = $list->filter('IsSpam', 0);
262
        }
263
264
        // Filter un-moderated comments for non-administrators if moderation is enabled
265
        $showUnmoderated = ($this->owner->ModerationRequired === 'None')
266
            || ($this->owner->getCommentsOption('frontend_moderation') && $this->owner->canModerateComments());
267
        if (!$showUnmoderated) {
268
            $list = $list->filter('Moderated', 1);
269
        }
270
271
        $this->owner->extend('updateAllVisibleComments', $list);
272
        return $list;
273
    }
274
275
    /**
276
     * Returns the root level comments, with spam and unmoderated items excluded, for use in the frontend
277
     *
278
     * @return DataList
279
     */
280 View Code Duplication
    public function Comments()
0 ignored issues
show
Duplication introduced by
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...
281
    {
282
        $list = $this->AllVisibleComments();
283
284
        // If nesting comments, only show root level
285
        if ($this->owner->getCommentsOption('nested_comments')) {
286
            $list = $list->filter('ParentCommentID', 0);
287
        }
288
289
        $this->owner->extend('updateComments', $list);
290
        return $list;
291
    }
292
293
    /**
294
     * Returns a paged list of the root level comments, with spam and unmoderated items excluded,
295
     * for use in the frontend
296
     *
297
     * @return PaginatedList
298
     */
299 View Code Duplication
    public function PagedComments()
0 ignored issues
show
Duplication introduced by
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...
300
    {
301
        $list = $this->Comments();
302
303
        // Add pagination
304
        $list = new PaginatedList($list, Controller::curr()->getRequest());
0 ignored issues
show
Documentation introduced by
\SilverStripe\Control\Co...r::curr()->getRequest() is of type object<SilverStripe\Control\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...
305
        $list->setPaginationGetVar('commentsstart' . $this->owner->ID);
306
        $list->setPageLength($this->owner->getCommentsOption('comments_per_page'));
307
308
        $this->owner->extend('updatePagedComments', $list);
309
        return $list;
310
    }
311
312
    /**
313
     * Determine if comments are enabled for this instance
314
     *
315
     * @return boolean
316
     */
317
    public function getCommentsEnabled()
318
    {
319
        // Don't display comments form for pseudo-pages (such as the login form)
320
        if (!$this->owner->exists()) {
321
            return false;
322
        }
323
324
        // Determine which flag should be used to determine if this is enabled
325
        if ($this->owner->getCommentsOption('enabled_cms')) {
326
            return $this->owner->ProvideComments;
327
        } else {
328
            return $this->owner->getCommentsOption('enabled');
329
        }
330
    }
331
332
    /**
333
     * Get the HTML ID for the comment holder in the template
334
     *
335
     * @return string
336
     */
337
    public function getCommentHolderID()
338
    {
339
        return $this->owner->getCommentsOption('comments_holder_id');
340
    }
341
342
    /**
343
     * Permission codes required in order to post (or empty if none required)
344
     *
345
     * @return string|array Permission or list of permissions, if required
346
     */
347
    public function getPostingRequiredPermission()
348
    {
349
        return $this->owner->getCommentsOption('required_permission');
350
    }
351
352
    /**
353
     * Determine if a user can post comments on this item
354
     *
355
     * @param Member $member Member to check
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
356
     *
357
     * @return boolean
358
     */
359
    public function canPostComment($member = null)
360
    {
361
        // Deny if not enabled for this object
362
        if (!$this->owner->CommentsEnabled) {
363
            return false;
364
        }
365
366
        // Check if member is required
367
        $requireLogin = $this->owner->CommentsRequireLogin;
368
        if (!$requireLogin) {
369
            return true;
370
        }
371
372
        // Check member is logged in
373
        $member = $member ?: Member::currentUser();
374
        if (!$member) {
375
            return false;
376
        }
377
378
        // If member required check permissions
379
        $requiredPermission = $this->owner->PostingRequiredPermission;
380
        if ($requiredPermission && !Permission::checkMember($member, $requiredPermission)) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($requiredPermis... $requiredPermission));.
Loading history...
381
            return false;
382
        }
383
384
        return true;
385
    }
386
387
    /**
388
     * Determine if this member can moderate comments in the CMS
389
     *
390
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
391
     *
392
     * @return boolean
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|string?

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...
393
     */
394
    public function canModerateComments($member = null)
395
    {
396
        // Deny if not enabled for this object
397
        if (!$this->owner->CommentsEnabled) {
398
            return false;
399
        }
400
401
        // Fallback to can-edit
402
        return $this->owner->canEdit($member);
403
    }
404
405
    /**
406
     * Gets the RSS link to all comments
407
     *
408
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

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...
409
     */
410
    public function getCommentRSSLink()
411
    {
412
        return Director::absoluteURL('comments/rss');
413
    }
414
415
    /**
416
     * Get the RSS link to all comments on this page
417
     *
418
     * @return string
419
     */
420
    public function getCommentRSSLinkPage()
421
    {
422
        return Controller::join_links(
423
            $this->getCommentRSSLink(),
424
            str_replace('\\', '-', $this->ownerBaseClass),
425
            $this->owner->ID
426
        );
427
    }
428
429
    /**
430
     * Comments interface for the front end. Includes the CommentAddForm and the composition
431
     * of the comments display.
432
     *
433
     * To customize the html see templates/CommentInterface.ss or extend this function with
434
     * your own extension.
435
     *
436
     * @todo Cleanup the passing of all this configuration based functionality
437
     *
438
     * @see  docs/en/Extending
439
     */
440
    public function CommentsForm()
441
    {
442
        // Check if enabled
443
        $enabled = $this->getCommentsEnabled();
444
        if ($enabled && $this->owner->getCommentsOption('include_js')) {
445
            Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery/jquery.js');
446
            Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
447
            Requirements::javascript(ADMIN_THIRDPARTY_DIR . '/jquery-form/jquery.form.js');
448
            Requirements::javascript(COMMENTS_THIRDPARTY . '/jquery-validate/jquery.validate.min.js');
449
            Requirements::add_i18n_javascript('comments/javascript/lang');
450
            Requirements::javascript('comments/javascript/CommentsInterface.js');
451
        }
452
453
        $controller = CommentingController::create();
454
        $controller->setOwnerRecord($this->owner);
455
        $controller->setParentClass($this->owner->getClassName());
456
        $controller->setOwnerController(Controller::curr());
457
458
        $moderatedSubmitted = Session::get('CommentsModerated');
459
        Session::clear('CommentsModerated');
460
461
        $form = ($enabled) ? $controller->CommentsForm() : false;
462
463
        // a little bit all over the show but to ensure a slightly easier upgrade for users
464
        // return back the same variables as previously done in comments
465
        return $this
466
            ->owner
467
            ->customise(array(
468
                'AddCommentForm' => $form,
469
                'ModeratedSubmitted' => $moderatedSubmitted,
470
            ))
471
            ->renderWith('CommentsInterface');
472
    }
473
474
    /**
475
     * Returns whether this extension instance is attached to a {@link SiteTree} object
476
     *
477
     * @return bool
478
     */
479
    public function attachedToSiteTree()
480
    {
481
        $class = $this->ownerBaseClass;
482
483
        return (is_subclass_of($class, SiteTree::class)) || ($class == SiteTree::class);
484
    }
485
486
    /**
487
     * Get the commenting option for this object
488
     *
489
     * This can be overridden in any instance or extension to customise the option available
490
     *
491
     * @param string $key
492
     *
493
     * @return mixed Result if the setting is available, or null otherwise
494
     */
495
    public function getCommentsOption($key)
496
    {
497
        $settings = $this->owner // In case singleton is called on the extension directly
498
            ? $this->owner->config()->comments
499
            : Config::inst()->get(__CLASS__, 'comments');
500
        $value = null;
501
        if (isset($settings[$key])) {
502
            $value = $settings[$key];
503
        }
504
505
        // To allow other extensions to customise this option
506
        if ($this->owner) {
507
            $this->owner->extend('updateCommentsOption', $key, $value);
508
        }
509
        return $value;
510
    }
511
512
    /**
513
     * Add moderation functions to the current fieldlist
514
     *
515
     * @param FieldList $fields
516
     */
517
    protected function updateModerationFields(FieldList $fields)
518
    {
519
        Requirements::css(COMMENTS_DIR . '/css/cms.css');
520
521
        $newComments = $this->owner->AllComments()->filter('Moderated', 0);
522
523
        $newGrid = new CommentsGridField(
524
            'NewComments',
525
            _t('CommentsAdmin.NewComments', 'New'),
526
            $newComments,
527
            CommentsGridFieldConfig::create()
528
        );
529
530
        $approvedComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 0);
531
532
        $approvedGrid = new CommentsGridField(
533
            'ApprovedComments',
534
            _t('CommentsAdmin.Comments', 'Approved'),
535
            $approvedComments,
536
            CommentsGridFieldConfig::create()
537
        );
538
539
        $spamComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 1);
540
541
        $spamGrid = new CommentsGridField(
542
            'SpamComments',
543
            _t('CommentsAdmin.SpamComments', 'Spam'),
544
            $spamComments,
545
            CommentsGridFieldConfig::create()
546
        );
547
548
        $newCount = '(' . count($newComments) . ')';
549
        $approvedCount = '(' . count($approvedComments) . ')';
550
        $spamCount = '(' . count($spamComments) . ')';
551
552
        if ($fields->hasTabSet()) {
553
            $tabs = new TabSet(
554
                'Comments',
555
                new Tab('CommentsNewCommentsTab', _t('CommentAdmin.NewComments', 'New') . ' ' . $newCount,
556
                    $newGrid
557
                ),
558
                new Tab('CommentsCommentsTab', _t('CommentAdmin.Comments', 'Approved') . ' ' . $approvedCount,
559
                    $approvedGrid
560
                ),
561
                new Tab('CommentsSpamCommentsTab', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount,
562
                    $spamGrid
563
                )
564
            );
565
            $fields->addFieldToTab('Root', $tabs);
566
        } else {
567
            $fields->push($newGrid);
568
            $fields->push($approvedGrid);
569
            $fields->push($spamGrid);
570
        }
571
    }
572
573
    public function updateCMSFields(FieldList $fields)
574
    {
575
        // Disable moderation if not permitted
576
        if ($this->owner->canModerateComments()) {
577
            $this->updateModerationFields($fields);
578
        }
579
580
        // If this isn't a page we should merge the settings into the CMS fields
581
        if (!$this->attachedToSiteTree()) {
582
            $this->updateSettingsFields($fields);
583
        }
584
    }
585
}
586