Completed
Push — master ( 17429c...067f41 )
by Damian
02:18
created

code/model/BlogPost.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * An individual blog post.
5
 *
6
 * @package silverstripe
7
 * @subpackage blog
8
 *
9
 * @method ManyManyList Categories()
10
 * @method ManyManyList Tags()
11
 * @method ManyManyList Authors()
12
 * @method Blog Parent()
13
 *
14
 * @property string $PublishDate
15
 * @property string $AuthorNames
16
 * @property int $ParentID
17
 */
18
class BlogPost extends Page
19
{
20
    /**
21
     * Same as above, but for list of users that can be
22
     * given credit in the author field for blog posts
23
     * @var string|bool false or group code
24
     */
25
    private static $restrict_authors_to_group = false;
26
27
    /**
28
     * @var array
29
     */
30
    private static $db = array(
31
        'PublishDate' => 'SS_Datetime',
32
        'AuthorNames' => 'Varchar(1024)',
33
        'Summary' => 'HTMLText',
34
    );
35
36
    /**
37
     * @var array
38
     */
39
    private static $has_one = array(
40
        'FeaturedImage' => 'Image',
41
    );
42
43
    /**
44
     * @var array
45
     */
46
    private static $many_many = array(
47
        'Categories' => 'BlogCategory',
48
        'Tags' => 'BlogTag',
49
        'Authors' => 'Member',
50
    );
51
52
    /**
53
     * @var array
54
     */
55
    private static $defaults = array(
56
        'ShowInMenus' => false,
57
        'InheritSideBar' => true,
58
        'ProvideComments' => true,
59
    );
60
61
    /**
62
     * @var array
63
     */
64
    private static $extensions = array(
65
        'BlogPostFilter',
66
    );
67
68
    /**
69
     * @var array
70
     */
71
    private static $searchable_fields = array(
72
        'Title',
73
    );
74
75
    /**
76
     * @var array
77
     */
78
    private static $summary_fields = array(
79
        'Title',
80
    );
81
82
    /**
83
     * @var array
84
     */
85
    private static $casting = array(
86
        'Excerpt' => 'Text',
87
    );
88
89
    /**
90
     * @var array
91
     */
92
    private static $allowed_children = array();
93
94
    /**
95
     * The default sorting lists BlogPosts with an empty PublishDate at the top.
96
     *
97
     * @var string
98
     */
99
    private static $default_sort = '"PublishDate" IS NULL DESC, "PublishDate" DESC';
100
101
    /**
102
     * @var bool
103
     */
104
    private static $can_be_root = false;
105
106
    /**
107
     * This will display or hide the current class from the SiteTree. This variable can be
108
     * configured using YAML.
109
     *
110
     * @var bool
111
     */
112
    private static $show_in_sitetree = false;
113
114
    /**
115
     * Determine the role of the given member.
116
     *
117
     * Call be called via template to determine the current user.
118
     *
119
     * @example "Hello $RoleOf($CurrentMember.ID)"
120
     *
121
     * @param null|int|Member $member
122
     *
123
     * @return null|string
124
     */
125
    public function RoleOf($member = null)
126
    {
127
        $member = $this->getMember($member);
128
129
        if (!$member) {
130
            return null;
131
        }
132
133
        if ($this->isAuthor($member)) {
134
            return _t('BlogPost.AUTHOR', 'Author');
135
        }
136
137
        $parent = $this->Parent();
138
139
        if ($parent instanceof Blog) {
140
            return $parent->RoleOf($member);
141
        }
142
143
        return null;
144
    }
145
146
    /**
147
     * Determine if the given member is an author of this post.
148
     *
149
     * @param null|Member $member
150
     *
151
     * @return bool
152
     */
153 View Code Duplication
    public function isAuthor($member = null)
154
    {
155
        if (!$member || !$member->exists()) {
156
            return false;
157
        }
158
159
        $list = $this->Authors();
160
161
        if ($list instanceof UnsavedRelationList) {
162
            return in_array($member->ID, $list->getIDList());
163
        }
164
165
        return $list->byID($member->ID) !== null;
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171
    public function getCMSFields()
172
    {
173
        Requirements::css(BLOGGER_DIR . '/css/cms.css');
174
        Requirements::javascript(BLOGGER_DIR . '/js/cms.js');
175
176
        $self =& $this;
177
178
        $this->beforeUpdateCMSFields(function ($fields) use ($self) {
179
            $uploadField = UploadField::create('FeaturedImage', _t('BlogPost.FeaturedImage', 'Featured Image'));
180
            $uploadField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif'));
181
182
            /**
183
             * @var FieldList $fields
184
             */
185
            $fields->insertAfter($uploadField, 'Content');
186
187
            $summary = HtmlEditorField::create('Summary', false);
188
            $summary->setRows(5);
189
            $summary->setDescription(_t(
190
                'BlogPost.SUMMARY_DESCRIPTION',
191
                'If no summary is specified the first 30 words will be used.'
192
            ));
193
194
            $summaryHolder = ToggleCompositeField::create(
195
                'CustomSummary',
196
                _t('BlogPost.CUSTOMSUMMARY', 'Add A Custom Summary'),
197
                array(
198
                    $summary,
199
                )
200
            );
201
            $summaryHolder->setHeadingLevel(4);
202
            $summaryHolder->addExtraClass('custom-summary');
203
204
            $fields->insertAfter($summaryHolder, 'FeaturedImage');
205
206
            $fields->push(HiddenField::create('MenuTitle'));
207
208
            $urlSegment = $fields->dataFieldByName('URLSegment');
209
            $urlSegment->setURLPrefix($self->Parent()->RelativeLink());
210
211
            $fields->removeFieldsFromTab('Root.Main', array(
212
                'MenuTitle',
213
                'URLSegment',
214
            ));
215
216
            $authorField = ListboxField::create(
217
                'Authors',
218
                _t('BlogPost.Authors', 'Authors'),
219
                $self->getCandidateAuthors()->map()->toArray()
220
            )->setMultiple(true);
221
222
            $authorNames = TextField::create(
223
                'AuthorNames',
224
                _t('BlogPost.AdditionalCredits', 'Additional Credits'),
225
                null,
226
                1024
227
            )->setDescription(_t(
228
                    'BlogPost.AdditionalCredits_Description',
229
                    'If some authors of this post don\'t have CMS access, enter their name(s) here. You can separate multiple names with a comma.')
230
            );
231
232
            if (!$self->canEditAuthors()) {
233
                $authorField = $authorField->performDisabledTransformation();
234
                $authorNames = $authorNames->performDisabledTransformation();
235
            }
236
237
            $publishDate = DatetimeField::create('PublishDate', _t('BlogPost.PublishDate', 'Publish Date'));
238
            $publishDate->getDateField()->setConfig('showcalendar', true);
239
            if (!$self->PublishDate) {
240
                $publishDate->setDescription(_t(
241
                        'BlogPost.PublishDate_Description',
242
                        'Will be set to "now" if published without a value.')
243
                );
244
            }
245
246
            // Get categories and tags
247
            $parent = $self->Parent();
248
            $categories = $parent instanceof Blog
249
                ? $parent->Categories()
250
                : BlogCategory::get();
251
            $tags = $parent instanceof Blog
252
                ? $parent->Tags()
253
                : BlogTag::get();
254
255
            $options = BlogAdminSidebar::create(
256
                $publishDate,
257
                $urlSegment,
258
                TagField::create(
259
                    'Categories',
260
                    _t('BlogPost.Categories', 'Categories'),
261
                    $categories,
262
                    $self->Categories()
263
                )
264
                    ->setCanCreate($self->canCreateCategories())
265
                    ->setShouldLazyLoad(true),
266
                TagField::create(
267
                    'Tags',
268
                    _t('BlogPost.Tags', 'Tags'),
269
                    $tags,
270
                    $self->Tags()
271
                )
272
                    ->setCanCreate($self->canCreateTags())
273
                    ->setShouldLazyLoad(true),
274
                $authorField,
275
                $authorNames
276
            )->setTitle('Post Options');
277
278
            $options->setName('blog-admin-sidebar');
279
280
            $fields->insertBefore($options, 'Root');
281
        });
282
283
        $fields = parent::getCMSFields();
284
285
        $fields->fieldByName('Root')->setTemplate('TabSet_holder');
286
287
        return $fields;
288
    }
289
290
    /**
291
     * Gets the list of author candidates to be assigned as authors of this blog post.
292
     *
293
     * @return SS_List
294
     */
295
    public function getCandidateAuthors()
296
    {
297
        if ($this->config()->restrict_authors_to_group) {
298
            return Group::get()->filter('Code', $this->config()->restrict_authors_to_group)->first()->Members();
299
        } else {
300
            $list = Member::get();
301
            $this->extend('updateCandidateAuthors', $list);
302
            return $list;
303
        }
304
    }
305
306
    /**
307
     * Determine if this user can edit the authors list.
308
     *
309
     * @param null|int|Member $member
310
     *
311
     * @return bool
312
     */
313
    public function canEditAuthors($member = null)
314
    {
315
        $member = $this->getMember($member);
316
317
        $extended = $this->extendedCan('canEditAuthors', $member);
318
319
        if ($extended !== null) {
320
            return $extended;
321
        }
322
323
        $parent = $this->Parent();
324
325
        if ($parent instanceof Blog && $parent->exists()) {
326
            if ($parent->isEditor($member)) {
327
                return true;
328
            }
329
330
            if ($parent->isWriter($member) && $this->isAuthor($member)) {
331
                return true;
332
            }
333
        }
334
335
        return Permission::checkMember($member, Blog::MANAGE_USERS);
336
    }
337
338
    /**
339
     * @param null|int|Member $member
340
     *
341
     * @return null|Member
342
     */
343 View Code Duplication
    protected function getMember($member = null)
344
    {
345
        if (!$member) {
346
            $member = Member::currentUser();
347
        }
348
349
        if (is_numeric($member)) {
350
            $member = Member::get()->byID($member);
351
        }
352
353
        return $member;
354
    }
355
356
    /**
357
     * Determine whether user can create new categories.
358
     *
359
     * @param null|int|Member $member
360
     *
361
     * @return bool
362
     */
363 View Code Duplication
    public function canCreateCategories($member = null)
364
    {
365
        $member = $this->getMember($member);
366
367
        $parent = $this->Parent();
368
369
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
370
            return false;
371
        }
372
373
        if ($parent->isEditor($member)) {
374
            return true;
375
        }
376
377
        return Permission::checkMember($member, 'ADMIN');
378
    }
379
380
    /**
381
     * Determine whether user can create new tags.
382
     *
383
     * @param null|int|Member $member
384
     *
385
     * @return bool
386
     */
387 View Code Duplication
    public function canCreateTags($member = null)
388
    {
389
        $member = $this->getMember($member);
390
391
        $parent = $this->Parent();
392
393
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
394
            return false;
395
        }
396
397
        if ($parent->isEditor($member)) {
398
            return true;
399
        }
400
401
        if ($parent->isWriter($member)) {
402
            return true;
403
        }
404
405
        return Permission::checkMember($member, 'ADMIN');
406
    }
407
408
    /**
409
     * {@inheritdoc}
410
     *
411
     * Update the PublishDate to now if the BlogPost would otherwise be published without a date.
412
     */
413
    public function onBeforePublish()
414
    {
415
        /**
416
         * @var SS_Datetime $publishDate
417
         */
418
        $publishDate = $this->dbObject('PublishDate');
419
420
        if (!$publishDate->getValue()) {
421
            $this->PublishDate = SS_Datetime::now()->getValue();
422
            $this->write();
423
        }
424
    }
425
426
    /**
427
     * {@inheritdoc}
428
     *
429
     * Sets blog relationship on all categories and tags assigned to this post.
430
     */
431
    public function onAfterWrite()
432
    {
433
        parent::onAfterWrite();
434
435
        foreach ($this->Categories() as $category) {
436
            /**
437
             * @var BlogCategory $category
438
             */
439
            $category->BlogID = $this->ParentID;
440
            $category->write();
441
        }
442
443
        foreach ($this->Tags() as $tag) {
444
            /**
445
             * @var BlogTag $tag
446
             */
447
            $tag->BlogID = $this->ParentID;
448
            $tag->write();
449
        }
450
    }
451
452
    /**
453
     * {@inheritdoc}
454
     */
455 View Code Duplication
    public function canView($member = null)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
456
    {
457
        $member = $this->getMember($member);
458
459
        if (!parent::canView($member)) {
460
            return false;
461
        }
462
463
        /**
464
         * @var SS_Datetime $publishDate
465
         */
466
        $publishDate = $this->dbObject('PublishDate');
467
468
        // Show past posts
469
        if (!$publishDate->exists() || !$publishDate->InFuture()) {
470
            return true;
471
        }
472
473
        // Anyone that can edit this page can view it
474
        return $this->canEdit($member);
475
    }
476
477
    /**
478
     * {@inheritdoc}
479
     */
480
    public function canPublish($member = null)
481
    {
482
        $member = $this->getMember($member);
483
484
        if (Permission::checkMember($member, 'ADMIN')) {
485
            return true;
486
        }
487
488
        $extended = $this->extendedCan('canPublish', $member);
489
490
        if ($extended !== null) {
491
            return $extended;
492
        }
493
494
        $parent = $this->Parent();
495
496
        if ($parent instanceof Blog && $parent->exists()) {
497
            if ($parent->isEditor($member)) {
498
                return true;
499
            }
500
501
            if ($parent->isWriter($member) && $this->isAuthor($member)) {
502
                return true;
503
            }
504
505
            if ($parent->isContributor($member)) {
506
                return parent::canEdit($member);
507
            }
508
        }
509
510
        return $this->canEdit($member);
511
    }
512
513
    /**
514
     * {@inheritdoc}
515
     */
516
    public function canEdit($member = null)
517
    {
518
        $member = $this->getMember($member);
519
520
        if (parent::canEdit($member)) {
521
            return true;
522
        }
523
524
        $parent = $this->Parent();
525
526
        if (!$parent || !$parent->exists() || !($parent instanceof Blog)) {
527
            return false;
528
        }
529
530
        if ($parent->isEditor($member)) {
531
            return true;
532
        }
533
534
        if (!$parent->isWriter($member) && !$parent->isContributor($member)) {
535
            return false;
536
        }
537
538
        return $this->isAuthor($member);
539
    }
540
541
    /**
542
     * Returns the post excerpt.
543
     *
544
     * @param int $wordsToDisplay
545
     *
546
     * @return string
547
     */
548
    public function Excerpt($wordsToDisplay = 30)
549
    {
550
        /**
551
         * @var Text $content
552
         */
553
        $content = $this->dbObject('Content');
554
555
        return $content->Summary($wordsToDisplay);
556
    }
557
558
    /**
559
     * Returns a monthly archive link for the current blog post.
560
     *
561
     * @param string $type
562
     *
563
     * @return string
564
     */
565
    public function getMonthlyArchiveLink($type = 'day')
566
    {
567
        /**
568
         * @var SS_Datetime $date
569
         */
570
        $date = $this->dbObject('PublishDate');
571
572
        if ($type != 'year') {
573
            if ($type == 'day') {
574
                return Controller::join_links(
575
                    $this->Parent()->Link('archive'),
576
                    $date->format('Y'),
577
                    $date->format('m'),
578
                    $date->format('d')
579
                );
580
            }
581
582
            return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'), $date->format('m'));
583
        }
584
585
        return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'));
586
    }
587
588
    /**
589
     * Returns a yearly archive link for the current blog post.
590
     *
591
     * @return string
592
     */
593
    public function getYearlyArchiveLink()
594
    {
595
        /**
596
         * @var SS_Datetime $date
597
         */
598
        $date = $this->dbObject('PublishDate');
599
600
        return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'));
601
    }
602
603
    /**
604
     * Resolves static and dynamic authors linked to this post.
605
     *
606
     * @return ArrayList
607
     */
608
    public function getCredits()
609
    {
610
        $list = new ArrayList();
611
612
        $list->merge($this->getDynamicCredits());
613
        $list->merge($this->getStaticCredits());
614
615
        return $list->sort('Name');
616
    }
617
618
    /**
619
     * Resolves dynamic authors linked to this post.
620
     *
621
     * @return ArrayList
622
     */
623
    protected function getDynamicCredits()
624
    {
625
        // Find best page to host user profiles
626
        $parent = $this->Parent();
627
        if (! ($parent instanceof Blog)) {
628
            $parent = Blog::get()->first();
629
        }
630
631
        // If there is no parent blog, return list undecorated
632
        if (!$parent) {
633
            $items = $this->Authors()->toArray();
634
            return new ArrayList($items);
635
        }
636
637
        // Update all authors
638
        $items = new ArrayList();
639
        foreach ($this->Authors() as $author) {
640
            // Add link for each author
641
            $author = $author->customise(array(
642
                'URL' => $parent->ProfileLink($author->URLSegment),
643
            ));
644
            $items->push($author);
645
        }
646
647
        return $items;
648
    }
649
650
    /**
651
     * Resolves static authors linked to this post.
652
     *
653
     * @return ArrayList
654
     */
655
    protected function getStaticCredits()
656
    {
657
        $items = new ArrayList();
658
659
        $authors = array_filter(preg_split('/\s*,\s*/', $this->AuthorNames));
660
661
        foreach ($authors as $author) {
662
            $item = new ArrayData(array(
663
                'Name' => $author,
664
            ));
665
666
            $items->push($item);
667
        }
668
669
        return $items;
670
    }
671
672
    /**
673
     * Sets the label for BlogPost.Title to 'Post Title' (Rather than 'Page name').
674
     *
675
     * @param bool $includeRelations
676
     *
677
     * @return array
678
     */
679
    public function fieldLabels($includeRelations = true)
680
    {
681
        $labels = parent::fieldLabels($includeRelations);
682
683
        $labels['Title'] = _t('BlogPost.PageTitleLabel', 'Post Title');
684
685
        return $labels;
686
    }
687
688
    /**
689
     * {@inheritdoc}
690
     */
691
    protected function onBeforeWrite()
692
    {
693
        parent::onBeforeWrite();
694
695
        if (!$this->exists() && ($member = Member::currentUser())) {
696
            $this->Authors()->add($member);
697
        }
698
    }
699
}
700
701
/**
702
 * @package silverstripe
703
 * @subpackage blog
704
 */
705
class BlogPost_Controller extends Page_Controller
706
{
707
}
708