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