From 2a04628459d86e4ae7bf7cacbec4e1c77f1f4856 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Thu, 11 Nov 2021 20:06:24 +0200 Subject: [PATCH] Added `FlexObject::getDiff()` to see difference to the saved object --- CHANGELOG.md | 2 + system/src/Grav/Framework/Flex/FlexObject.php | 64 +++++++++++++++---- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee3b8604f..90544568d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,12 @@ 1. [](#new) * Updated phpstan to v1.0 + * Added `FlexObject::getDiff()` to see difference to the saved object 2. [](#improved) * Use Symfony `dump` instead of PHP's `vardump` in side the `{{ vardump(x) }}` Twig vardump function * Added `route` and `request` to `onPagesInitialized` event * Improved page cloning, added method `Page::initialize()` + * Improved `FlexObject::getChanges()`: return changed lists and arrays as whole instead of just changed keys/values 3. [](#bugfix) * Fixed path traversal vulnerability when using `bin/grav server` * Fixed unescaped error messages in JSON error responses diff --git a/system/src/Grav/Framework/Flex/FlexObject.php b/system/src/Grav/Framework/Flex/FlexObject.php index f5949ec49..ac51b3461 100644 --- a/system/src/Grav/Framework/Flex/FlexObject.php +++ b/system/src/Grav/Framework/Flex/FlexObject.php @@ -12,6 +12,7 @@ namespace Grav\Framework\Flex; use ArrayAccess; use Exception; use Grav\Common\Data\Blueprint; +use Grav\Common\Data\Data; use Grav\Common\Debugger; use Grav\Common\Grav; use Grav\Common\Inflector; @@ -72,8 +73,6 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface private $_meta; /** @var array */ protected $_original; - /** @var array */ - protected $_changes; /** @var string */ protected $storage_key; /** @var int */ @@ -454,13 +453,50 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface } /** - * Get any changes based on data sent to update + * Get diff array from the object. + * + * @return array + */ + public function getDiff(): array + { + $blueprint = $this->getBlueprint(); + + $flattenOriginal = $blueprint->flattenData($this->getOriginalData()); + $flattenElements = $blueprint->flattenData($this->getElements()); + $removedElements = array_diff_key($flattenOriginal, $flattenElements); + $diff = []; + + // Include all added or changed keys. + foreach ($flattenElements as $key => $value) { + $orig = $flattenOriginal[$key] ?? null; + if ($orig !== $value) { + $diff[$key] = ['old' => $orig, 'new' => $value]; + } + } + + // Include all removed keys. + foreach ($removedElements as $key => $value) { + $diff[$key] = ['old' => $value, 'new' => null]; + } + + return $diff; + } + + /** + * Get any changes from the object. * * @return array */ public function getChanges(): array { - return $this->_changes ?? []; + $diff = $this->getDiff(); + + $data = new Data(); + foreach ($diff as $key => $change) { + $data->set($key, $change['new']); + } + + return $data->toArray(); } /** @@ -641,14 +677,19 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface public function update(array $data, array $files = []) { if ($data) { + // Get currently stored data. + $elements = $this->getElements(); + + // Store original version of the object. + if ($this->_original === null) { + $this->_original = $elements; + } + $blueprint = $this->getBlueprint(); // Process updated data through the object filters. $this->filterElements($data); - // Get currently stored data. - $elements = $this->getElements(); - // Merge existing object to the test data to be validated. $test = $blueprint->mergeData($elements, $data); @@ -657,19 +698,14 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface $data = $blueprint->filter($data, true, true); // Finally update the object. - foreach ($blueprint->flattenData($data) as $key => $value) { + $flattenData = $blueprint->flattenData($data); + foreach ($flattenData as $key => $value) { if ($value === null) { $this->unsetNestedProperty($key); } else { $this->setNestedProperty($key, $value); } } - - // Store the changes - if ($this->_original === null) { - $this->_original = $elements; - } - $this->_changes = Utils::arrayDiffMultidimensional($this->_original, $this->getElements()); } if ($files && method_exists($this, 'setUpdatedMedia')) {