diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d6a43..707c5ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,5 @@ # Changelog -All notable changes to this project will be documented in this file. +For more information on changes and releases, please visit [Releases](https://github.com/symbiote/silverstripe-datachange-tracker/releases). -This project adheres to [Semantic Versioning](http://semver.org/). - -## [5.0.0] - -* First SilverStripe 4 compatible version. +This project adheres to [Semantic Versioning](http://semver.org/) diff --git a/README.md b/README.md index c578f91..da77b03 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Total Downloads](https://poser.pugx.org/symbiote/silverstripe-datachange-tracker/downloads.svg)](https://packagist.org/packages/symbiote/silverstripe-datachange-tracker) [![License](https://poser.pugx.org/symbiote/silverstripe-datachange-tracker/license.svg)](https://github.com/symbiote/silverstripe-datachange-tracker/blob/master/LICENSE.md) -Compatible with SilverStripe 4 +Compatible with SilverStripe 4 and 5 ## Maintainers @@ -28,21 +28,10 @@ composer require symbiote/silverstripe-datachange-tracker:~5.0 ## Requirements -* SilverStripe 4 +* SilverStripe 4.12 || 5 ## Documentation * [Quick Start](docs/en/quick-start.md) * [License](LICENSE.md) * [Contributing](CONTRIBUTING.md) - -## Version details - -*3.2.0* - -* Added pruning of data via queuedjobs - -*3.0.0* - -* Removed static DataChangeRecord::track() method - diff --git a/composer.json b/composer.json index 301413e..0362b68 100644 --- a/composer.json +++ b/composer.json @@ -12,16 +12,15 @@ ], "require": { - "silverstripe/framework": "~4.0" + "silverstripe/framework": "^4.12 || ^5" }, "require-dev": { - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^9.6" }, "extra": { "expose": [ "client" ], - "installer-name": "datachange-tracker", "branch-alias": { "dev-master": "5.0.x-dev" } diff --git a/src/Extension/ChangeRecordable.php b/src/Extension/ChangeRecordable.php index a8f6b01..be70c4f 100644 --- a/src/Extension/ChangeRecordable.php +++ b/src/Extension/ChangeRecordable.php @@ -22,7 +22,7 @@ class ChangeRecordable extends DataExtension */ public $dataChangeTrackService; - private static $ignored_fields = array(); + private static $ignored_fields = []; protected $isNewObject = false; @@ -80,7 +80,8 @@ public function onBeforeVersionedPublish($from, $to) * * @return \SilverStripe\ORM\DataList */ - public function getDataChangesList() { + public function getDataChangesList() + { return DataChangeRecord::get()->filter([ 'ChangeRecordID' => $this->owner->ID, 'ChangeRecordClass' => $this->owner->ClassName diff --git a/src/Extension/SignificantChangeRecordable.php b/src/Extension/SignificantChangeRecordable.php index da46864..5d65efc 100644 --- a/src/Extension/SignificantChangeRecordable.php +++ b/src/Extension/SignificantChangeRecordable.php @@ -20,14 +20,14 @@ class SignificantChangeRecordable extends DataExtension { - private static $ignored_fields = array(); + private static $ignored_fields = []; - private static $significant_fields = array(); + private static $significant_fields = []; - private static $db = array( + private static $db = [ 'LastSignificantChange' => 'DBDatetime', 'ChangeDescription' => 'Text' - ); + ]; public function updateCMSFields(FieldList $fields) { diff --git a/src/Extension/SiteTreeChangeRecordable.php b/src/Extension/SiteTreeChangeRecordable.php index 62715e0..c26740e 100644 --- a/src/Extension/SiteTreeChangeRecordable.php +++ b/src/Extension/SiteTreeChangeRecordable.php @@ -39,14 +39,13 @@ public function updateCMSFields(FieldList $fields) //create a gridfield out of them $gridFieldConfig = GridFieldConfig_RecordViewer::create(); $publishedGrid = new GridField('PublishStates', 'Published States', $dataChanges, $gridFieldConfig); - $dataColumns = $publishedGrid->getConfig()->getComponentByType('SilverStripe\Forms\GridField\GridFieldDataColumns'); - $dataColumns->setDisplayFields( - array('ChangeType' => 'Change Type', - 'ObjectTitle' => 'Page Title', - 'ChangedBy.Title' => 'User', - 'Created' => 'Modification Date', - ) - ); + $dataColumns = $publishedGrid->getConfig()->getComponentByType(\SilverStripe\Forms\GridField\GridFieldDataColumns::class); + $dataColumns->setDisplayFields([ + 'ChangeType' => 'Change Type', + 'ObjectTitle' => 'Page Title', + 'ChangedBy.Title' => 'User', + 'Created' => 'Modification Date' + ]); //linking through to the datachanges modeladmin diff --git a/src/Job/CleanupDataChangeHistoryTask.php b/src/Job/CleanupDataChangeHistoryTask.php index 466dd80..dd61a7e 100644 --- a/src/Job/CleanupDataChangeHistoryTask.php +++ b/src/Job/CleanupDataChangeHistoryTask.php @@ -26,7 +26,7 @@ public function run($request) return; } - $since = strtotime($since); + $since = strtotime((string) $since); if (!$since) { echo "Please specify an 'older' param with a date older than which to prune (in strtotime friendly format)
\n"; return; diff --git a/src/Job/PruneChangesBeforeJob.php b/src/Job/PruneChangesBeforeJob.php index 3c0dbd9..87987bf 100644 --- a/src/Job/PruneChangesBeforeJob.php +++ b/src/Job/PruneChangesBeforeJob.php @@ -24,7 +24,7 @@ public function __construct($priorTo = null) { $ts = 0; if ($priorTo) { - $ts = strtotime($priorTo); + $ts = strtotime((string) $priorTo); } if ($ts <= 0) { $ts = time() - 90 * 86400; @@ -69,4 +69,3 @@ public function process() Injector::inst()->get(QueuedJobService::class)->queueJob($job, $next); } } - diff --git a/src/Model/DataChangeRecord.php b/src/Model/DataChangeRecord.php index a7b75d6..4ce0caf 100644 --- a/src/Model/DataChangeRecord.php +++ b/src/Model/DataChangeRecord.php @@ -3,6 +3,7 @@ namespace Symbiote\DataChange\Model; use SilverStripe\ORM\DataObject; +use SilverStripe\Security\Security; use SilverStripe\View\Requirements; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\ToggleCompositeField; @@ -36,24 +37,24 @@ class DataChangeRecord extends DataObject 'GetVars' => 'Text', 'PostVars' => 'Text', ]; - private static $has_one = array( - 'ChangedBy' => 'SilverStripe\Security\Member', - 'ChangeRecord' => 'SilverStripe\ORM\DataObject', - ); - private static $summary_fields = array( + private static $has_one = [ + 'ChangedBy' => Member::class, + 'ChangeRecord' => DataObject::class + ]; + private static $summary_fields = [ 'ChangeType' => 'Change Type', 'ChangeRecordClass' => 'Record Class', 'ChangeRecordID' => 'Record ID', 'ObjectTitle' => 'Record Title', 'ChangedBy.Title' => 'User', - 'Created' => 'Modification Date', - ); - private static $searchable_fields = array( + 'Created' => 'Modification Date' + ]; + private static $searchable_fields = [ 'ChangeType', 'ObjectTitle', 'ChangeRecordClass', - 'ChangeRecordID', - ); + 'ChangeRecordID' + ]; private static $default_sort = 'ID DESC'; /** @@ -62,8 +63,8 @@ class DataChangeRecord extends DataObject * @var boolean */ private static $save_request_vars = false; - private static $field_blacklist = array('Password'); - private static $request_vars_blacklist = array('url', 'SecurityID'); + private static $field_blacklist = ['Password']; + private static $request_vars_blacklist = ['url', 'SecurityID']; public function getCMSFields($params = null) { @@ -73,7 +74,7 @@ public function getCMSFields($params = null) ToggleCompositeField::create( 'Details', 'Details', - array( + [ ReadonlyField::create('ChangeType', 'Type of change'), ReadonlyField::create('ChangeRecordClass', 'Record Class'), ReadonlyField::create('ChangeRecordID', 'Record ID'), @@ -84,18 +85,18 @@ public function getCMSFields($params = null) ReadonlyField::create('CurrentURL', 'URL'), ReadonlyField::create('Referer', 'Referer'), ReadonlyField::create('RemoteIP', 'Remote IP'), - ReadonlyField::create('Agent', 'Agent'), - ) + ReadonlyField::create('Agent', 'Agent') + ] )->setStartClosed(false)->addExtraClass('datachange-field'), ToggleCompositeField::create( 'RawData', 'Raw Data', - array( + [ ReadonlyField::create('Before'), ReadonlyField::create('After'), ReadonlyField::create('GetVars'), - ReadonlyField::create('PostVars'), - ) + ReadonlyField::create('PostVars') + ] )->setStartClosed(false)->addExtraClass('datachange-field') ); @@ -106,11 +107,11 @@ public function getCMSFields($params = null) // The solr search service injector dependency causes issues with comparison, since it has public variables that are stored in an array. - $diff->ignoreFields(array('searchService')); + $diff->ignoreFields(['searchService']); $diffed = $diff->diffedData(); $diffText = ''; - $changedFields = array(); + $changedFields = []; foreach ($diffed->toMap() as $field => $prop) { if (is_object($prop)) { continue; @@ -119,7 +120,7 @@ public function getCMSFields($params = null) $prop = json_encode($prop); } $changedFields[] = $readOnly = \SilverStripe\Forms\ReadonlyField::create( - 'ChangedField'.$field, + 'ChangedField' . $field, $field, $prop ); @@ -127,17 +128,17 @@ public function getCMSFields($params = null) } $fields->insertBefore( + 'RawData', ToggleCompositeField::create('FieldChanges', 'Changed Fields', $changedFields) ->setStartClosed(false) - ->addExtraClass('datachange-field'), - 'RawData' + ->addExtraClass('datachange-field') ); } // Flags fields that cannot be rendered with 'forTemplate'. This prevents bugs where // WorkflowService (of AdvancedWorkflow Module) and BlockManager (of Sheadawson/blocks module) get put // into a field and break the page. - $fieldsToRemove = array(); + $fieldsToRemove = []; foreach ($fields->dataFields() as $field) { $value = $field->Value(); if ($value && is_object($value)) { @@ -145,7 +146,7 @@ public function getCMSFields($params = null) $value, 'forTemplate' )) { - $field->setValue('[Missing '.get_class($value).'::forTemplate]'); + $field->setValue('[Missing ' . $value::class . '::forTemplate]'); } } } @@ -198,8 +199,8 @@ public function track(DataObject $changedObject, $type = 'Change') $this->ObjectTitle = $changedObject->Title; $this->Stage = Versioned::get_reading_mode(); - $before = array(); - $after = array(); + $before = []; + $after = []; if ($type != 'Change' && $type != 'New') { // If we are (un)publishing we want to store the entire object $before = ($type === 'Unpublish') ? $changedObject->toMap() : null; @@ -237,27 +238,26 @@ public function track(DataObject $changedObject, $type = 'Change') $this->PostVars = isset($_POST) ? json_encode($_POST) : null; } - $this->ChangedByID = Member::currentUserID(); - - if (Member::currentUserID() && Member::currentUser()) { - $this->CurrentEmail = Member::currentUser()->Email; + if ($member = Security::getCurrentUser()) { + $this->ChangedByID = $member->ID; + $this->CurrentEmail = $member->Email; } if (isset($_SERVER['SERVER_NAME'])) { $protocol = 'http'; $protocol = isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on" ? 'https://' : 'http://'; - $port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '80'; + $port = $_SERVER['SERVER_PORT'] ?? '80'; - $this->CurrentURL = $protocol.$_SERVER["SERVER_NAME"].":".$port.$_SERVER["REQUEST_URI"]; + $this->CurrentURL = $protocol . $_SERVER["SERVER_NAME"] . ":" . $port . $_SERVER["REQUEST_URI"]; } elseif (Director::is_cli()) { $this->CurrentURL = 'CLI'; } else { $this->CurrentURL = 'Could not determine current URL'; } - $this->RemoteIP = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : (Director::is_cli() ? 'CLI' : 'Unknown remote addr'); - $this->Referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; - $this->Agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; + $this->RemoteIP = $_SERVER['REMOTE_ADDR'] ?? (Director::is_cli() ? 'CLI' : 'Unknown remote addr'); + $this->Referer = $_SERVER['HTTP_REFERER'] ?? ''; + $this->Agent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $this->write(); return $this; @@ -276,7 +276,7 @@ public function canDelete($member = null) * */ public function getTitle() { - return $this->ChangeRecordClass.' #'.$this->ChangeRecordID; + return $this->ChangeRecordClass . ' #' . $this->ChangeRecordID; } /** @@ -306,7 +306,7 @@ private function prepareForDataDifferencer($jsonData) // // So solve this, we simply only decode to a depth of 1. (rather than the 512 default) // - $resultJsonData = json_decode($jsonData, true, 1); + $resultJsonData = json_decode((string) $jsonData, true, 1); return $resultJsonData; } } diff --git a/src/Model/TrackedManyManyList.php b/src/Model/TrackedManyManyList.php index 2c8300e..3a49419 100644 --- a/src/Model/TrackedManyManyList.php +++ b/src/Model/TrackedManyManyList.php @@ -12,9 +12,9 @@ */ class TrackedManyManyList extends ManyManyList { - public $trackedRelationships = array(); + public $trackedRelationships = []; - public function add($item, $extraFields = array()) + public function add($item, $extraFields = []) { $this->recordManyManyChange(__FUNCTION__, $item); $result = parent::add($item, $extraFields); @@ -58,7 +58,7 @@ protected function recordManyManyChange($type, $item) $item = $class::get()->byID($item); } $join = $type === 'add' ? ' to ' : ' from '; - $type = ucfirst($type) . ' "' . $item->Title . '"' . $join . $relationName; + $type = ucfirst((string) $type) . ' "' . $item->Title . '"' . $join . $relationName; $onItem->RelatedItem = $item->ClassName . ' #' . $item->ID; singleton('DataChangeTrackService')->track($onItem, $type); } diff --git a/src/Service/DataChangeTrackService.php b/src/Service/DataChangeTrackService.php index d52e7f9..2ab323d 100644 --- a/src/Service/DataChangeTrackService.php +++ b/src/Service/DataChangeTrackService.php @@ -9,10 +9,10 @@ /** * @author Stephen McMahon */ -class DataChangeTrackService +class DataChangeTrackService implements \Stringable { - protected $dcr_cache = array(); + protected $dcr_cache = []; public $disabled = false; @@ -30,11 +30,12 @@ public function track(DataObject $object, $type = 'Change') $this->dcr_cache["{$object->ID}-{$object->Classname}"]->track($object, $type); } - public function resetChangeCache() { + public function resetChangeCache() + { $this->dcr_cache = []; } - public function __toString() + public function __toString(): string { return ''; } diff --git a/tests/DataChangeCMSTest.php b/tests/DataChangeCMSTest.php index f1abf2d..9d4bf21 100644 --- a/tests/DataChangeCMSTest.php +++ b/tests/DataChangeCMSTest.php @@ -50,7 +50,7 @@ public function testCMSFieldsWithJSONData() // View in the CMS. $this->logInWithPermission('ADMIN'); $dataChangeTrackEditID = $dataChangeTrackRecordIds[0]; - $editLink = 'admin/datachanges/Symbiote-DataChange-Model-DataChangeRecord/EditForm/field/Symbiote-DataChange-Model-DataChangeRecord/item/'.$dataChangeTrackEditID.'/edit'; + $editLink = 'admin/datachanges/Symbiote-DataChange-Model-DataChangeRecord/EditForm/field/Symbiote-DataChange-Model-DataChangeRecord/item/' . $dataChangeTrackEditID . '/edit'; // NOTE(Jake): 2018-06-25 // @@ -66,13 +66,11 @@ public function testCMSFieldsWithJSONData() $body = $response->getBody(); $this->assertTrue( true, - strpos($body, 'Get Vars') !== false, - 'Cannot find \'Get Vars\' field to prove that we\'re actually on the editing DataChangeRecord page.' + str_contains($body, 'Get Vars') ); $this->assertTrue( true, - strpos($body, 'Post Vars') !== false, - 'Cannot find \'Post Vars\' field to prove that we\'re actually on the editing DataChangeRecord page.' + str_contains($body, 'Post Vars') ); } } diff --git a/tests/DataChangeTest.php b/tests/DataChangeTest.php index c686257..86580f2 100644 --- a/tests/DataChangeTest.php +++ b/tests/DataChangeTest.php @@ -79,7 +79,7 @@ public function testManyManyChanges_TableWithNoUnderscores() Injector::inst()->load($newInjectorConfig); // We want to check that $obj->Kids() is returning the injected TrackedManyManyList, not ManyManyList - $this->assertEquals(TrackedManyManyList::class, get_class($obj->Kids())); + $this->assertEquals(TrackedManyManyList::class, $obj->Kids()::class); // We want to make sure the join table looks like how we expect. $this->assertEquals('TestTrackedObject_Kids', $obj->Kids()->getJoinTable()); @@ -137,7 +137,7 @@ public function testAManyManyChanges_TableWithUnderscores() Injector::inst()->load($newInjectorConfig); // We want to check that $obj->Kids() is returning the injected TrackedManyManyList, not ManyManyList - $this->assertEquals(TrackedManyManyList::class, get_class($obj->Kids())); + $this->assertEquals(TrackedManyManyList::class, $obj->Kids()::class); // We want to make sure the join table looks like how we expect. $this->assertEquals('Symbiote_DataChange_Tests_TestTrackedUnderscoreObject_Kids', $obj->Kids()->getJoinTable()); diff --git a/tests/TestTextJSONFieldObject.php b/tests/TestTextJSONFieldObject.php index 9176dfa..6f7b8b6 100644 --- a/tests/TestTextJSONFieldObject.php +++ b/tests/TestTextJSONFieldObject.php @@ -25,7 +25,8 @@ class TestTextJSONFieldObject extends DataObject implements TestOnly * * This getter pattern was used in at least 1 internal Symbiote project. */ - public function getTextFieldWithJSON() { + public function getTextFieldWithJSON() + { $value = $this->getField('TextFieldWithJSON'); if (is_string($value)) { $value = json_decode($value, true);