This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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\Core\Manifest\ModuleLoader; |
||
12 | use SilverStripe\Forms\FieldList; |
||
13 | use SilverStripe\Forms\LiteralField; |
||
14 | use SilverStripe\Forms\FormAction; |
||
15 | use SilverStripe\Forms\CompositeField; |
||
16 | use SilverStripe\Forms\Tab; |
||
17 | use SilverStripe\Forms\DateField; |
||
18 | use SilverStripe\Forms\DateTimeField; |
||
19 | use SilverStripe\Forms\DropdownField; |
||
20 | use SilverStripe\Forms\GridField\GridField; |
||
21 | use SilverStripe\Forms\GridField\GridFieldConfig; |
||
22 | use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; |
||
23 | use SilverStripe\Forms\GridField\GridFieldDataColumns; |
||
24 | use SilverStripe\Forms\GridField\GridFieldSortableHeader; |
||
25 | use SilverStripe\Forms\ListboxField; |
||
26 | use SilverStripe\Forms\OptionsetField; |
||
27 | use SilverStripe\Forms\ReadonlyField; |
||
28 | use SilverStripe\Forms\HeaderField; |
||
29 | use SilverStripe\ORM\ArrayList; |
||
30 | use SilverStripe\ORM\DataExtension; |
||
31 | use SilverStripe\ORM\DataObject; |
||
32 | use SilverStripe\ORM\DB; |
||
33 | use SilverStripe\ORM\FieldType\DBDatetime; |
||
34 | use SilverStripe\ORM\FieldType\DBDate; |
||
35 | use SilverStripe\ORM\SS_List; |
||
36 | use SilverStripe\Security\Group; |
||
37 | use SilverStripe\Security\Member; |
||
38 | use SilverStripe\Security\Permission; |
||
39 | use SilverStripe\Security\PermissionProvider; |
||
40 | use SilverStripe\Security\Security; |
||
41 | use SilverStripe\SiteConfig\SiteConfig; |
||
42 | use SilverStripe\View\Requirements; |
||
43 | use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor; |
||
44 | use Symbiote\QueuedJobs\Services\QueuedJobService; |
||
45 | |||
46 | /** |
||
47 | * Set dates at which content needs to be reviewed and provide a report and emails to alert |
||
48 | * to content needing review. |
||
49 | * |
||
50 | * @property string $ContentReviewType |
||
51 | * @property int $ReviewPeriodDays |
||
52 | * @property Date $NextReviewDate |
||
53 | * @property string $LastEditedByName |
||
54 | * @property string $OwnerNames |
||
55 | * |
||
56 | * @method DataList ReviewLogs() |
||
57 | * @method DataList ContentReviewGroups() |
||
58 | * @method DataList ContentReviewUsers() |
||
59 | */ |
||
60 | class SiteTreeContentReview extends DataExtension implements PermissionProvider |
||
61 | { |
||
62 | /** |
||
63 | * @var array |
||
64 | */ |
||
65 | private static $db = array( |
||
0 ignored issues
–
show
|
|||
66 | "ContentReviewType" => "Enum('Inherit, Disabled, Custom', 'Inherit')", |
||
67 | "ReviewPeriodDays" => "Int", |
||
68 | "NextReviewDate" => "Date", |
||
69 | "LastEditedByName" => "Varchar(255)", |
||
70 | "OwnerNames" => "Varchar(255)", |
||
71 | ); |
||
72 | |||
73 | /** |
||
74 | * @var array |
||
75 | */ |
||
76 | private static $defaults = array( |
||
0 ignored issues
–
show
|
|||
77 | "ContentReviewType" => "Inherit", |
||
78 | ); |
||
79 | |||
80 | /** |
||
81 | * @var array |
||
82 | */ |
||
83 | private static $has_many = array( |
||
0 ignored issues
–
show
|
|||
84 | "ReviewLogs" => ContentReviewLog::class, |
||
85 | ); |
||
86 | |||
87 | /** |
||
88 | * @var array |
||
89 | */ |
||
90 | private static $belongs_many_many = array( |
||
0 ignored issues
–
show
|
|||
91 | "ContentReviewGroups" => Group::class, |
||
92 | "ContentReviewUsers" => Member::class, |
||
93 | ); |
||
94 | |||
95 | /** |
||
96 | * @var array |
||
97 | */ |
||
98 | private static $schedule = array( |
||
0 ignored issues
–
show
|
|||
99 | 0 => "No automatic review date", |
||
100 | 1 => "1 day", |
||
101 | 7 => "1 week", |
||
102 | 30 => "1 month", |
||
103 | 60 => "2 months", |
||
104 | 91 => "3 months", |
||
105 | 121 => "4 months", |
||
106 | 152 => "5 months", |
||
107 | 183 => "6 months", |
||
108 | 365 => "12 months", |
||
109 | ); |
||
110 | |||
111 | /** |
||
112 | * @return array |
||
113 | */ |
||
114 | public static function get_schedule() |
||
115 | { |
||
116 | return Config::inst()->get(static::class, 'schedule'); |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Takes a list of groups and members and return a list of unique member. |
||
121 | * |
||
122 | * @param SS_List $groups |
||
123 | * @param SS_List $members |
||
124 | * |
||
125 | * @return ArrayList |
||
126 | */ |
||
127 | public static function merge_owners(SS_List $groups, SS_List $members) |
||
128 | { |
||
129 | $contentReviewOwners = new ArrayList(); |
||
130 | |||
131 | if ($groups->count()) { |
||
132 | $groupIDs = array(); |
||
133 | |||
134 | foreach ($groups as $group) { |
||
135 | $familyIDs = $group->collateFamilyIDs(); |
||
136 | |||
137 | if (is_array($familyIDs)) { |
||
138 | $groupIDs = array_merge($groupIDs, array_values($familyIDs)); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | array_unique($groupIDs); |
||
143 | |||
144 | if (count($groupIDs)) { |
||
145 | $groupMembers = DataObject::get(Member::class)->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")") |
||
146 | ->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"") |
||
147 | /** @skipUpgrade */ |
||
148 | ->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\""); |
||
149 | |||
150 | $contentReviewOwners->merge($groupMembers); |
||
151 | } |
||
152 | } |
||
153 | |||
154 | $contentReviewOwners->merge($members); |
||
155 | $contentReviewOwners->removeDuplicates(); |
||
156 | |||
157 | return $contentReviewOwners; |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * @param FieldList $actions |
||
162 | */ |
||
163 | public function updateCMSActions(FieldList $actions) |
||
164 | { |
||
165 | if (!$this->canBeReviewedBy(Security::getCurrentUser())) { |
||
166 | return; |
||
167 | } |
||
168 | |||
169 | $module = ModuleLoader::getModule('silverstripe/contentreview'); |
||
170 | Requirements::css($module->getRelativeResourcePath('client/dist/styles/contentreview.css')); |
||
171 | Requirements::javascript($module->getRelativeResourcePath('client/dist/js/contentreview.js')); |
||
172 | |||
173 | $reviewTab = LiteralField::create('ContentReviewButton', $this->owner->renderWith(__CLASS__ . '_button')); |
||
174 | $actions->insertAfter('MajorActions', $reviewTab); |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Returns false if the content review have disabled. |
||
179 | * |
||
180 | * @param SiteTree $page |
||
181 | * |
||
182 | * @return bool|Date |
||
183 | */ |
||
184 | public function getReviewDate(SiteTree $page = null) |
||
185 | { |
||
186 | if ($page === null) { |
||
187 | $page = $this->owner; |
||
188 | } |
||
189 | |||
190 | if ($page->obj('NextReviewDate')->exists()) { |
||
191 | return $page->obj('NextReviewDate'); |
||
192 | } |
||
193 | |||
194 | $options = $this->owner->getOptions(); |
||
195 | |||
196 | if (!$options) { |
||
197 | return false; |
||
198 | } |
||
199 | |||
200 | if (!$options->ReviewPeriodDays) { |
||
201 | return false; |
||
202 | } |
||
203 | |||
204 | // Failover to check on ReviewPeriodDays + LastEdited |
||
205 | $nextReviewUnixSec = strtotime(' + ' . $options->ReviewPeriodDays . ' days', DBDatetime::now()->getTimestamp()); |
||
206 | $date = DBDate::create('NextReviewDate'); |
||
207 | $date->setValue($nextReviewUnixSec); |
||
208 | |||
209 | return $date; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Get the object that have the information about the content review settings. Either: |
||
214 | * |
||
215 | * - a SiteTreeContentReview decorated object |
||
216 | * - the default SiteTree config |
||
217 | * - false if this page have it's content review disabled |
||
218 | * |
||
219 | * Will go through parents and root pages will use the site config if their setting is Inherit. |
||
220 | * |
||
221 | * @return bool|DataObject |
||
222 | * |
||
223 | * @throws Exception |
||
224 | */ |
||
225 | public function getOptions() |
||
226 | { |
||
227 | if ($this->owner->ContentReviewType == "Custom") { |
||
228 | return $this->owner; |
||
229 | } |
||
230 | |||
231 | if ($this->owner->ContentReviewType == "Disabled") { |
||
232 | return false; |
||
233 | } |
||
234 | |||
235 | $page = $this->owner; |
||
236 | |||
237 | // $page is inheriting it's settings from it's parent, find |
||
238 | // the first valid parent with a valid setting |
||
239 | while ($parent = $page->Parent()) { |
||
240 | // Root page, use site config |
||
241 | if (!$parent->exists()) { |
||
242 | return SiteConfig::current_site_config(); |
||
243 | } |
||
244 | |||
245 | if ($parent->ContentReviewType == "Custom") { |
||
246 | return $parent; |
||
247 | } |
||
248 | |||
249 | if ($parent->ContentReviewType == "Disabled") { |
||
250 | return false; |
||
251 | } |
||
252 | |||
253 | $page = $parent; |
||
254 | } |
||
255 | |||
256 | throw new Exception("This shouldn't really happen, as per usual developer logic."); |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * @return string |
||
261 | */ |
||
262 | public function getOwnerNames() |
||
263 | { |
||
264 | $options = $this->getOptions(); |
||
265 | |||
266 | $names = array(); |
||
267 | |||
268 | if (!$options) { |
||
269 | return ""; |
||
270 | } |
||
271 | |||
272 | foreach ($options->OwnerGroups() as $group) { |
||
273 | $names[] = $group->getBreadcrumbs(" > "); |
||
274 | } |
||
275 | |||
276 | foreach ($options->OwnerUsers() as $group) { |
||
277 | $names[] = $group->getName(); |
||
278 | } |
||
279 | |||
280 | return implode(", ", $names); |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * @return null|string |
||
285 | */ |
||
286 | public function getEditorName() |
||
287 | { |
||
288 | $member = Security::getCurrentUser(); |
||
289 | |||
290 | if ($member) { |
||
291 | return $member->getTitle(); |
||
292 | } |
||
293 | |||
294 | return null; |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * Get all Members that are Content Owners to this page. This includes checking group |
||
299 | * hierarchy and adding any direct users. |
||
300 | * |
||
301 | * @return ArrayList |
||
302 | */ |
||
303 | public function ContentReviewOwners() |
||
304 | { |
||
305 | return SiteTreeContentReview::merge_owners( |
||
306 | $this->OwnerGroups(), |
||
307 | $this->OwnerUsers() |
||
308 | ); |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * @return ManyManyList |
||
313 | */ |
||
314 | public function OwnerGroups() |
||
315 | { |
||
316 | return $this->owner->getManyManyComponents("ContentReviewGroups"); |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * @return ManyManyList |
||
321 | */ |
||
322 | public function OwnerUsers() |
||
323 | { |
||
324 | return $this->owner->getManyManyComponents("ContentReviewUsers"); |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * @param FieldList $fields |
||
329 | */ |
||
330 | public function updateSettingsFields(FieldList $fields) |
||
331 | { |
||
332 | $module = ModuleLoader::getModule('silverstripe/contentreview'); |
||
333 | Requirements::javascript($module->getRelativeResourcePath('client/dist/js/contentreview.js')); |
||
334 | |||
335 | // Display read-only version only |
||
336 | if (!Permission::check("EDIT_CONTENT_REVIEW_FIELDS")) { |
||
337 | $schedule = self::get_schedule(); |
||
338 | $contentOwners = ReadonlyField::create("ROContentOwners", _t("ContentReview.CONTENTOWNERS", "Content Owners"), $this->getOwnerNames()); |
||
339 | $nextReviewAt = DateField::create('RONextReviewDate', _t("ContentReview.NEXTREVIEWDATE", "Next review date"), $this->owner->NextReviewDate); |
||
340 | |||
341 | if (!isset($schedule[$this->owner->ReviewPeriodDays])) { |
||
342 | $reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $schedule[0]); |
||
343 | } else { |
||
344 | $reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $schedule[$this->owner->ReviewPeriodDays]); |
||
345 | } |
||
346 | |||
347 | $logConfig = GridFieldConfig::create() |
||
348 | ->addComponent(Injector::inst()->create(GridFieldSortableHeader::class)) |
||
349 | ->addComponent($logColumns = Injector::inst()->create(GridFieldDataColumns::class)); |
||
350 | |||
351 | // Cast the value to the users preferred date format |
||
352 | $logColumns->setFieldCasting(array( |
||
353 | 'Created' => DateTimeField::class . '->value', |
||
354 | )); |
||
355 | |||
356 | $logs = GridField::create("ROReviewNotes", "Review Notes", $this->owner->ReviewLogs(), $logConfig); |
||
357 | |||
358 | |||
359 | $optionsFrom = ReadonlyField::create("ROType", _t("ContentReview.SETTINGSFROM", "Options are"), $this->owner->ContentReviewType); |
||
360 | |||
361 | $fields->addFieldsToTab("Root.ContentReview", array( |
||
362 | $contentOwners, |
||
363 | $nextReviewAt->performReadonlyTransformation(), |
||
364 | $reviewFreq, |
||
365 | $optionsFrom, |
||
366 | $logs, |
||
367 | )); |
||
368 | |||
369 | return; |
||
370 | } |
||
371 | |||
372 | $options = array(); |
||
373 | $options["Disabled"] = _t("ContentReview.DISABLE", "Disable content review"); |
||
374 | $options["Inherit"] = _t("ContentReview.INHERIT", "Inherit from parent page"); |
||
375 | $options["Custom"] = _t("ContentReview.CUSTOM", "Custom settings"); |
||
376 | |||
377 | $viewersOptionsField = OptionsetField::create("ContentReviewType", _t("ContentReview.OPTIONS", "Options"), $options); |
||
378 | |||
379 | $users = Permission::get_members_by_permission(array("CMS_ACCESS_CMSMain", "ADMIN")); |
||
380 | |||
381 | $usersMap = $users->map("ID", "Title")->toArray(); |
||
382 | |||
383 | asort($usersMap); |
||
384 | |||
385 | $userField = ListboxField::create("OwnerUsers", _t("ContentReview.PAGEOWNERUSERS", "Users"), $usersMap) |
||
386 | ->addExtraClass('custom-setting') |
||
387 | ->setAttribute("data-placeholder", _t("ContentReview.ADDUSERS", "Add users")) |
||
388 | ->setDescription(_t('ContentReview.OWNERUSERSDESCRIPTION', 'Page owners that are responsible for reviews')); |
||
389 | |||
390 | $groupsMap = array(); |
||
391 | |||
392 | foreach (Group::get() as $group) { |
||
393 | $groupsMap[$group->ID] = $group->getBreadcrumbs(" > "); |
||
394 | } |
||
395 | asort($groupsMap); |
||
396 | |||
397 | $groupField = ListboxField::create("OwnerGroups", _t("ContentReview.PAGEOWNERGROUPS", "Groups"), $groupsMap) |
||
398 | ->addExtraClass('custom-setting') |
||
399 | ->setAttribute("data-placeholder", _t("ContentReview.ADDGROUP", "Add groups")) |
||
400 | ->setDescription(_t("ContentReview.OWNERGROUPSDESCRIPTION", "Page owners that are responsible for reviews")); |
||
401 | |||
402 | $reviewDate = DateField::create("NextReviewDate", _t("ContentReview.NEXTREVIEWDATE", "Next review date")) |
||
403 | ->setDescription(_t("ContentReview.NEXTREVIEWDATADESCRIPTION", "Leave blank for no review")); |
||
404 | |||
405 | $reviewFrequency = DropdownField::create( |
||
406 | "ReviewPeriodDays", |
||
407 | _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), |
||
408 | self::get_schedule() |
||
409 | ) |
||
410 | ->addExtraClass('custom-setting') |
||
411 | ->setDescription(_t("ContentReview.REVIEWFREQUENCYDESCRIPTION", "The review date will be set to this far in the future whenever the page is published")); |
||
412 | |||
413 | $notesField = GridField::create("ReviewNotes", "Review Notes", $this->owner->ReviewLogs(), GridFieldConfig_RecordEditor::create()); |
||
414 | |||
415 | $fields->addFieldsToTab("Root.ContentReview", array( |
||
416 | HeaderField::create('ContentReviewHeader', _t("ContentReview.REVIEWHEADER", "Content review"), 2), |
||
417 | $viewersOptionsField, |
||
418 | CompositeField::create( |
||
419 | $userField, |
||
420 | $groupField, |
||
421 | $reviewDate, |
||
422 | $reviewFrequency |
||
423 | )->addExtraClass("review-settings"), |
||
424 | ReadonlyField::create("ROContentOwners", _t("ContentReview.CONTENTOWNERS", "Content Owners"), $this->getOwnerNames()), |
||
425 | $notesField, |
||
426 | )); |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * Creates a ContentReviewLog and connects it to this Page. |
||
431 | * |
||
432 | * @param Member $reviewer |
||
433 | * @param string $message |
||
434 | */ |
||
435 | public function addReviewNote(Member $reviewer, $message) |
||
436 | { |
||
437 | $reviewLog = ContentReviewLog::create(); |
||
438 | $reviewLog->Note = $message; |
||
0 ignored issues
–
show
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 <?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. ![]() |
|||
439 | $reviewLog->ReviewerID = $reviewer->ID; |
||
0 ignored issues
–
show
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 <?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. ![]() |
|||
440 | $this->owner->ReviewLogs()->add($reviewLog); |
||
441 | } |
||
442 | |||
443 | /** |
||
444 | * Advance review date to the next date based on review period or set it to null |
||
445 | * if there is no schedule. Returns true if date was required and false is content |
||
446 | * review is 'off'. |
||
447 | * |
||
448 | * @return bool |
||
449 | */ |
||
450 | public function advanceReviewDate() |
||
451 | { |
||
452 | $nextDateTimestamp = false; |
||
453 | $options = $this->getOptions(); |
||
454 | |||
455 | if ($options && $options->ReviewPeriodDays) { |
||
456 | $nextDateTimestamp = strtotime( |
||
457 | ' + ' . $options->ReviewPeriodDays . ' days', |
||
458 | DBDatetime::now()->getTimestamp() |
||
459 | ); |
||
460 | |||
461 | $this->owner->NextReviewDate = DBDate::create()->setValue($nextDateTimestamp)->Format('y-MM-dd'); |
||
462 | $this->owner->write(); |
||
463 | } |
||
464 | |||
465 | return (bool) $nextDateTimestamp; |
||
466 | } |
||
467 | |||
468 | /** |
||
469 | * Check if a review is due by a member for this owner. |
||
470 | * |
||
471 | * @param Member $member |
||
472 | * |
||
473 | * @return bool |
||
474 | */ |
||
475 | public function canBeReviewedBy(Member $member = null) |
||
476 | { |
||
477 | if (!$this->owner->obj("NextReviewDate")->exists()) { |
||
478 | return false; |
||
479 | } |
||
480 | |||
481 | if ($this->owner->obj("NextReviewDate")->InFuture()) { |
||
482 | return false; |
||
483 | } |
||
484 | |||
485 | $options = $this->getOptions(); |
||
486 | |||
487 | if (!$options) { |
||
488 | return false; |
||
489 | } |
||
490 | |||
491 | if (!$options |
||
492 | // Options can be a SiteConfig with different extension applied |
||
493 | || (!$options->hasExtension(__CLASS__) && !$options->hasExtension(ContentReviewDefaultSettings::class)) |
||
494 | ) { |
||
495 | return false; |
||
496 | } |
||
497 | |||
498 | if ($options->OwnerGroups()->count() == 0 && $options->OwnerUsers()->count() == 0) { |
||
499 | return false; |
||
500 | } |
||
501 | |||
502 | if (!$member) { |
||
503 | return true; |
||
504 | } |
||
505 | |||
506 | if ($member->inGroups($options->OwnerGroups())) { |
||
507 | return true; |
||
508 | } |
||
509 | |||
510 | if ($options->OwnerUsers()->find("ID", $member->ID)) { |
||
511 | return true; |
||
512 | } |
||
513 | |||
514 | return false; |
||
515 | } |
||
516 | |||
517 | /** |
||
518 | * Set the review data from the review period, if set. |
||
519 | */ |
||
520 | public function onBeforeWrite() |
||
521 | { |
||
522 | // Only update if DB fields have been changed |
||
523 | $changedFields = $this->owner->getChangedFields(true, 2); |
||
524 | if ($changedFields) { |
||
0 ignored issues
–
show
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 ![]() |
|||
525 | $this->owner->LastEditedByName = $this->owner->getEditorName(); |
||
0 ignored issues
–
show
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. ![]() |
|||
526 | $this->owner->OwnerNames = $this->owner->getOwnerNames(); |
||
527 | } |
||
528 | |||
529 | // If the user changed the type, we need to recalculate the review date. |
||
530 | if ($this->owner->isChanged("ContentReviewType", 2)) { |
||
531 | if ($this->owner->ContentReviewType == "Disabled") { |
||
532 | $this->setDefaultReviewDateForDisabled(); |
||
533 | } elseif ($this->owner->ContentReviewType == "Custom") { |
||
534 | $this->setDefaultReviewDateForCustom(); |
||
535 | } else { |
||
536 | $this->setDefaultReviewDateForInherited(); |
||
537 | } |
||
538 | } |
||
539 | |||
540 | // Ensure that a inherited page always have a next review date |
||
541 | if ($this->owner->ContentReviewType == "Inherit" && !$this->owner->NextReviewDate) { |
||
542 | $this->setDefaultReviewDateForInherited(); |
||
543 | } |
||
544 | |||
545 | // We need to update all the child pages that inherit this setting. We can only |
||
546 | // change children after this record has been created, otherwise the stageChildren |
||
547 | // method will grab all pages in the DB (this messes up unit testing) |
||
548 | if (!$this->owner->exists()) { |
||
549 | return; |
||
550 | } |
||
551 | |||
552 | // parent page change its review period |
||
553 | // && !$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. ![]() |
|||
554 | if ($this->owner->isChanged('ReviewPeriodDays', 2)) { |
||
555 | $nextReviewUnixSec = strtotime( |
||
556 | ' + ' . $this->owner->ReviewPeriodDays . ' days', |
||
557 | DBDatetime::now()->getTimestamp() |
||
558 | ); |
||
559 | $this->owner->NextReviewDate = DBDate::create()->setValue($nextReviewUnixSec)->Format('y-MM-dd'); |
||
560 | } |
||
561 | } |
||
562 | |||
563 | private function setDefaultReviewDateForDisabled() |
||
564 | { |
||
565 | $this->owner->NextReviewDate = null; |
||
566 | } |
||
567 | |||
568 | protected function setDefaultReviewDateForCustom() |
||
569 | { |
||
570 | // Don't overwrite existing value |
||
571 | if ($this->owner->NextReviewDate) { |
||
572 | return; |
||
573 | } |
||
574 | |||
575 | $this->owner->NextReviewDate = null; |
||
576 | $nextDate = $this->getReviewDate(); |
||
577 | |||
578 | View Code Duplication | if (is_object($nextDate)) { |
|
0 ignored issues
–
show
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. ![]() |
|||
579 | $this->owner->NextReviewDate = $nextDate->getValue(); |
||
580 | } else { |
||
581 | $this->owner->NextReviewDate = $nextDate; |
||
582 | } |
||
583 | } |
||
584 | |||
585 | protected function setDefaultReviewDateForInherited() |
||
586 | { |
||
587 | // Don't overwrite existing value |
||
588 | if ($this->owner->NextReviewDate) { |
||
589 | return; |
||
590 | } |
||
591 | |||
592 | $options = $this->getOptions(); |
||
593 | $nextDate = null; |
||
594 | |||
595 | if ($options instanceof SiteTree) { |
||
596 | $nextDate = $this->getReviewDate($options); |
||
597 | } elseif ($options instanceof SiteConfig) { |
||
598 | $nextDate = $this->getReviewDate(); |
||
599 | } |
||
600 | |||
601 | View Code Duplication | if (is_object($nextDate)) { |
|
0 ignored issues
–
show
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. ![]() |
|||
602 | $this->owner->NextReviewDate = $nextDate->getValue(); |
||
603 | } else { |
||
604 | $this->owner->NextReviewDate = $nextDate; |
||
605 | } |
||
606 | } |
||
607 | |||
608 | /** |
||
609 | * Provide permissions to the CMS. |
||
610 | * |
||
611 | * @return array |
||
612 | */ |
||
613 | public function providePermissions() |
||
614 | { |
||
615 | return array( |
||
616 | "EDIT_CONTENT_REVIEW_FIELDS" => array( |
||
617 | "name" => "Set content owners and review dates", |
||
618 | "category" => _t("Permissions.CONTENT_CATEGORY", "Content permissions"), |
||
619 | "sort" => 50, |
||
620 | ), |
||
621 | ); |
||
622 | } |
||
623 | |||
624 | /** |
||
625 | * If the queued jobs module is installed, queue up the first job for 9am tomorrow morning |
||
626 | * (by default). |
||
627 | */ |
||
628 | public function requireDefaultRecords() |
||
629 | { |
||
630 | if (class_exists(ContentReviewNotificationJob::class)) { |
||
631 | // Ensure there is not already a job queued |
||
632 | if (QueuedJobDescriptor::get()->filter("Implementation", ContentReviewNotificationJob::class)->first()) { |
||
633 | return; |
||
634 | } |
||
635 | |||
636 | $nextRun = Injector::inst()->create(ContentReviewNotificationJob::class); |
||
637 | $runHour = Config::inst()->get(ContentReviewNotificationJob::class, "first_run_hour"); |
||
638 | $firstRunTime = date("Y-m-d H:i:s", mktime($runHour, 0, 0, date("m"), date("d") + 1, date("y"))); |
||
639 | |||
640 | singleton(QueuedJobService::class)->queueJob( |
||
641 | $nextRun, |
||
642 | $firstRunTime |
||
643 | ); |
||
644 | |||
645 | DB::alteration_message(sprintf("Added ContentReviewNotificationJob to run at %s", $firstRunTime)); |
||
646 | } |
||
647 | } |
||
648 | } |
||
649 |
This check marks private properties in classes that are never used. Those properties can be removed.