Completed
Push — master ( 271fbf...1d6cf1 )
by Daniel
02:13
created

BlogPost::getCredits()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\Blog\Model;
4
5
use Page;
6
use SilverStripe\Assets\Image;
7
use SilverStripe\Blog\Forms\BlogAdminSidebar;
8
use SilverStripe\Blog\Model\BlogCategory;
9
use SilverStripe\Blog\Model\BlogPostFilter;
10
use SilverStripe\Blog\Model\BlogTag;
11
use SilverStripe\Control\Controller;
12
use SilverStripe\Core\Config\Config;
13
use SilverStripe\Core\Manifest\ModuleLoader;
14
use SilverStripe\Forms\DatetimeField;
15
use SilverStripe\Forms\HiddenField;
16
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
17
use SilverStripe\Forms\ListboxField;
18
use SilverStripe\Forms\TextField;
19
use SilverStripe\Forms\ToggleCompositeField;
20
use SilverStripe\AssetAdmin\Forms\UploadField;
21
use SilverStripe\ORM\ArrayList;
22
use SilverStripe\ORM\FieldType\DBDatetime;
23
use SilverStripe\ORM\UnsavedRelationList;
24
use SilverStripe\Security\Group;
25
use SilverStripe\Security\Member;
26
use SilverStripe\Security\Permission;
27
use SilverStripe\Security\Security;
28
use SilverStripe\TagField\TagField;
29
use SilverStripe\Versioned\Versioned;
30
use SilverStripe\View\ArrayData;
31
use SilverStripe\View\Requirements;
32
33
/**
34
 * An individual blog post.
35
 *
36
 * @method ManyManyList Categories()
37
 * @method ManyManyList Tags()
38
 * @method ManyManyList Authors()
39
 * @method Blog Parent()
40
 *
41
 * @property string $PublishDate
42
 * @property string $AuthorNames
43
 * @property int $ParentID
44
 */
45
class BlogPost extends Page
46
{
47
    /**
48
     * Same as above, but for list of users that can be
49
     * given credit in the author field for blog posts
50
     * @var string|bool false or group code
51
     */
52
    private static $restrict_authors_to_group = false;
0 ignored issues
show
Unused Code introduced by
The property $restrict_authors_to_group 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...
53
54
    /**
55
     * {@inheritDoc}
56
     * @var string
57
     */
58
    private static $table_name = 'BlogPost';
0 ignored issues
show
Unused Code introduced by
The property $table_name 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...
59
60
    /**
61
     * @var array
62
     */
63
    private static $db = [
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...
64
        'PublishDate' => 'Datetime',
65
        'AuthorNames' => 'Varchar(1024)',
66
        'Summary'     => 'HTMLText'
67
    ];
68
69
    /**
70
     * @var array
71
     */
72
    private static $has_one = [
0 ignored issues
show
Unused Code introduced by
The property $has_one 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...
73
        'FeaturedImage' => Image::class
74
    ];
75
76
    /**
77
     * @var array
78
     */
79
    private static $owns = [
0 ignored issues
show
Unused Code introduced by
The property $owns 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...
80
        'FeaturedImage',
81
    ];
82
83
    /**
84
     * @var array
85
     */
86
    private static $many_many = [
0 ignored issues
show
Unused Code introduced by
The property $many_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...
87
        'Categories' => BlogCategory::class,
88
        'Tags'       => BlogTag::class,
89
        'Authors'    => Member::class
90
    ];
91
92
    /**
93
     * @var array
94
     */
95
    private static $defaults = [
0 ignored issues
show
Unused Code introduced by
The property $defaults 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
        'ShowInMenus'     => false,
97
        'InheritSideBar'  => true,
98
        'ProvideComments' => true
99
    ];
100
101
    /**
102
     * @var array
103
     */
104
    private static $extensions = [
0 ignored issues
show
Unused Code introduced by
The property $extensions 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
        BlogPostFilter::class
106
    ];
107
108
    /**
109
     * @var array
110
     */
111
    private static $searchable_fields = [
0 ignored issues
show
Unused Code introduced by
The property $searchable_fields 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...
112
        'Title'
113
    ];
114
115
    /**
116
     * @var array
117
     */
118
    private static $summary_fields = [
0 ignored issues
show
Unused Code introduced by
The property $summary_fields 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...
119
        'Title'
120
    ];
121
122
    /**
123
     * @var array
124
     */
125
    private static $casting = [
0 ignored issues
show
Unused Code introduced by
The property $casting 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...
126
        'Excerpt' => 'HTMLText',
127
        'Date' => 'DBDatetime'
128
    ];
129
130
    /**
131
     * @var array
132
     */
133
    private static $allowed_children = [];
0 ignored issues
show
Unused Code introduced by
The property $allowed_children 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...
134
135
    /**
136
     * The default sorting lists BlogPosts with an empty PublishDate at the top.
137
     *
138
     * @var string
139
     */
140
    private static $default_sort = '"PublishDate" IS NULL DESC, "PublishDate" DESC';
0 ignored issues
show
Unused Code introduced by
The property $default_sort 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...
141
142
    /**
143
     * @var bool
144
     */
145
    private static $can_be_root = false;
0 ignored issues
show
Unused Code introduced by
The property $can_be_root 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...
146
147
    /**
148
     * This will display or hide the current class from the SiteTree. This variable can be
149
     * configured using YAML.
150
     *
151
     * @var bool
152
     */
153
    private static $show_in_sitetree = false;
0 ignored issues
show
Unused Code introduced by
The property $show_in_sitetree 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...
154
155
    /**
156
     * Determine the role of the given member.
157
     *
158
     * Call be called via template to determine the current user.
159
     *
160
     * @example "Hello $RoleOf($CurrentMember.ID)"
161
     *
162
     * @param null|int|Member $member
163
     *
164
     * @return null|string
165
     */
166
    public function RoleOf($member = null)
167
    {
168
        $member = $this->getMember($member);
169
170
        if (!$member) {
171
            return null;
172
        }
173
174
        if ($this->isAuthor($member)) {
175
            return _t(__CLASS__ . '.AUTHOR', 'Author');
176
        }
177
178
        $parent = $this->Parent();
179
180
        if ($parent instanceof Blog) {
181
            return $parent->RoleOf($member);
182
        }
183
184
        return null;
185
    }
186
187
    /**
188
     * Determine if the given member is an author of this post.
189
     *
190
     * @param null|Member $member
191
     *
192
     * @return bool
193
     */
194 View Code Duplication
    public function isAuthor($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...
195
    {
196
        if (!$member || !$member->exists()) {
197
            return false;
198
        }
199
200
        $list = $this->Authors();
201
202
        if ($list instanceof UnsavedRelationList) {
203
            return in_array($member->ID, $list->getIDList());
204
        }
205
206
        return $list->byID($member->ID) !== null;
207
    }
208
209
    /**
210
     * {@inheritdoc}
211
     */
212
    public function getCMSFields()
213
    {
214
        $module = ModuleLoader::getModule('silverstripe/blog');
215
        Requirements::css($module->getRelativeResourcePath('css/cms.css'));
216
        Requirements::javascript($module->getRelativeResourcePath('js/cms.js'));
217
218
        $this->beforeUpdateCMSFields(function ($fields) {
219
            $uploadField = UploadField::create('FeaturedImage', _t(__CLASS__ . '.FeaturedImage', 'Featured Image'));
220
            $uploadField->getValidator()->setAllowedExtensions(['jpg', 'jpeg', 'png', 'gif']);
221
222
            /**
223
             * @var FieldList $fields
224
             */
225
            $fields->insertAfter($uploadField, 'Content');
226
227
            $summary = HtmlEditorField::create('Summary', false);
228
            $summary->setRows(5);
229
            $summary->setDescription(_t(
230
                __CLASS__ . '.SUMMARY_DESCRIPTION',
231
                'If no summary is specified the first 30 words will be used.'
232
            ));
233
234
            $summaryHolder = ToggleCompositeField::create(
235
                'CustomSummary',
236
                _t(__CLASS__ . '.CUSTOMSUMMARY', 'Add A Custom Summary'),
237
                [
238
                    $summary,
239
                ]
240
            );
241
            $summaryHolder->setHeadingLevel(4);
242
            $summaryHolder->addExtraClass('custom-summary');
243
244
            $fields->insertAfter($summaryHolder, 'FeaturedImage');
245
246
            $urlSegment = $fields->dataFieldByName('URLSegment');
247
            $urlSegment->setURLPrefix($this->Parent()->RelativeLink());
248
249
            $fields->removeFieldsFromTab('Root.Main', [
250
                'MenuTitle',
251
                'URLSegment',
252
            ]);
253
254
            $authorField = ListboxField::create(
255
                'Authors',
256
                _t(__CLASS__ . '.Authors', 'Authors'),
257
                $this->getCandidateAuthors()->map()->toArray()
258
            );
259
260
            $authorNames = TextField::create(
261
                'AuthorNames',
262
                _t(__CLASS__ . '.AdditionalCredits', 'Additional Credits'),
263
                null,
264
                1024
265
            )->setDescription(
266
                _t(
267
                    __CLASS__ . '.AdditionalCredits_Description',
268
                    'If some authors of this post don\'t have CMS access, enter their name(s) here. You can separate multiple names with a comma.'
269
                )
270
            );
271
272
            if (!$this->canEditAuthors()) {
273
                $authorField = $authorField->performDisabledTransformation();
274
                $authorNames = $authorNames->performDisabledTransformation();
275
            }
276
277
            $publishDate = DatetimeField::create('PublishDate', _t(__CLASS__ . '.PublishDate', 'Publish Date'));
278
279
            if (!$this->PublishDate) {
280
                $publishDate->setDescription(
281
                    _t(
282
                        __CLASS__ . '.PublishDate_Description',
283
                        'Will be set to "now" if published without a value.'
284
                    )
285
                );
286
            }
287
288
            // Get categories and tags
289
            $parent = $this->Parent();
290
            $categories = $parent instanceof Blog
291
                ? $parent->Categories()
292
                : BlogCategory::get();
293
            $tags = $parent instanceof Blog
294
                ? $parent->Tags()
295
                : BlogTag::get();
296
297
            // @todo: Reimplement the sidebar
298
            // $options = BlogAdminSidebar::create(
299
            $fields->addFieldsToTab(
300
                'Root.PostOptions',
301
                [
302
                    $publishDate,
303
                    $urlSegment,
304
                    TagField::create(
305
                        'Categories',
306
                        _t(__CLASS__ . '.Categories', 'Categories'),
307
                        $categories,
308
                        $this->Categories()
309
                    )
310
                        ->setCanCreate($this->canCreateCategories())
311
                        ->setShouldLazyLoad(true),
312
                    TagField::create(
313
                        'Tags',
314
                        _t(__CLASS__ . '.Tags', 'Tags'),
315
                        $tags,
316
                        $this->Tags()
317
                    )
318
                        ->setCanCreate($this->canCreateTags())
319
                        ->setShouldLazyLoad(true),
320
                    $authorField,
321
                    $authorNames
322
                ]
323
            );
324
            // )->setTitle('Post Options');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
325
            // $options->setName('blog-admin-sidebar');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
326
            // $fields->insertBefore($options, 'Root');
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
327
        });
328
329
        $fields = parent::getCMSFields();
330
331
        $fields->fieldByName('Root')->setTemplate('TabSet_holder');
332
333
        return $fields;
334
    }
335
336
    /**
337
     * Gets the list of author candidates to be assigned as authors of this blog post.
338
     *
339
     * @return SS_List
340
     */
341
    public function getCandidateAuthors()
342
    {
343
        if ($this->config()->get('restrict_authors_to_group')) {
344
            return Group::get()->filter('Code', $this->config()->get('restrict_authors_to_group'))->first()->Members();
345
        }
346
347
        $list = Member::get();
348
        $this->extend('updateCandidateAuthors', $list);
349
        return $list;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $list; (SilverStripe\ORM\DataList) is incompatible with the return type documented by SilverStripe\Blog\Model\...st::getCandidateAuthors of type SilverStripe\Blog\Model\SS_List.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
350
    }
351
352
    /**
353
     * Determine if this user can edit the authors list.
354
     *
355
     * @param null|int|Member $member
356
     *
357
     * @return bool
358
     */
359
    public function canEditAuthors($member = null)
360
    {
361
        $member = $this->getMember($member);
362
363
        $extended = $this->extendedCan('canEditAuthors', $member);
364
365
        if ($extended !== null) {
366
            return $extended;
367
        }
368
369
        $parent = $this->Parent();
370
371
        if ($parent instanceof Blog && $parent->exists()) {
372
            if ($parent->isEditor($member)) {
373
                return true;
374
            }
375
376
            if ($parent->isWriter($member) && $this->isAuthor($member)) {
377
                return true;
378
            }
379
        }
380
381
        return Permission::checkMember($member, Blog::MANAGE_USERS);
0 ignored issues
show
Bug Compatibility introduced by
The expression \SilverStripe\Security\P...el\Blog::MANAGE_USERS); of type boolean|string adds the type string to the return on line 381 which is incompatible with the return type documented by SilverStripe\Blog\Model\BlogPost::canEditAuthors of type boolean.
Loading history...
382
    }
383
384
    /**
385
     * @param null|int|Member $member
386
     *
387
     * @return null|Member
388
     */
389 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...
390
    {
391
        if (!$member) {
392
            $member = Security::getCurrentUser();
393
        }
394
395
        if (is_numeric($member)) {
396
            $member = Member::get()->byID($member);
397
        }
398
399
        return $member;
400
    }
401
402
    /**
403
     * Determine whether user can create new categories.
404
     *
405
     * @param null|int|Member $member
406
     *
407
     * @return bool
408
     */
409 View Code Duplication
    public function canCreateCategories($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...
410
    {
411
        $member = $this->getMember($member);
412
413
        $parent = $this->Parent();
414
415
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
416
            return false;
417
        }
418
419
        if ($parent->isEditor($member)) {
420
            return true;
421
        }
422
423
        return Permission::checkMember($member, 'ADMIN');
424
    }
425
426
    /**
427
     * Determine whether user can create new tags.
428
     *
429
     * @param null|int|Member $member
430
     *
431
     * @return bool
432
     */
433 View Code Duplication
    public function canCreateTags($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...
434
    {
435
        $member = $this->getMember($member);
436
437
        $parent = $this->Parent();
438
439
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
440
            return false;
441
        }
442
443
        if ($parent->isEditor($member)) {
444
            return true;
445
        }
446
447
        if ($parent->isWriter($member)) {
448
            return true;
449
        }
450
451
        return Permission::checkMember($member, 'ADMIN');
452
    }
453
454
    /**
455
     * {@inheritdoc}
456
     *
457
     * Update the PublishDate to now if the BlogPost would otherwise be published without a date.
458
     */
459
    public function onBeforePublish()
460
    {
461
        /**
462
         * @var DBDatetime $publishDate
463
         */
464
        $publishDate = $this->dbObject('PublishDate');
465
466
        if (!$publishDate->getValue()) {
467
            $this->PublishDate = DBDatetime::now()->getValue();
468
            $this->write();
469
        }
470
    }
471
472
    /**
473
     * {@inheritdoc}
474
     *
475
     * Sets blog relationship on all categories and tags assigned to this post.
476
     */
477
    public function onAfterWrite()
478
    {
479
        parent::onAfterWrite();
480
481
        foreach ($this->Categories() as $category) {
482
            /**
483
             * @var BlogCategory $category
484
             */
485
            $category->BlogID = $this->ParentID;
486
            $category->write();
487
        }
488
489
        foreach ($this->Tags() as $tag) {
490
            /**
491
             * @var BlogTag $tag
492
             */
493
            $tag->BlogID = $this->ParentID;
494
            $tag->write();
495
        }
496
    }
497
498
    /**
499
     * {@inheritdoc}
500
     */
501
    public function canView($member = null)
502
    {
503
        $member = $this->getMember($member);
504
505
        if (!parent::canView($member)) {
506
            return false;
507
        }
508
509
        if ($this->canEdit($member)) {
510
            return true;
511
        }
512
513
        // If on draft stage, user has permission to view draft, so show it
514
        if (Versioned::get_stage() === Versioned::DRAFT) {
515
            return true;
516
        }
517
518
        /**
519
         * @var DBDatetime $publishDate
520
         */
521
        $publishDate = $this->dbObject('PublishDate');
522
        if (!$publishDate->exists()) {
523
            return false;
524
        }
525
526
        return !$publishDate->InFuture();
527
    }
528
529
    /**
530
     * {@inheritdoc}
531
     */
532
    public function canPublish($member = null)
533
    {
534
        $member = $this->getMember($member);
535
536
        if (Permission::checkMember($member, 'ADMIN')) {
537
            return true;
538
        }
539
540
        $extended = $this->extendedCan('canPublish', $member);
541
542
        if ($extended !== null) {
543
            return $extended;
544
        }
545
546
        $parent = $this->Parent();
547
548
        if ($parent instanceof Blog && $parent->exists()) {
549
            if ($parent->isEditor($member)) {
550
                return true;
551
            }
552
553
            if ($parent->isWriter($member) && $this->isAuthor($member)) {
554
                return true;
555
            }
556
557
            if ($parent->isContributor($member)) {
558
                return parent::canEdit($member);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canEdit() instead of canPublish()). Are you sure this is correct? If so, you might want to change this to $this->canEdit().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
559
            }
560
        }
561
562
        return $this->canEdit($member);
563
    }
564
565
    /**
566
     * {@inheritdoc}
567
     */
568
    public function canEdit($member = null)
569
    {
570
        $member = $this->getMember($member);
571
572
        if (parent::canEdit($member)) {
573
            return true;
574
        }
575
576
        $parent = $this->Parent();
577
578
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
579
            return false;
580
        }
581
582
        if ($parent->isEditor($member)) {
583
            return true;
584
        }
585
586
        if (!$parent->isWriter($member) && !$parent->isContributor($member)) {
587
            return false;
588
        }
589
590
        return $this->isAuthor($member);
591
    }
592
593
    /**
594
     * Returns the post excerpt.
595
     *
596
     * @param int $wordsToDisplay
597
     *
598
     * @return string
599
     */
600
    public function Excerpt($wordsToDisplay = 30)
601
    {
602
        /** @var HTMLText $content */
603
        $content = $this->dbObject('Content');
604
605
        return $content->Summary($wordsToDisplay);
606
    }
607
608
    /**
609
     * Returns a monthly archive link for the current blog post.
610
     *
611
     * @param string $type
612
     *
613
     * @return string
614
     */
615
    public function getMonthlyArchiveLink($type = 'day')
616
    {
617
        /**
618
         * @var DBDatetime $date
619
         */
620
        $date = $this->dbObject('PublishDate');
621
622
        if ($type != 'year') {
623
            if ($type == 'day') {
624
                return Controller::join_links(
625
                    $this->Parent()->Link('archive'),
626
                    $date->format('Y'),
627
                    $date->format('m'),
628
                    $date->format('d')
629
                );
630
            }
631
632
            return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'), $date->format('m'));
633
        }
634
635
        return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'));
636
    }
637
638
    /**
639
     * Returns a yearly archive link for the current blog post.
640
     *
641
     * @return string
642
     */
643
    public function getYearlyArchiveLink()
644
    {
645
        /**
646
         * @var DBDatetime $date
647
         */
648
        $date = $this->dbObject('PublishDate');
649
650
        return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'));
651
    }
652
653
    /**
654
     * Resolves static and dynamic authors linked to this post.
655
     *
656
     * @return ArrayList
657
     */
658
    public function getCredits()
659
    {
660
        $list = ArrayList::create();
661
662
        $list->merge($this->getDynamicCredits());
663
        $list->merge($this->getStaticCredits());
664
665
        return $list->sort('Name');
666
    }
667
668
    /**
669
     * Resolves dynamic authors linked to this post.
670
     *
671
     * @return ArrayList
672
     */
673
    protected function getDynamicCredits()
674
    {
675
        // Find best page to host user profiles
676
        $parent = $this->Parent();
677
        if (! ($parent instanceof Blog)) {
678
            $parent = Blog::get()->first();
679
        }
680
681
        // If there is no parent blog, return list undecorated
682
        if (!$parent) {
683
            $items = $this->Authors()->toArray();
684
            return ArrayList::create($items);
685
        }
686
687
        // Update all authors
688
        $items = ArrayList::create();
689
        foreach ($this->Authors() as $author) {
690
            // Add link for each author
691
            $author = $author->customise([
692
                'URL' => $parent->ProfileLink($author->URLSegment),
693
            ]);
694
            $items->push($author);
695
        }
696
697
        return $items;
698
    }
699
700
    /**
701
     * Resolves static authors linked to this post.
702
     *
703
     * @return ArrayList
704
     */
705
    protected function getStaticCredits()
706
    {
707
        $items = ArrayList::create();
708
709
        $authors = array_filter(preg_split('/\s*,\s*/', $this->AuthorNames));
710
711
        foreach ($authors as $author) {
712
            $item = ArrayData::create([
713
                'Name' => $author,
714
            ]);
715
716
            $items->push($item);
717
        }
718
719
        return $items;
720
    }
721
722
    /**
723
     * Checks to see if User Profiles has been disabled via config
724
     *
725
     * @return bool
726
     */
727
    public function getProfilesDisabled()
728
    {
729
        return Config::inst()->get(BlogController::class, 'disable_profiles');
730
    }
731
732
    /**
733
     * Sets the label for BlogPost.Title to 'Post Title' (Rather than 'Page name').
734
     *
735
     * @param bool $includeRelations
736
     *
737
     * @return array
738
     */
739
    public function fieldLabels($includeRelations = true)
740
    {
741
        $labels = parent::fieldLabels($includeRelations);
742
743
        $labels['Title'] = _t(__CLASS__ . '.PageTitleLabel', 'Post Title');
744
745
        return $labels;
746
    }
747
748
    /**
749
     * Proxy method for displaying the publish date in rss feeds.
750
     * @see https://github.com/silverstripe/silverstripe-blog/issues/394
751
     *
752
     * @return string|null
753
     */
754
    public function getDate()
755
    {
756
        if ($this->hasDatabaseField('Date')) {
757
            return $this->getField('Date');
758
        }
759
        return !empty($this->PublishDate) ? $this->PublishDate : null;
760
    }
761
762
    /**
763
     * {@inheritdoc}
764
     */
765
    protected function onBeforeWrite()
766
    {
767
        parent::onBeforeWrite();
768
769
        if (!$this->exists() && ($member = Security::getCurrentUser())) {
770
            $this->Authors()->add($member);
771
        }
772
    }
773
}
774