Blog   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 702
Duplicated Lines 11.97 %

Coupling/Cohesion

Components 1
Dependencies 26

Importance

Changes 0
Metric Value
wmc 63
lcom 1
cbo 26
dl 84
loc 702
rs 3.258
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A Tags() 14 14 3
A Categories() 14 14 3
B getCMSFields() 0 55 2
A addCMSRequirements() 0 5 1
A canEdit() 0 10 2
A getMember() 12 12 3
A isEditor() 0 7 1
A isMemberOf() 12 12 4
B RoleOf() 0 24 6
A isWriter() 0 7 1
A isContributor() 0 7 1
A canAddChildren() 0 10 4
B getSettingsFields() 0 87 4
A getCandidateUsers() 0 12 2
A canEditEditors() 0 12 2
A canEditWriters() 16 16 3
A canEditContributors() 16 16 3
A getArchivedBlogPosts() 0 35 4
A getBlogPosts() 0 8 1
A ProfileLink() 0 4 1
A getLumberjackTitle() 0 4 1
A getLumberjackGridFieldConfig() 0 4 1
A providePermissions() 0 17 1
A onBeforeWrite() 0 5 1
B assignGroup() 0 20 6
A getUserGroup() 0 23 2

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 Blog 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 Blog, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SilverStripe\Blog\Model;
4
5
use Exception;
6
use Page;
7
use SilverStripe\Blog\Admin\GridFieldCategorisationConfig;
8
use SilverStripe\Blog\Forms\GridField\GridFieldConfigBlogPost;
9
use SilverStripe\Control\Controller;
10
use SilverStripe\Core\Convert;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\GridField\GridField;
13
use SilverStripe\Forms\GridField\GridFieldConfig;
14
use SilverStripe\Forms\ListboxField;
15
use SilverStripe\Forms\LiteralField;
16
use SilverStripe\Forms\NumericField;
17
use SilverStripe\Forms\Tab;
18
use SilverStripe\Forms\TabSet;
19
use SilverStripe\ORM\DataList;
20
use SilverStripe\ORM\DataObject;
21
use SilverStripe\ORM\DB;
22
use SilverStripe\ORM\ManyManyList;
23
use SilverStripe\ORM\SS_List;
24
use SilverStripe\ORM\UnsavedRelationList;
25
use SilverStripe\ORM\ValidationException;
26
use SilverStripe\Security\Group;
27
use SilverStripe\Security\Member;
28
use SilverStripe\Security\Permission;
29
use SilverStripe\Security\PermissionProvider;
30
use SilverStripe\Security\Security;
31
use SilverStripe\View\Requirements;
32
33
/**
34
 * Blog Holder
35
 *
36
 * @property int $PostsPerPage
37
 * @method ManyManyList Editors() List of editors
38
 * @method ManyManyList Writers() List of writers
39
 * @method ManyManyList Contributors() List of contributors
40
 */
41
class Blog extends Page implements PermissionProvider
42
{
43
    /**
44
     * Permission for user management.
45
     *
46
     * @var string
47
     */
48
    const MANAGE_USERS = 'BLOG_MANAGE_USERS';
49
50
    /**
51
     * If true, users assigned as editor, writer, or contributor will be automatically granted
52
     * CMS_ACCESS_CMSMain permission. If false, only users with this permission already may be
53
     * assigned.
54
     *
55
     * @config
56
     *
57
     * @var boolean
58
     */
59
    private static $grant_user_access = true;
60
61
    /**
62
     * Permission to either require, or grant to users assigned to work on this blog.
63
     *
64
     * @config
65
     *
66
     * @var string
67
     */
68
    private static $grant_user_permission = 'CMS_ACCESS_CMSMain';
69
70
    /**
71
     * Group code to assign newly granted users to.
72
     *
73
     * @config
74
     *
75
     * @var string
76
     */
77
    private static $grant_user_group = 'blog-users';
78
79
    /**
80
     * {@inheritDoc}
81
     * @var string
82
     */
83
    private static $table_name = 'Blog';
84
85
    /**
86
     * @var array
87
     */
88
    private static $db = [
89
        'PostsPerPage' => 'Int',
90
    ];
91
92
    /**
93
     * @var array
94
     */
95
    private static $many_many = [
96
        'Editors'      => Member::class,
97
        'Writers'      => Member::class,
98
        'Contributors' => Member::class,
99
    ];
100
101
    /**
102
     * @var array
103
     */
104
    private static $allowed_children = [
105
        BlogPost::class,
106
    ];
107
108
    /**
109
     * @var array
110
     */
111
    private static $extensions = [
112
        BlogFilter::class,
113
    ];
114
115
    /**
116
     * @var array
117
     */
118
    private static $defaults = [
119
        'ProvideComments' => false,
120
        'PostsPerPage'    => 10
121
    ];
122
123
    /**
124
     * @var string
125
     */
126
    private static $description = 'Adds a blog to your website.';
127
128
    private static $icon_class = 'font-icon-p-posts';
129
130
    /**
131
     * Gets the list of all tags attached to this blog
132
     *
133
     * @param bool $hideEmpty Set to false to include tags without posts
134
     * @return DataList|BlogTag[]
135
     */
136 View Code Duplication
    public function Tags($hideEmpty = true)
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...
137
    {
138
        $tags = BlogTag::get()->setDataQueryParam('BlogID', $this->ID);
139
140
        // Conditionally hide empty tags
141
        if ($this->ID && $hideEmpty) {
142
            $tags = $tags->filter([
143
                'BlogPosts.ParentID' => $this->ID,
144
            ]);
145
        }
146
147
        $this->extend('updateBlogTags', $tags);
148
        return $tags;
149
    }
150
151
    /**
152
     * Gets the list of all categories attached to this blog
153
     *
154
     * @param bool $hideEmpty Set to false to include categories without posts
155
     * @return DataList|BlogCategory[]
156
     */
157 View Code Duplication
    public function Categories($hideEmpty = true)
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...
158
    {
159
        $tags = BlogCategory::get()->setDataQueryParam('BlogID', $this->ID);
160
161
        // Conditionally hide empty categories
162
        if ($this->ID && $hideEmpty) {
163
            $tags = $tags->filter([
164
                'BlogPosts.ParentID' => $this->ID,
165
            ]);
166
        }
167
168
        $this->extend('updateBlogCategories', $tags);
169
        return $tags;
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function getCMSFields()
176
    {
177
        $this->addCMSRequirements();
178
179
        $this->beforeUpdateCMSFields(function (FieldList $fields) {
180
            if (!$this->canEdit()) {
181
                return;
182
            }
183
            
184
            $categories = GridField::create(
185
                'Categories',
186
                _t(__CLASS__ . '.Categories', 'Categories'),
187
                $this->Categories(false),
188
                GridFieldCategorisationConfig::create(
189
                    15,
190
                    $this->Categories(false)->sort('Title'),
191
                    BlogCategory::class,
192
                    'Categories',
193
                    'BlogPosts'
194
                )
195
            );
196
197
            $tags = GridField::create(
198
                'Tags',
199
                _t(__CLASS__ . '.Tags', 'Tags'),
200
                $this->Tags(false),
201
                GridFieldCategorisationConfig::create(
202
                    15,
203
                    $this->Tags(false)->sort('Title'),
204
                    BlogTag::class,
205
                    'Tags',
206
                    'BlogPosts'
207
                )
208
            );
209
210
            $fields->addFieldToTab(
211
                'Root',
212
                TabSet::create('Categorisation', _t(__CLASS__ . '.Categorisation', 'Categorisation'))
213
                    ->addExtraClass('blog-cms-categorisation')
214
            );
215
            $fields->addFieldToTab(
216
                'Root.Categorisation',
217
                Tab::create('Categories', _t(__CLASS__ . '.Categories', 'Categories'))
218
            );
219
            $fields->addFieldToTab(
220
                'Root.Categorisation',
221
                Tab::create('Tags', _t(__CLASS__ . '.Tags', 'Tags'))
222
            );
223
224
            $fields->addFieldToTab('Root.Categorisation.Categories', $categories);
225
            $fields->addFieldToTab('Root.Categorisation.Tags', $tags);
226
        });
227
228
        return parent::getCMSFields();
229
    }
230
231
    /**
232
     * Adds CMS related css and js overrides
233
     */
234
    protected function addCMSRequirements()
235
    {
236
        Requirements::css('silverstripe/blog:client/dist/styles/main.css');
237
        Requirements::javascript('silverstripe/blog:client/dist/js/main.bundle.js');
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243
    public function canEdit($member = null)
244
    {
245
        $member = $this->getMember($member);
246
247
        if ($this->isEditor($member)) {
248
            return true;
249
        }
250
251
        return parent::canEdit($member);
252
    }
253
254
    /**
255
     * @param null|int|Member $member
256
     *
257
     * @return null|Member
258
     */
259 View Code Duplication
    protected function getMember($member = null)
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...
260
    {
261
        if (!$member) {
262
            $member = Security::getCurrentUser();
263
        }
264
265
        if (is_numeric($member)) {
266
            $member = Member::get()->byID($member);
267
        }
268
269
        return $member;
270
    }
271
272
    /**
273
     * Check if this member is an editor of the blog.
274
     *
275
     * @param Member $member
276
     *
277
     * @return bool
278
     */
279
    public function isEditor($member)
280
    {
281
        $isEditor = $this->isMemberOf($member, $this->Editors());
282
        $this->extend('updateIsEditor', $isEditor, $member);
283
284
        return $isEditor;
285
    }
286
287
    /**
288
     * Determine if the given member belongs to the given relation.
289
     *
290
     * @param Member   $member
291
     * @param DataList $relation
292
     *
293
     * @return bool
294
     */
295 View Code Duplication
    protected function isMemberOf($member, $relation)
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...
296
    {
297
        if (!$member || !$member->exists()) {
298
            return false;
299
        }
300
301
        if ($relation instanceof UnsavedRelationList) {
302
            return in_array($member->ID, $relation->getIDList());
303
        }
304
305
        return $relation->byID($member->ID) !== null;
306
    }
307
308
    /**
309
     * Determine the role of the given member.
310
     *
311
     * Call be called via template to determine the current user.
312
     *
313
     * @example "Hello $RoleOf($CurrentMember.ID)"
314
     *
315
     * @param int|Member $member
316
     *
317
     * @return null|string
318
     */
319
    public function RoleOf($member)
320
    {
321
        if (is_numeric($member)) {
322
            $member = Member::get()->byId($member);
323
        }
324
325
        if (!$member) {
326
            return null;
327
        }
328
329
        if ($this->isEditor($member)) {
330
            return _t(__CLASS__ . '.EDITOR', 'Editor');
331
        }
332
333
        if ($this->isWriter($member)) {
334
            return _t(__CLASS__ . '.WRITER', 'Writer');
335
        }
336
337
        if ($this->isContributor($member)) {
338
            return _t(__CLASS__ . '.CONTRIBUTOR', 'Contributor');
339
        }
340
341
        return null;
342
    }
343
344
    /**
345
     * Check if this member is a writer of the blog.
346
     *
347
     * @param Member $member
348
     *
349
     * @return bool
350
     */
351
    public function isWriter($member)
352
    {
353
        $isWriter = $this->isMemberOf($member, $this->Writers());
354
        $this->extend('updateIsWriter', $isWriter, $member);
355
356
        return $isWriter;
357
    }
358
359
    /**
360
     * Check if this member is a contributor of the blog.
361
     *
362
     * @param Member $member
363
     *
364
     * @return bool
365
     */
366
    public function isContributor($member)
367
    {
368
        $isContributor = $this->isMemberOf($member, $this->Contributors());
369
        $this->extend('updateIsContributor', $isContributor, $member);
370
371
        return $isContributor;
372
    }
373
374
    /**
375
     * {@inheritdoc}
376
     */
377
    public function canAddChildren($member = null)
378
    {
379
        $member = $this->getMember($member);
380
381
        if ($this->isEditor($member) || $this->isWriter($member) || $this->isContributor($member)) {
382
            return true;
383
        }
384
385
        return parent::canAddChildren($member);
386
    }
387
388
    /**
389
     * {@inheritdoc}
390
     */
391
    public function getSettingsFields()
392
    {
393
        $this->addCMSRequirements();
394
        $fields = parent::getSettingsFields();
395
396
        $fields->addFieldToTab(
397
            'Root.Settings',
398
            NumericField::create('PostsPerPage', _t(__CLASS__ . '.PostsPerPage', 'Posts Per Page'))
399
        );
400
401
        $members = $this->getCandidateUsers()->map()->toArray();
402
        $toggleButton = LiteralField::create(
403
            'ToggleButton',
404
            '<a class="font-icon-info-circled toggle-description"></a>'
405
        );
406
407
        $editorField = ListboxField::create('Editors', 'Editors', $members)
408
            ->setRightTitle($toggleButton)
409
            ->setDescription(
410
                _t(
411
                    __CLASS__ . '.UsersEditorsFieldDescription',
412
                    'An editor has control over specific Blogs, and all posts included within it.
413
                     Short of being able to assign other editors to a blog, they are able to handle most changes to
414
                     their assigned blog. <br /><br />
415
                    Editors have these permissions:<br />
416
                    <br />
417
                    Update or publish any BlogPost in their Blog<br />
418
                    Update or publish their Blog<br />
419
                    Assign/unassign writers to their Blog<br />
420
                    Assign/unassign contributors to their Blog<br />
421
                    Assign/unassign any member as an author of a particular BlogPost'
422
                )
423
            );
424
        if (!$this->canEditEditors()) {
425
            $editorField = $editorField->performDisabledTransformation();
426
        }
427
        $writerField = ListboxField::create('Writers', 'Writers', $members)
428
            ->setRightTitle($toggleButton)
429
            ->setDescription(
430
                _t(
431
                    __CLASS__ . '.UsersWritersFieldDescription',
432
                    'A writer has full control over creating, editing and publishing BlogPosts they have authored
433
                      or have been assigned to. Writers are unable to edit BlogPosts to which they are not assigned.
434
                    <br /><br />
435
                    Writers have these permissions:<br />
436
                    <br />
437
                    Update or publish any BlogPost they have authored or have been assigned to<br />
438
                    Assign/unassign any member as an author of a particular BlogPost they have authored or have been
439
                    assigned to'
440
                )
441
            );
442
443
        if (!$this->canEditWriters()) {
444
            $writerField = $writerField->performDisabledTransformation();
445
        }
446
447
        $contributorField = ListboxField::create('Contributors', 'Contributors', $members)
448
            // ->setMultiple(true)
449
            ->setRightTitle($toggleButton)
450
            ->setDescription(
451
                _t(
452
                    __CLASS__ . '.UsersContributorsFieldDescription',
453
                    'Contributors have the ability to create or edit BlogPosts, but are unable to publish without
454
                        authorisation of an editor. They are also unable to assign other contributing authors to any of
455
                         their BlogPosts.<br />
456
                        <br />
457
                        Contributors have these permissions:<br />
458
                        <br />
459
                        Update any BlogPost they have authored or have been assigned to'
460
                )
461
            );
462
463
        if (!$this->canEditContributors()) {
464
            $contributorField = $contributorField->performDisabledTransformation();
465
        }
466
467
        $fields->addFieldsToTab(
468
            'Root.Users',
469
            [
470
                $editorField,
471
                $writerField,
472
                $contributorField
473
            ]
474
        );
475
476
        return $fields;
477
    }
478
479
    /**
480
     * Gets the list of user candidates to be assigned to assist with this blog.
481
     *
482
     * @return SS_List
483
     */
484
    protected function getCandidateUsers()
485
    {
486
        if ($this->config()->get('grant_user_access')) {
487
            $list = Member::get();
488
            $this->extend('updateCandidateUsers', $list);
489
            return $list;
490
        }
491
492
        return Permission::get_members_by_permission(
493
            $this->config()->get('grant_user_permission')
494
        );
495
    }
496
497
    /**
498
     * Determine if this user can edit the editors list.
499
     *
500
     * @param int|Member $member
501
     *
502
     * @return bool
503
     */
504
    public function canEditEditors($member = null)
505
    {
506
        $member = $this->getMember($member);
507
508
        $extended = $this->extendedCan('canEditEditors', $member);
509
510
        if ($extended !== null) {
511
            return $extended;
512
        }
513
514
        return Permission::checkMember($member, self::MANAGE_USERS);
0 ignored issues
show
Bug Compatibility introduced by
The expression \SilverStripe\Security\P...r, self::MANAGE_USERS); of type boolean|string adds the type string to the return on line 514 which is incompatible with the return type documented by SilverStripe\Blog\Model\Blog::canEditEditors of type boolean.
Loading history...
515
    }
516
517
    /**
518
     * Determine if this user can edit writers list.
519
     *
520
     * @param int|Member $member
521
     *
522
     * @return boolean
523
     */
524 View Code Duplication
    public function canEditWriters($member = null)
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...
525
    {
526
        $member = $this->getMember($member);
527
528
        $extended = $this->extendedCan('canEditWriters', $member);
529
530
        if ($extended !== null) {
531
            return $extended;
532
        }
533
534
        if ($this->isEditor($member)) {
535
            return true;
536
        }
537
538
        return Permission::checkMember($member, self::MANAGE_USERS);
0 ignored issues
show
Bug Compatibility introduced by
The expression \SilverStripe\Security\P...r, self::MANAGE_USERS); of type boolean|string adds the type string to the return on line 538 which is incompatible with the return type documented by SilverStripe\Blog\Model\Blog::canEditWriters of type boolean.
Loading history...
539
    }
540
541
    /**
542
     * Determines if this user can edit the contributors list.
543
     *
544
     * @param int|Member $member
545
     *
546
     * @return boolean
547
     */
548 View Code Duplication
    public function canEditContributors($member = null)
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...
549
    {
550
        $member = $this->getMember($member);
551
552
        $extended = $this->extendedCan('canEditContributors', $member);
553
554
        if ($extended !== null) {
555
            return $extended;
556
        }
557
558
        if ($this->isEditor($member)) {
559
            return true;
560
        }
561
562
        return Permission::checkMember($member, self::MANAGE_USERS);
0 ignored issues
show
Bug Compatibility introduced by
The expression \SilverStripe\Security\P...r, self::MANAGE_USERS); of type boolean|string adds the type string to the return on line 562 which is incompatible with the return type documented by SilverStripe\Blog\Model\Blog::canEditContributors of type boolean.
Loading history...
563
    }
564
565
    /**
566
     * Returns BlogPosts for a given date period.
567
     *
568
     * @param int      $year
569
     * @param null|int $month
570
     * @param null|int $day
571
     *
572
     * @return DataList
573
     */
574
    public function getArchivedBlogPosts($year, $month = null, $day = null)
575
    {
576
        $query = $this->getBlogPosts()->dataQuery();
577
578
        $stage = $query->getQueryParam('Versioned.stage');
579
580
        if ($stage) {
581
            $stage = '_' . $stage;
582
        }
583
584
        $query->innerJoin(
585
            DataObject::getSchema()->tableName(BlogPost::class),
586
            sprintf('"SiteTree%s"."ID" = "BlogPost%s"."ID"', $stage, $stage)
587
        );
588
589
        $conn = DB::get_conn();
590
591
        // Filter by year
592
        $yearCond = $conn->formattedDatetimeClause('"BlogPost"."PublishDate"', '%Y');
593
        $query->where(sprintf('%s = \'%04d\'', $yearCond, Convert::raw2sql($year)));
594
595
        // Filter by month (if given)
596
        if ($month) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $month of type null|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
597
            $monthCond = $conn->formattedDatetimeClause('"BlogPost"."PublishDate"', '%m');
598
            $query->where(sprintf('%s = \'%02d\'', $monthCond, Convert::raw2sql($month)));
599
600
            if ($day) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $day of type null|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
601
                $dayCond = $conn->formattedDatetimeClause('"BlogPost"."PublishDate"', '%d');
602
                $query->where(sprintf('%s = \'%02d\'', $dayCond, Convert::raw2sql($day)));
603
            }
604
        }
605
606
607
        return $this->getBlogPosts()->setDataQuery($query);
608
    }
609
610
    /**
611
     * Return blog posts.
612
     *
613
     * @return DataList of BlogPost objects
614
     */
615
    public function getBlogPosts()
616
    {
617
        $blogPosts = BlogPost::get()->filter('ParentID', $this->ID);
618
619
        $this->extend('updateGetBlogPosts', $blogPosts);
620
621
        return $blogPosts;
622
    }
623
624
    /**
625
     * Get a link to a Member profile.
626
     *
627
     * @param string $urlSegment
628
     *
629
     * @return string
630
     */
631
    public function ProfileLink($urlSegment)
632
    {
633
        return Controller::join_links($this->Link('profile'), $urlSegment);
634
    }
635
636
    /**
637
     * This sets the title for our gridfield.
638
     *
639
     * @return string
640
     */
641
    public function getLumberjackTitle()
642
    {
643
        return _t(__CLASS__ . '.LumberjackTitle', 'Blog Posts');
644
    }
645
646
    /**
647
     * This overwrites lumberjacks default gridfield config.
648
     *
649
     * @return GridFieldConfig
650
     */
651
    public function getLumberjackGridFieldConfig()
652
    {
653
        return GridFieldConfigBlogPost::create();
654
    }
655
656
    /**
657
     * {@inheritdoc}
658
     */
659
    public function providePermissions()
660
    {
661
        return [
662
            Blog::MANAGE_USERS => [
663
                'name'     => _t(
664
                    __CLASS__ . '.PERMISSION_MANAGE_USERS_DESCRIPTION',
665
                    'Manage users for individual blogs'
666
                ),
667
                'help'     => _t(
668
                    __CLASS__ . '.PERMISSION_MANAGE_USERS_HELP',
669
                    'Allow assignment of Editors, Writers, or Contributors to blogs'
670
                ),
671
                'category' => _t(__CLASS__ . '.PERMISSIONS_CATEGORY', 'Blog permissions'),
672
                'sort'     => 100
673
            ]
674
        ];
675
    }
676
677
    /**
678
     * @throws ValidationException
679
     */
680
    protected function onBeforeWrite()
681
    {
682
        parent::onBeforeWrite();
683
        $this->assignGroup();
684
    }
685
686
    /**
687
     * Assign users as necessary to the blog group.
688
     *
689
     * @throws ValidationException
690
     * @throws Exception
691
     */
692
    protected function assignGroup()
693
    {
694
        if (!$this->config()->get('grant_user_access')) {
695
            return;
696
        }
697
698
        $group = $this->getUserGroup();
699
700
        // Must check if the method exists or else an error occurs when changing page type
701
        if ($this->hasMethod('Editors')) {
702
            foreach ([$this->Editors(), $this->Writers(), $this->Contributors()] as $levels) {
703
                /** @var Member $user */
704
                foreach ($levels as $user) {
705
                    if (!$user->inGroup($group)) {
706
                        $user->Groups()->add($group);
707
                    }
708
                }
709
            }
710
        }
711
    }
712
713
    /**
714
     * Gets or creates the group used to assign CMS access.
715
     *
716
     * @return Group
717
     * @throws ValidationException
718
     */
719
    protected function getUserGroup()
720
    {
721
        $code = $this->config()->get('grant_user_group');
722
723
        /** @var Group $group */
724
        $group = Group::get()->filter('Code', $code)->first();
725
        if ($group) {
726
            return $group;
727
        }
728
729
        $group = Group::create();
730
        $group->Title = 'Blog users';
731
        $group->Code = $code;
732
733
        $group->write();
734
735
        $permission = Permission::create();
736
        $permission->Code = $this->config()->get('grant_user_permission');
737
738
        $group->Permissions()->add($permission);
739
740
        return $group;
741
    }
742
}
743