Completed
Pull Request — master (#421)
by Robbie
02:31
created

BlogPost::getStaticCredits()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 0
1
<?php
2
3
namespace SilverStripe\Blog\Model;
4
5
use Page;
6
use SilverStripe\Blog\Forms\BlogAdminSidebar;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Forms\DatetimeField;
9
use SilverStripe\Forms\HiddenField;
10
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
11
use SilverStripe\Forms\ListboxField;
12
use SilverStripe\Forms\TextField;
13
use SilverStripe\Forms\ToggleCompositeField;
14
use SilverStripe\Forms\UploadField;
15
use SilverStripe\ORM\ArrayList;
16
use SilverStripe\ORM\FieldType\DBDatetime;
17
use SilverStripe\ORM\UnsavedRelationList;
18
use SilverStripe\Security\Group;
19
use SilverStripe\Security\Member;
20
use SilverStripe\Security\Permission;
21
use SilverStripe\TagField\TagField;
22
use SilverStripe\View\ArrayData;
23
use SilverStripe\View\Requirements;
24
25
/**
26
 * An individual blog post.
27
 *
28
 * @package silverstripe
29
 * @subpackage blog
30
 *
31
 * @method ManyManyList Categories()
32
 * @method ManyManyList Tags()
33
 * @method ManyManyList Authors()
34
 * @method Blog Parent()
35
 *
36
 * @property string $PublishDate
37
 * @property string $AuthorNames
38
 * @property int $ParentID
39
 */
40
class BlogPost extends Page
41
{
42
    /**
43
     * Same as above, but for list of users that can be
44
     * given credit in the author field for blog posts
45
     * @var string|bool false or group code
46
     */
47
    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...
48
49
    /**
50
     * {@inheritDoc}
51
     * @var string
52
     */
53
    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...
54
55
    /**
56
     * @var array
57
     */
58
    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...
59
        'PublishDate' => 'Datetime',
60
        'AuthorNames' => 'Varchar(1024)',
61
        'Summary'     => 'HTMLText'
62
    );
63
64
    /**
65
     * @var array
66
     */
67
    private static $has_one = array(
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...
68
        'FeaturedImage' => 'SilverStripe\\Assets\\Image'
69
    );
70
71
    /**
72
     * @var array
73
     */
74
    private static $many_many = array(
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...
75
        'Categories' => 'SilverStripe\\Blog\\Model\\BlogCategory',
76
        'Tags'       => 'SilverStripe\\Blog\\Model\\BlogTag',
77
        'Authors'    => Member::class
78
    );
79
80
    /**
81
     * @var array
82
     */
83
    private static $defaults = array(
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...
84
        'ShowInMenus'     => false,
85
        'InheritSideBar'  => true,
86
        'ProvideComments' => true
87
    );
88
89
    /**
90
     * @var array
91
     */
92
    private static $extensions = array(
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...
93
        'SilverStripe\\Blog\\Model\\BlogPostFilter'
94
    );
95
96
    /**
97
     * @var array
98
     */
99
    private static $searchable_fields = array(
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...
100
        'Title'
101
    );
102
103
    /**
104
     * @var array
105
     */
106
    private static $summary_fields = array(
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...
107
        'Title'
108
    );
109
110
    /**
111
     * @var array
112
     */
113
    private static $casting = array(
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...
114
        'Excerpt' => 'HTMLText',
115
        'Date' => 'DBDatetime'
116
    );
117
118
    /**
119
     * @var array
120
     */
121
    private static $allowed_children = array();
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...
122
123
    /**
124
     * The default sorting lists BlogPosts with an empty PublishDate at the top.
125
     *
126
     * @var string
127
     */
128
    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...
129
130
    /**
131
     * @var bool
132
     */
133
    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...
134
135
    /**
136
     * This will display or hide the current class from the SiteTree. This variable can be
137
     * configured using YAML.
138
     *
139
     * @var bool
140
     */
141
    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...
142
143
    /**
144
     * Determine the role of the given member.
145
     *
146
     * Call be called via template to determine the current user.
147
     *
148
     * @example "Hello $RoleOf($CurrentMember.ID)"
149
     *
150
     * @param null|int|Member $member
151
     *
152
     * @return null|string
153
     */
154
    public function RoleOf($member = null)
155
    {
156
        $member = $this->getMember($member);
157
158
        if (!$member) {
159
            return null;
160
        }
161
162
        if ($this->isAuthor($member)) {
163
            return _t('BlogPost.AUTHOR', 'Author');
164
        }
165
166
        $parent = $this->Parent();
167
168
        if ($parent instanceof Blog) {
169
            return $parent->RoleOf($member);
170
        }
171
172
        return null;
173
    }
174
175
    /**
176
     * Determine if the given member is an author of this post.
177
     *
178
     * @param null|Member $member
179
     *
180
     * @return bool
181
     */
182 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...
183
    {
184
        if (!$member || !$member->exists()) {
185
            return false;
186
        }
187
188
        $list = $this->Authors();
189
190
        if ($list instanceof UnsavedRelationList) {
191
            return in_array($member->ID, $list->getIDList());
192
        }
193
194
        return $list->byID($member->ID) !== null;
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function getCMSFields()
201
    {
202
        Requirements::css(BLOGGER_DIR . '/css/cms.css');
203
        Requirements::javascript(BLOGGER_DIR . '/js/cms.js');
204
205
        $this->beforeUpdateCMSFields(function ($fields) {
206
            $uploadField = UploadField::create('FeaturedImage', _t('BlogPost.FeaturedImage', 'Featured Image'));
207
            $uploadField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif'));
208
209
            /**
210
             * @var FieldList $fields
211
             */
212
            $fields->insertAfter($uploadField, 'Content');
213
214
            $summary = HtmlEditorField::create('Summary', false);
215
            $summary->setRows(5);
216
            $summary->setDescription(_t(
217
                'BlogPost.SUMMARY_DESCRIPTION',
218
                'If no summary is specified the first 30 words will be used.'
219
            ));
220
221
            $summaryHolder = ToggleCompositeField::create(
222
                'CustomSummary',
223
                _t('BlogPost.CUSTOMSUMMARY', 'Add A Custom Summary'),
224
                array(
225
                    $summary,
226
                )
227
            );
228
            $summaryHolder->setHeadingLevel(4);
229
            $summaryHolder->addExtraClass('custom-summary');
230
231
            $fields->insertAfter($summaryHolder, 'FeaturedImage');
232
233
            $urlSegment = $fields->dataFieldByName('URLSegment');
234
            $urlSegment->setURLPrefix($this->Parent()->RelativeLink());
235
236
            $fields->removeFieldsFromTab('Root.Main', array(
237
                'MenuTitle',
238
                'URLSegment',
239
            ));
240
241
            $authorField = ListboxField::create(
242
                'Authors',
243
                _t('BlogPost.Authors', 'Authors'),
244
                $this->getCandidateAuthors()->map()->toArray()
245
            );
246
247
            $authorNames = TextField::create(
248
                'AuthorNames',
249
                _t('BlogPost.AdditionalCredits', 'Additional Credits'),
250
                null,
251
                1024
252
            )->setDescription(
253
                _t(
254
                    'BlogPost.AdditionalCredits_Description',
255
                    'If some authors of this post don\'t have CMS access, enter their name(s) here. You can separate multiple names with a comma.'
256
                )
257
            );
258
259
            if (!$this->canEditAuthors()) {
260
                $authorField = $authorField->performDisabledTransformation();
261
                $authorNames = $authorNames->performDisabledTransformation();
262
            }
263
264
            $publishDate = DatetimeField::create('PublishDate', _t('BlogPost.PublishDate', 'Publish Date'));
265
            $publishDate->getDateField()->setConfig('showcalendar', true);
266
            if (!$this->PublishDate) {
267
                $publishDate->setDescription(
268
                    _t(
269
                        'BlogPost.PublishDate_Description',
270
                        'Will be set to "now" if published without a value.'
271
                    )
272
                );
273
            }
274
275
            // Get categories and tags
276
            $parent = $this->Parent();
277
            $categories = $parent instanceof Blog
278
                ? $parent->Categories()
279
                : BlogCategory::get();
280
            $tags = $parent instanceof Blog
281
                ? $parent->Tags()
282
                : BlogTag::get();
283
284
            // @todo: Reimplement the sidebar
285
            // $options = BlogAdminSidebar::create(
286
            $fields->addFieldsToTab(
287
                'Root.PostOptions',
288
                [
289
                    $publishDate,
290
                    $urlSegment,
291
                    TagField::create(
292
                        'Categories',
293
                        _t('BlogPost.Categories', 'Categories'),
294
                        $categories,
295
                        $this->Categories()
296
                    )
297
                        ->setCanCreate($this->canCreateCategories())
298
                        ->setShouldLazyLoad(true),
299
                    TagField::create(
300
                        'Tags',
301
                        _t('BlogPost.Tags', 'Tags'),
302
                        $tags,
303
                        $this->Tags()
304
                    )
305
                        ->setCanCreate($this->canCreateTags())
306
                        ->setShouldLazyLoad(true),
307
                    $authorField,
308
                    $authorNames
309
                ]
310
            );
311
            // )->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...
312
            // $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...
313
            // $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...
314
        });
315
316
        $fields = parent::getCMSFields();
317
318
        $fields->fieldByName('Root')->setTemplate('TabSet_holder');
319
320
        return $fields;
321
    }
322
323
    /**
324
     * Gets the list of author candidates to be assigned as authors of this blog post.
325
     *
326
     * @return SS_List
327
     */
328
    public function getCandidateAuthors()
329
    {
330
        if ($this->config()->restrict_authors_to_group) {
331
            return Group::get()->filter('Code', $this->config()->restrict_authors_to_group)->first()->Members();
332
        }
333
334
        $list = Member::get();
335
        $this->extend('updateCandidateAuthors', $list);
336
        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...
337
    }
338
339
    /**
340
     * Determine if this user can edit the authors list.
341
     *
342
     * @param null|int|Member $member
343
     *
344
     * @return bool
345
     */
346
    public function canEditAuthors($member = null)
347
    {
348
        $member = $this->getMember($member);
349
350
        $extended = $this->extendedCan('canEditAuthors', $member);
351
352
        if ($extended !== null) {
353
            return $extended;
354
        }
355
356
        $parent = $this->Parent();
357
358
        if ($parent instanceof Blog && $parent->exists()) {
359
            if ($parent->isEditor($member)) {
360
                return true;
361
            }
362
363
            if ($parent->isWriter($member) && $this->isAuthor($member)) {
364
                return true;
365
            }
366
        }
367
368
        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 368 which is incompatible with the return type documented by SilverStripe\Blog\Model\BlogPost::canEditAuthors of type boolean.
Loading history...
369
    }
370
371
    /**
372
     * @param null|int|Member $member
373
     *
374
     * @return null|Member
375
     */
376 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...
377
    {
378
        if (!$member) {
379
            $member = Member::currentUser();
380
        }
381
382
        if (is_numeric($member)) {
383
            $member = Member::get()->byID($member);
384
        }
385
386
        return $member;
387
    }
388
389
    /**
390
     * Determine whether user can create new categories.
391
     *
392
     * @param null|int|Member $member
393
     *
394
     * @return bool
395
     */
396 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...
397
    {
398
        $member = $this->getMember($member);
399
400
        $parent = $this->Parent();
401
402
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
403
            return false;
404
        }
405
406
        if ($parent->isEditor($member)) {
407
            return true;
408
        }
409
410
        return Permission::checkMember($member, 'ADMIN');
411
    }
412
413
    /**
414
     * Determine whether user can create new tags.
415
     *
416
     * @param null|int|Member $member
417
     *
418
     * @return bool
419
     */
420 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...
421
    {
422
        $member = $this->getMember($member);
423
424
        $parent = $this->Parent();
425
426
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
427
            return false;
428
        }
429
430
        if ($parent->isEditor($member)) {
431
            return true;
432
        }
433
434
        if ($parent->isWriter($member)) {
435
            return true;
436
        }
437
438
        return Permission::checkMember($member, 'ADMIN');
439
    }
440
441
    /**
442
     * {@inheritdoc}
443
     *
444
     * Update the PublishDate to now if the BlogPost would otherwise be published without a date.
445
     */
446
    public function onBeforePublish()
447
    {
448
        /**
449
         * @var DBDatetime $publishDate
450
         */
451
        $publishDate = $this->dbObject('PublishDate');
452
453
        if (!$publishDate->getValue()) {
454
            $this->PublishDate = DBDatetime::now()->getValue();
455
            $this->write();
456
        }
457
    }
458
459
    /**
460
     * {@inheritdoc}
461
     *
462
     * Sets blog relationship on all categories and tags assigned to this post.
463
     */
464
    public function onAfterWrite()
465
    {
466
        parent::onAfterWrite();
467
468
        foreach ($this->Categories() as $category) {
469
            /**
470
             * @var BlogCategory $category
471
             */
472
            $category->BlogID = $this->ParentID;
473
            $category->write();
474
        }
475
476
        foreach ($this->Tags() as $tag) {
477
            /**
478
             * @var BlogTag $tag
479
             */
480
            $tag->BlogID = $this->ParentID;
481
            $tag->write();
482
        }
483
    }
484
485
    /**
486
     * {@inheritdoc}
487
     */
488
    public function canView($member = null)
489
    {
490
        $member = $this->getMember($member);
491
492
        if (!parent::canView($member)) {
493
            return false;
494
        }
495
496
        if ($this->canEdit($member)) {
497
            return true;
498
        }
499
500
        /**
501
         * @var DBDatetime $publishDate
502
         */
503
        $publishDate = $this->dbObject('PublishDate');
504
        if (!$publishDate->exists()) {
505
            return false;
506
        }
507
508
        return !$publishDate->InFuture();
509
    }
510
511
    /**
512
     * {@inheritdoc}
513
     */
514
    public function canPublish($member = null)
515
    {
516
        $member = $this->getMember($member);
517
518
        if (Permission::checkMember($member, 'ADMIN')) {
519
            return true;
520
        }
521
522
        $extended = $this->extendedCan('canPublish', $member);
523
524
        if ($extended !== null) {
525
            return $extended;
526
        }
527
528
        $parent = $this->Parent();
529
530
        if ($parent instanceof Blog && $parent->exists()) {
531
            if ($parent->isEditor($member)) {
532
                return true;
533
            }
534
535
            if ($parent->isWriter($member) && $this->isAuthor($member)) {
536
                return true;
537
            }
538
539
            if ($parent->isContributor($member)) {
540
                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...
541
            }
542
        }
543
544
        return $this->canEdit($member);
545
    }
546
547
    /**
548
     * {@inheritdoc}
549
     */
550
    public function canEdit($member = null)
551
    {
552
        $member = $this->getMember($member);
553
554
        if (parent::canEdit($member)) {
555
            return true;
556
        }
557
558
        $parent = $this->Parent();
559
560
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
561
            return false;
562
        }
563
564
        if ($parent->isEditor($member)) {
565
            return true;
566
        }
567
568
        if (!$parent->isWriter($member) && !$parent->isContributor($member)) {
569
            return false;
570
        }
571
572
        return $this->isAuthor($member);
573
    }
574
575
    /**
576
     * Returns the post excerpt.
577
     *
578
     * @param int $wordsToDisplay
579
     *
580
     * @return string
581
     */
582
    public function Excerpt($wordsToDisplay = 30)
583
    {
584
        /** @var HTMLText $content */
585
        $content = $this->dbObject('Content');
586
587
        return $content->Summary($wordsToDisplay);
588
    }
589
590
    /**
591
     * Returns a monthly archive link for the current blog post.
592
     *
593
     * @param string $type
594
     *
595
     * @return string
596
     */
597
    public function getMonthlyArchiveLink($type = 'day')
598
    {
599
        /**
600
         * @var DBDatetime $date
601
         */
602
        $date = $this->dbObject('PublishDate');
603
604
        if ($type != 'year') {
605
            if ($type == 'day') {
606
                return Controller::join_links(
607
                    $this->Parent()->Link('archive'),
608
                    $date->format('Y'),
609
                    $date->format('m'),
610
                    $date->format('d')
611
                );
612
            }
613
614
            return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'), $date->format('m'));
615
        }
616
617
        return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'));
618
    }
619
620
    /**
621
     * Returns a yearly archive link for the current blog post.
622
     *
623
     * @return string
624
     */
625
    public function getYearlyArchiveLink()
626
    {
627
        /**
628
         * @var DBDatetime $date
629
         */
630
        $date = $this->dbObject('PublishDate');
631
632
        return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'));
633
    }
634
635
    /**
636
     * Resolves static and dynamic authors linked to this post.
637
     *
638
     * @return ArrayList
639
     */
640
    public function getCredits()
641
    {
642
        $list = ArrayList::create();
643
644
        $list->merge($this->getDynamicCredits());
645
        $list->merge($this->getStaticCredits());
646
647
        return $list->sort('Name');
648
    }
649
650
    /**
651
     * Resolves dynamic authors linked to this post.
652
     *
653
     * @return ArrayList
654
     */
655
    protected function getDynamicCredits()
656
    {
657
        // Find best page to host user profiles
658
        $parent = $this->Parent();
659
        if (! ($parent instanceof Blog)) {
660
            $parent = Blog::get()->first();
661
        }
662
663
        // If there is no parent blog, return list undecorated
664
        if (!$parent) {
665
            $items = $this->Authors()->toArray();
666
            return new ArrayList($items);
667
        }
668
669
        // Update all authors
670
        $items = new ArrayList();
671
        foreach ($this->Authors() as $author) {
672
            // Add link for each author
673
            $author = $author->customise(array(
674
                'URL' => $parent->ProfileLink($author->URLSegment),
675
            ));
676
            $items->push($author);
677
        }
678
679
        return $items;
680
    }
681
682
    /**
683
     * Resolves static authors linked to this post.
684
     *
685
     * @return ArrayList
686
     */
687
    protected function getStaticCredits()
688
    {
689
        $items = new ArrayList();
690
691
        $authors = array_filter(preg_split('/\s*,\s*/', $this->AuthorNames));
692
693
        foreach ($authors as $author) {
694
            $item = new ArrayData(array(
695
                'Name' => $author,
696
            ));
697
698
            $items->push($item);
699
        }
700
701
        return $items;
702
    }
703
704
    /**
705
     * Sets the label for BlogPost.Title to 'Post Title' (Rather than 'Page name').
706
     *
707
     * @param bool $includeRelations
708
     *
709
     * @return array
710
     */
711
    public function fieldLabels($includeRelations = true)
712
    {
713
        $labels = parent::fieldLabels($includeRelations);
714
715
        $labels['Title'] = _t('BlogPost.PageTitleLabel', 'Post Title');
716
717
        return $labels;
718
    }
719
720
    /**
721
     * Proxy method for displaying the publish date in rss feeds.
722
     * @see https://github.com/silverstripe/silverstripe-blog/issues/394
723
     *
724
     * @return string|null
725
     */
726
    public function getDate()
727
    {
728
        return !empty($this->PublishDate) ? $this->PublishDate : null;
729
    }
730
731
    /**
732
     * {@inheritdoc}
733
     */
734
    protected function onBeforeWrite()
735
    {
736
        parent::onBeforeWrite();
737
738
        if (!$this->exists() && ($member = Member::currentUser())) {
739
            $this->Authors()->add($member);
740
        }
741
    }
742
}
743