Completed
Pull Request — master (#64)
by Robbie
01:38
created

SiteTreeContentReview::canBeReviewedBy()   C

Complexity

Conditions 11
Paths 9

Size

Total Lines 38
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 38
rs 5.2653
c 1
b 0
f 0
cc 11
eloc 19
nc 9
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\ContentReview\Extensions;
4
5
use Exception;
6
use SilverStripe\CMS\Model\SiteTree;
7
use SilverStripe\ContentReview\Jobs\ContentReviewNotificationJob;
8
use SilverStripe\ContentReview\Models\ContentReviewLog;
9
use SilverStripe\Core\Config\Config;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\LiteralField;
13
use SilverStripe\Forms\FormAction;
14
use SilverStripe\Forms\CompositeField;
15
use SilverStripe\Forms\Tab;
16
use SilverStripe\Forms\DateField;
17
use SilverStripe\Forms\DropdownField;
18
use SilverStripe\Forms\GridField\GridField;
19
use SilverStripe\Forms\GridField\GridFieldConfig;
20
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
21
use SilverStripe\Forms\GridField\GridFieldDataColumns;
22
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
23
use SilverStripe\Forms\ListboxField;
24
use SilverStripe\Forms\OptionsetField;
25
use SilverStripe\Forms\ReadonlyField;
26
use SilverStripe\Forms\HeaderField;
27
use SilverStripe\ORM\ArrayList;
28
use SilverStripe\ORM\DataExtension;
29
use SilverStripe\ORM\DataObject;
30
use SilverStripe\ORM\DB;
31
use SilverStripe\ORM\FieldType\DBDatetime;
32
use SilverStripe\ORM\FieldType\DBDate;
33
use SilverStripe\ORM\SS_List;
34
use SilverStripe\Security\Group;
35
use SilverStripe\Security\Member;
36
use SilverStripe\Security\Permission;
37
use SilverStripe\Security\PermissionProvider;
38
use SilverStripe\Security\Security;
39
use SilverStripe\SiteConfig\SiteConfig;
40
use SilverStripe\View\Requirements;
41
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
42
use Symbiote\QueuedJobs\Services\QueuedJobService;
43
44
/**
45
 * Set dates at which content needs to be reviewed and provide a report and emails to alert
46
 * to content needing review.
47
 *
48
 * @property string $ContentReviewType
49
 * @property int    $ReviewPeriodDays
50
 * @property Date   $NextReviewDate
51
 * @property string $LastEditedByName
52
 * @property string $OwnerNames
53
 *
54
 * @method DataList ReviewLogs()
55
 * @method DataList ContentReviewGroups()
56
 * @method DataList ContentReviewUsers()
57
 */
58
class SiteTreeContentReview extends DataExtension implements PermissionProvider
59
{
60
    /**
61
     * @var array
62
     */
63
    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...
64
        "ContentReviewType" => "Enum('Inherit, Disabled, Custom', 'Inherit')",
65
        "ReviewPeriodDays"  => "Int",
66
        "NextReviewDate"    => "Date",
67
        "LastEditedByName"  => "Varchar(255)",
68
        "OwnerNames"        => "Varchar(255)",
69
    );
70
71
    /**
72
     * @var array
73
     */
74
    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...
75
        "ContentReviewType" => "Inherit",
76
    );
77
78
    /**
79
     * @var array
80
     */
81
    private static $has_many = array(
0 ignored issues
show
Unused Code introduced by
The property $has_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...
82
        "ReviewLogs" => ContentReviewLog::class,
83
    );
84
85
    /**
86
     * @var array
87
     */
88
    private static $belongs_many_many = array(
0 ignored issues
show
Unused Code introduced by
The property $belongs_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...
89
        "ContentReviewGroups" => Group::class,
90
        "ContentReviewUsers"  => Member::class,
91
    );
92
93
    /**
94
     * @var array
95
     */
96
    private static $schedule = array(
0 ignored issues
show
Unused Code introduced by
The property $schedule 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...
97
        0   => "No automatic review date",
98
        1   => "1 day",
99
        7   => "1 week",
100
        30  => "1 month",
101
        60  => "2 months",
102
        91  => "3 months",
103
        121 => "4 months",
104
        152 => "5 months",
105
        183 => "6 months",
106
        365 => "12 months",
107
    );
108
109
    /**
110
     * @return array
111
     */
112
    public static function get_schedule()
113
    {
114
        return Config::inst()->get(static::class, 'schedule');
115
    }
116
117
    /**
118
     * Takes a list of groups and members and return a list of unique member.
119
     *
120
     * @param SS_List $groups
121
     * @param SS_List $members
122
     *
123
     * @return ArrayList
124
     */
125
    public static function merge_owners(SS_List $groups, SS_List $members)
126
    {
127
        $contentReviewOwners = new ArrayList();
128
129
        if ($groups->count()) {
130
            $groupIDs = array();
131
132
            foreach ($groups as $group) {
133
                $familyIDs = $group->collateFamilyIDs();
134
135
                if (is_array($familyIDs)) {
136
                    $groupIDs = array_merge($groupIDs, array_values($familyIDs));
137
                }
138
            }
139
140
            array_unique($groupIDs);
141
142
            if (count($groupIDs)) {
143
                $groupMembers = DataObject::get(Member::class)->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")")
144
                    ->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")
145
                    /** @skipUpgrade */
146
                    ->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"");
147
148
                $contentReviewOwners->merge($groupMembers);
149
            }
150
        }
151
152
        $contentReviewOwners->merge($members);
153
        $contentReviewOwners->removeDuplicates();
154
155
        return $contentReviewOwners;
156
    }
157
158
    /**
159
     * @param FieldList $actions
160
     */
161
    public function updateCMSActions(FieldList $actions)
162
    {
163
        if (!$this->canBeReviewedBy(Security::getCurrentUser())) {
164
            return;
165
        }
166
167
        Requirements::css('silverstripe/contentreview:client/dist/styles/contentreview.css');
168
        Requirements::javascript('silverstripe/contentreview:client/dist/js/contentreview.js');
169
170
        $reviewTab = LiteralField::create('ContentReviewButton', $this->owner->renderWith(__CLASS__ . '_button'));
171
        $actions->insertAfter('MajorActions', $reviewTab);
172
    }
173
174
    /**
175
     * Returns false if the content review have disabled.
176
     *
177
     * @param SiteTree $page
178
     *
179
     * @return bool|Date
180
     */
181
    public function getReviewDate(SiteTree $page = null)
182
    {
183
        if ($page === null) {
184
            $page = $this->owner;
185
        }
186
187
        if ($page->obj('NextReviewDate')->exists()) {
188
            return $page->obj('NextReviewDate');
189
        }
190
191
        $options = $this->owner->getOptions();
192
193
        if (!$options) {
194
            return false;
195
        }
196
197
        if (!$options->ReviewPeriodDays) {
198
            return false;
199
        }
200
201
        // Failover to check on ReviewPeriodDays + LastEdited
202
        $nextReviewUnixSec = strtotime(' + ' . $options->ReviewPeriodDays . ' days', DBDatetime::now()->getTimestamp());
203
        $date = DBDate::create('NextReviewDate');
204
        $date->setValue($nextReviewUnixSec);
205
206
        return $date;
207
    }
208
209
    /**
210
     * Get the object that have the information about the content review settings. Either:
211
     *
212
     *  - a SiteTreeContentReview decorated object
213
     *  - the default SiteTree config
214
     *  - false if this page have it's content review disabled
215
     *
216
     * Will go through parents and root pages will use the site config if their setting is Inherit.
217
     *
218
     * @return bool|DataObject
219
     *
220
     * @throws Exception
221
     */
222
    public function getOptions()
223
    {
224
        if ($this->owner->ContentReviewType == "Custom") {
225
            return $this->owner;
226
        }
227
228
        if ($this->owner->ContentReviewType == "Disabled") {
229
            return false;
230
        }
231
232
        $page = $this->owner;
233
234
        // $page is inheriting it's settings from it's parent, find
235
        // the first valid parent with a valid setting
236
        while ($parent = $page->Parent()) {
237
            // Root page, use site config
238
            if (!$parent->exists()) {
239
                return SiteConfig::current_site_config();
240
            }
241
242
            if ($parent->ContentReviewType == "Custom") {
243
                return $parent;
244
            }
245
246
            if ($parent->ContentReviewType == "Disabled") {
247
                return false;
248
            }
249
250
            $page = $parent;
251
        }
252
253
        throw new Exception("This shouldn't really happen, as per usual developer logic.");
254
    }
255
256
    /**
257
     * @return string
258
     */
259
    public function getOwnerNames()
260
    {
261
        $options = $this->getOptions();
262
263
        $names = array();
264
265
        if (!$options) {
266
            return "";
267
        }
268
269
        foreach ($options->OwnerGroups() as $group) {
270
            $names[] = $group->getBreadcrumbs(" > ");
271
        }
272
273
        foreach ($options->OwnerUsers() as $group) {
274
            $names[] = $group->getName();
275
        }
276
277
        return implode(", ", $names);
278
    }
279
280
    /**
281
     * @return null|string
282
     */
283
    public function getEditorName()
284
    {
285
        $member = Security::getCurrentUser();
286
287
        if ($member) {
288
            return $member->getTitle();
289
        }
290
291
        return null;
292
    }
293
294
    /**
295
     * Get all Members that are Content Owners to this page. This includes checking group
296
     * hierarchy and adding any direct users.
297
     *
298
     * @return ArrayList
299
     */
300
    public function ContentReviewOwners()
301
    {
302
        return SiteTreeContentReview::merge_owners(
303
            $this->OwnerGroups(),
304
            $this->OwnerUsers()
305
        );
306
    }
307
308
    /**
309
     * @return ManyManyList
310
     */
311
    public function OwnerGroups()
312
    {
313
        return $this->owner->getManyManyComponents("ContentReviewGroups");
314
    }
315
316
    /**
317
     * @return ManyManyList
318
     */
319
    public function OwnerUsers()
320
    {
321
        return $this->owner->getManyManyComponents("ContentReviewUsers");
322
    }
323
324
    /**
325
     * @param FieldList $fields
326
     */
327
    public function updateSettingsFields(FieldList $fields)
328
    {
329
        Requirements::javascript("silverstripe/contentreview:client/dist/js/contentreview.js");
330
331
        // Display read-only version only
332
        if (!Permission::check("EDIT_CONTENT_REVIEW_FIELDS")) {
333
            $schedule = self::get_schedule();
334
            $contentOwners = ReadonlyField::create("ROContentOwners", _t("ContentReview.CONTENTOWNERS", "Content Owners"), $this->getOwnerNames());
335
            $nextReviewAt = DateField::create('RONextReviewDate', _t("ContentReview.NEXTREVIEWDATE", "Next review date"), $this->owner->NextReviewDate);
336
337
            if (!isset($schedule[$this->owner->ReviewPeriodDays])) {
338
                $reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $schedule[0]);
339
            } else {
340
                $reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $schedule[$this->owner->ReviewPeriodDays]);
341
            }
342
343
            $logConfig = GridFieldConfig::create()
344
                ->addComponent(Injector::inst()->create(GridFieldSortableHeader::class))
345
                ->addComponent($logColumns = Injector::inst()->create(GridFieldDataColumns::class));
346
347
            // Cast the value to the users preferred date format
348
            $logColumns->setFieldCasting(array(
349
                "Created" => "DateTimeField->value",
350
            ));
351
352
            $logs = GridField::create("ROReviewNotes", "Review Notes", $this->owner->ReviewLogs(), $logConfig);
353
354
355
            $optionsFrom = ReadonlyField::create("ROType", _t("ContentReview.SETTINGSFROM", "Options are"), $this->owner->ContentReviewType);
356
357
            $fields->addFieldsToTab("Root.ContentReview", array(
358
                $contentOwners,
359
                $nextReviewAt->performReadonlyTransformation(),
360
                $reviewFreq,
361
                $optionsFrom,
362
                $logs,
363
            ));
364
365
            return;
366
        }
367
368
        $options = array();
369
        $options["Disabled"] = _t("ContentReview.DISABLE", "Disable content review");
370
        $options["Inherit"] = _t("ContentReview.INHERIT", "Inherit from parent page");
371
        $options["Custom"] = _t("ContentReview.CUSTOM", "Custom settings");
372
373
        $viewersOptionsField = OptionsetField::create("ContentReviewType", _t("ContentReview.OPTIONS", "Options"), $options);
374
375
        $users = Permission::get_members_by_permission(array("CMS_ACCESS_CMSMain", "ADMIN"));
376
377
        $usersMap = $users->map("ID", "Title")->toArray();
378
379
        asort($usersMap);
380
381
        $userField = ListboxField::create("OwnerUsers", _t("ContentReview.PAGEOWNERUSERS", "Users"), $usersMap)
382
            ->addExtraClass('custom-setting')
383
            ->setAttribute("data-placeholder", _t("ContentReview.ADDUSERS", "Add users"))
384
            ->setDescription(_t('ContentReview.OWNERUSERSDESCRIPTION', 'Page owners that are responsible for reviews'));
385
386
        $groupsMap = array();
387
388
        foreach (Group::get() as $group) {
389
            $groupsMap[$group->ID] = $group->getBreadcrumbs(" > ");
390
        }
391
        asort($groupsMap);
392
393
        $groupField = ListboxField::create("OwnerGroups", _t("ContentReview.PAGEOWNERGROUPS", "Groups"), $groupsMap)
394
            ->addExtraClass('custom-setting')
395
            ->setAttribute("data-placeholder", _t("ContentReview.ADDGROUP", "Add groups"))
396
            ->setDescription(_t("ContentReview.OWNERGROUPSDESCRIPTION", "Page owners that are responsible for reviews"));
397
398
        $reviewDate = DateField::create("NextReviewDate", _t("ContentReview.NEXTREVIEWDATE", "Next review date"))
399
            ->setDescription(_t("ContentReview.NEXTREVIEWDATADESCRIPTION", "Leave blank for no review"));
400
401
        $reviewFrequency = DropdownField::create(
402
            "ReviewPeriodDays",
403
            _t("ContentReview.REVIEWFREQUENCY", "Review frequency"),
404
            self::get_schedule()
405
        )
406
            ->addExtraClass('custom-setting')
407
            ->setDescription(_t("ContentReview.REVIEWFREQUENCYDESCRIPTION", "The review date will be set to this far in the future whenever the page is published"));
408
409
        $notesField = GridField::create("ReviewNotes", "Review Notes", $this->owner->ReviewLogs(), GridFieldConfig_RecordEditor::create());
410
411
        $fields->addFieldsToTab("Root.ContentReview", array(
412
            HeaderField::create('ContentReviewHeader', _t("ContentReview.REVIEWHEADER", "Content review"), 2),
413
            $viewersOptionsField,
414
            CompositeField::create(
415
                $userField,
416
                $groupField,
417
                $reviewDate,
418
                $reviewFrequency
419
            )->addExtraClass("review-settings"),
420
            ReadonlyField::create("ROContentOwners", _t("ContentReview.CONTENTOWNERS", "Content Owners"), $this->getOwnerNames()),
421
            $notesField,
422
        ));
423
    }
424
425
    /**
426
     * Creates a ContentReviewLog and connects it to this Page.
427
     *
428
     * @param Member $reviewer
429
     * @param string $message
430
     */
431
    public function addReviewNote(Member $reviewer, $message)
432
    {
433
        $reviewLog = ContentReviewLog::create();
434
        $reviewLog->Note = $message;
0 ignored issues
show
Documentation introduced by
The property Note does not exist on object<SilverStripe\Cont...odels\ContentReviewLog>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
435
        $reviewLog->ReviewerID = $reviewer->ID;
0 ignored issues
show
Documentation introduced by
The property ReviewerID does not exist on object<SilverStripe\Cont...odels\ContentReviewLog>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
436
        $this->owner->ReviewLogs()->add($reviewLog);
437
    }
438
439
    /**
440
     * Advance review date to the next date based on review period or set it to null
441
     * if there is no schedule. Returns true if date was required and false is content
442
     * review is 'off'.
443
     *
444
     * @return bool
445
     */
446
    public function advanceReviewDate()
447
    {
448
        $nextDateTimestamp = false;
449
        $options = $this->getOptions();
450
451
        if ($options && $options->ReviewPeriodDays) {
452
            $nextDateTimestamp = strtotime(
453
                ' + ' . $options->ReviewPeriodDays . ' days',
454
                DBDatetime::now()->getTimestamp()
455
            );
456
457
            $this->owner->NextReviewDate = DBDate::create()->setValue($nextDateTimestamp)->Format('y-MM-dd');
458
            $this->owner->write();
459
        }
460
461
        return (bool) $nextDateTimestamp;
462
    }
463
464
    /**
465
     * Check if a review is due by a member for this owner.
466
     *
467
     * @param Member $member
468
     *
469
     * @return bool
470
     */
471
    public function canBeReviewedBy(Member $member = null)
472
    {
473
        if (!$this->owner->obj("NextReviewDate")->exists()) {
474
            return false;
475
        }
476
477
        if ($this->owner->obj("NextReviewDate")->InFuture()) {
478
            return false;
479
        }
480
481
        $options = $this->getOptions();
482
483
        if (!$options) {
484
            return false;
485
        }
486
487
        if (!$options || !$options->hasExtension(__CLASS__)) {
488
            return false;
489
        }
490
491
        if ($options->OwnerGroups()->count() == 0 && $options->OwnerUsers()->count() == 0) {
492
            return false;
493
        }
494
495
        if (!$member) {
496
            return true;
497
        }
498
499
        if ($member->inGroups($options->OwnerGroups())) {
500
            return true;
501
        }
502
503
        if ($options->OwnerUsers()->find("ID", $member->ID)) {
504
            return true;
505
        }
506
507
        return false;
508
    }
509
510
    /**
511
     * Set the review data from the review period, if set.
512
     */
513
    public function onBeforeWrite()
514
    {
515
        // Only update if DB fields have been changed
516
        $changedFields = $this->owner->getChangedFields(true, 2);
517
        if ($changedFields) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $changedFields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
518
            $this->owner->LastEditedByName = $this->owner->getEditorName();
0 ignored issues
show
Bug introduced by
The property LastEditedByName does not seem to exist. Did you mean LastEdited?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
519
            $this->owner->OwnerNames = $this->owner->getOwnerNames();
520
        }
521
522
        // If the user changed the type, we need to recalculate the review date.
523
        if ($this->owner->isChanged("ContentReviewType", 2)) {
524
            if ($this->owner->ContentReviewType == "Disabled") {
525
                $this->setDefaultReviewDateForDisabled();
526
            } elseif ($this->owner->ContentReviewType == "Custom") {
527
                $this->setDefaultReviewDateForCustom();
528
            } else {
529
                $this->setDefaultReviewDateForInherited();
530
            }
531
        }
532
533
        // Ensure that a inherited page always have a next review date
534
        if ($this->owner->ContentReviewType == "Inherit" && !$this->owner->NextReviewDate) {
535
            $this->setDefaultReviewDateForInherited();
536
        }
537
538
        // We need to update all the child pages that inherit this setting. We can only
539
        // change children after this record has been created, otherwise the stageChildren
540
        // method will grab all pages in the DB (this messes up unit testing)
541
        if (!$this->owner->exists()) {
542
            return;
543
        }
544
545
        // parent page change its review period
546
        // && !$this->owner->isChanged('ContentReviewType', 2)
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
547
        if ($this->owner->isChanged('ReviewPeriodDays', 2)) {
548
            $nextReviewUnixSec = strtotime(
549
                ' + ' . $this->owner->ReviewPeriodDays . ' days',
550
                DBDatetime::now()->getTimestamp()
551
            );
552
            $this->owner->NextReviewDate = DBDate::create()->setValue($nextReviewUnixSec)->Format('y-MM-dd');
553
        }
554
    }
555
556
    private function setDefaultReviewDateForDisabled()
557
    {
558
        $this->owner->NextReviewDate = null;
559
    }
560
561
    protected function setDefaultReviewDateForCustom()
562
    {
563
        // Don't overwrite existing value
564
        if ($this->owner->NextReviewDate) {
565
            return;
566
        }
567
568
        $this->owner->NextReviewDate = null;
569
        $nextDate = $this->getReviewDate();
570
571 View Code Duplication
        if (is_object($nextDate)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
572
            $this->owner->NextReviewDate = $nextDate->getValue();
573
        } else {
574
            $this->owner->NextReviewDate = $nextDate;
575
        }
576
    }
577
578
    protected function setDefaultReviewDateForInherited()
579
    {
580
        // Don't overwrite existing value
581
        if ($this->owner->NextReviewDate) {
582
            return;
583
        }
584
585
        $options = $this->getOptions();
586
        $nextDate = null;
587
588
        if ($options instanceof SiteTree) {
589
            $nextDate = $this->getReviewDate($options);
590
        } elseif ($options instanceof SiteConfig) {
591
            $nextDate = $this->getReviewDate();
592
        }
593
594 View Code Duplication
        if (is_object($nextDate)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
595
            $this->owner->NextReviewDate = $nextDate->getValue();
596
        } else {
597
            $this->owner->NextReviewDate = $nextDate;
598
        }
599
    }
600
601
    /**
602
     * Provide permissions to the CMS.
603
     *
604
     * @return array
605
     */
606
    public function providePermissions()
607
    {
608
        return array(
609
            "EDIT_CONTENT_REVIEW_FIELDS" => array(
610
                "name"     => "Set content owners and review dates",
611
                "category" => _t("Permissions.CONTENT_CATEGORY", "Content permissions"),
612
                "sort"     => 50,
613
            ),
614
        );
615
    }
616
617
    /**
618
     * If the queued jobs module is installed, queue up the first job for 9am tomorrow morning
619
     * (by default).
620
     */
621
    public function requireDefaultRecords()
622
    {
623
        if (class_exists(ContentReviewNotificationJob::class)) {
624
            // Ensure there is not already a job queued
625
            if (QueuedJobDescriptor::get()->filter("Implementation", ContentReviewNotificationJob::class)->first()) {
626
                return;
627
            }
628
629
            $nextRun = Injector::inst()->create(ContentReviewNotificationJob::class);
630
            $runHour = Config::inst()->get(ContentReviewNotificationJob::class, "first_run_hour");
631
            $firstRunTime = date("Y-m-d H:i:s", mktime($runHour, 0, 0, date("m"), date("d") + 1, date("y")));
632
633
            singleton(QueuedJobService::class)->queueJob(
634
                $nextRun,
635
                $firstRunTime
636
            );
637
638
            DB::alteration_message(sprintf("Added ContentReviewNotificationJob to run at %s", $firstRunTime));
639
        }
640
    }
641
}
642