From f4b9e858b82e5c271da624bccfb89e2da5db5858 Mon Sep 17 00:00:00 2001 From: Nick Sagona Date: Fri, 29 Sep 2023 10:47:36 -0500 Subject: [PATCH] Add full state tracking --- README.md | 46 +++++++++++++++++++++++++++----- src/Adapter/AbstractAdapter.php | 21 ++++++++------- src/Adapter/AdapterInterface.php | 14 +++++----- src/Auditor.php | 39 ++++++++++++++++++++++++++- tests/AuditorTest.php | 11 ++++++++ 5 files changed, 106 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d270b43..edec233 100644 --- a/README.md +++ b/README.md @@ -41,17 +41,26 @@ $new = [ 'email' => 'test@test.com' ]; +// Tracking the full state is optional +$state = [ + "id" => 1, + "username" => "admin2", + "first_name" => "John", + "last_name" => "Doe", + "email" => "test@test.com" +]; + $auditor = new Audit\Auditor(new Audit\Adapter\File('tmp')); // Folder passed to the File adapter $auditor->setModel('MyApp\Model\User', 1001); // Model name and model ID -$auditor->setUser('testuser', 101); // Username and user ID (optional) +$auditor->setUser('testuser', 101); // Username and user ID that made the change (optional) $auditor->setDomain('users.localhost'); // Domain (optional) -$logFile = $auditor->send($old, $new); +$logFile = $auditor->send($old, $new, $state); ``` In this case, the variable `$logFile` would contain the name of the audit log file, for example `pop-audit-1535060625.log` in case it needs to be referenced again. That file will contain the JSON-encoded data that tracks the difference between the -model states: +model states, as well as a snapshot of the full state (if provided): ```json { @@ -67,12 +76,17 @@ model states: "new": { "username": "admin2" }, + "state": { + "id": 1, + "username": "admin2", + "first_name": "John", + "last_name": "Doe", + "email": "test@test.com" + }, "timestamp": "2018-08-23 16:56:36" } ``` -Notice that only the difference is stored. In this case, only the `username` value changed. - ### Using a database Using a database connection requires the use of the `pop-db` component and a database table class @@ -104,12 +118,20 @@ $new = [ 'email' => 'test@test.com' ]; +// Tracking the full state is optional +$state = [ + "id" => 1, + "username" => "admin2", + "first_name" => "John", + "last_name" => "Doe", + "email" => "test@test.com" +]; $auditor = new Audit\Auditor(new Audit\Adapter\Table('AuditLog')); $auditor->setModel('MyApp\Model\User', 1001); $auditor->setUser('testuser', 101); $auditor->setDomain('users.localhost'); -$row = $auditor->send($old, $new); +$row = $auditor->send($old, $new, $state); ``` If needed, the variable `$row` contains the newly created record in the audit table. @@ -131,6 +153,15 @@ $new = [ 'email' => 'test@test.com' ]; +// Tracking the full state is optional +$state = [ + "id" => 1, + "username" => "admin2", + "first_name" => "John", + "last_name" => "Doe", + "email" => "test@test.com" +]; + $stream = new \Pop\Http\Client\Stream('http://audit.localhost'); $stream->setContextOptions(['http' => [ 'protocol_version' => '1.1', @@ -142,7 +173,7 @@ $auditor = new Audit\Auditor(new Audit\Adapter\Http($stream)); $auditor->setModel('MyApp\Model\User', 1001); $auditor->setUser('testuser', 101); $auditor->setDomain('users.localhost'); -$auditor->send($old, $new); +$auditor->send($old, $new, $state); ``` ### Setting the Diff @@ -169,3 +200,4 @@ $auditor->setUser('testuser', 101); $auditor->setDomain('users.localhost'); $auditor->setDiff($old, $new); $auditor->send(); +``` diff --git a/src/Adapter/AbstractAdapter.php b/src/Adapter/AbstractAdapter.php index d0abd67..cf4b45f 100644 --- a/src/Adapter/AbstractAdapter.php +++ b/src/Adapter/AbstractAdapter.php @@ -357,16 +357,6 @@ public function setStateData(array $state) return $this; } - /** - * Determine if there is a final state - * - * @return boolean - */ - public function hasStateData() - { - return !empty($this->stateData); - } - /** * Get the final state * @@ -382,6 +372,17 @@ public function getStateData($name = null) } } + /** + * Determine if there is final state data + * + * @param string $name + * @return boolean + */ + public function hasStateData($name = null) + { + return (null !== $name) ? array_key_exists($name, $this->stateData) : !empty($this->stateData); + } + /** * Set the differences in values between the model states (that have already been processed) * diff --git a/src/Adapter/AdapterInterface.php b/src/Adapter/AdapterInterface.php index 0c19076..0427e2f 100644 --- a/src/Adapter/AdapterInterface.php +++ b/src/Adapter/AdapterInterface.php @@ -193,13 +193,6 @@ public function getMetadata($name = null); */ public function setStateData(array $state); - /** - * Determine if there is a final state - * - * @return boolean - */ - public function hasStateData(); - /** * Get the final state * @@ -208,6 +201,13 @@ public function hasStateData(); */ public function getStateData($name = null); + /** + * Determine if there is a final state + * + * @return boolean + */ + public function hasStateData(); + /** * Set the differences in values between the model states (that have already been processed) * diff --git a/src/Auditor.php b/src/Auditor.php index 3ce09fd..23cadce 100644 --- a/src/Auditor.php +++ b/src/Auditor.php @@ -142,6 +142,39 @@ public function addMetadata($name, $value) return $this; } + /** + * Set state data + * + * @param array $stateData + * @return Auditor + */ + public function setStateData(array $stateData) + { + $this->adapter->setStateData($stateData); + return $this; + } + + /** + * Get state data + * + * @param string $name + * @return mixed + */ + public function getStateData($name = null) + { + return $this->adapter->getStateData($name); + } + + /** + * Has state data + * + * @param string $name + * @return boolean + */ + public function hasStateData($name = null) + { + return $this->adapter->hasStateData($name); + } /** * Set the differences in values between the model states (that have already been processed) @@ -184,13 +217,17 @@ public function hasDiff() * * @param array $old * @param array $new + * @param array $state * @return mixed */ - public function send(array $old = null, array $new = null) + public function send(array $old = null, array $new = null, array $state = null) { if ((null !== $old) && (null !== $new)) { $this->adapter->resolveDiff($old, $new); } + if (null !== $state) { + $this->adapter->setStateData($state); + } return ($this->adapter->hasDiff()) ? $this->adapter->send() : false; } diff --git a/tests/AuditorTest.php b/tests/AuditorTest.php index a08a0cb..0f96265 100644 --- a/tests/AuditorTest.php +++ b/tests/AuditorTest.php @@ -51,6 +51,17 @@ public function testMetadata() $this->assertEquals('bar', $auditor->adapter()->getMetadata('foo')); } + public function testStateData() + { + $auditor = new Audit\Auditor(new Audit\Adapter\File(__DIR__ . '/tmp')); + $auditor->setStateData(['foo' => 'bar']); + $this->assertTrue($auditor->adapter()->hasStateData()); + $this->assertTrue($auditor->adapter()->hasStateData('foo')); + $this->assertFalse($auditor->adapter()->hasStateData('baz')); + $this->assertEquals('bar', $auditor->adapter()->getStateData('foo')); + $this->assertEquals(['foo' => 'bar'], $auditor->adapter()->getStateData()); + } + public function testSetDiff() { $old = ['username' => 'admin'];