From 4afff44bd0284ca213b762a75d29498e67f24801 Mon Sep 17 00:00:00 2001 From: erikn69 Date: Tue, 21 May 2024 13:46:14 -0500 Subject: [PATCH] Fix DispatchAudit Serialization Problems (#893) * Fix DispatchAudit Serialization Problems * Remove SerializesModels trait * Tests for `Serialization of 'Closure' is not allowed` --- src/Events/DispatchAudit.php | 85 ++++++++++++++++++++++++++++++++++++ tests/Models/Article.php | 4 ++ 2 files changed, 89 insertions(+) diff --git a/src/Events/DispatchAudit.php b/src/Events/DispatchAudit.php index 28bf8d3c..3acfd144 100644 --- a/src/Events/DispatchAudit.php +++ b/src/Events/DispatchAudit.php @@ -3,6 +3,7 @@ namespace OwenIt\Auditing\Events; use OwenIt\Auditing\Contracts\Auditable; +use ReflectionClass; class DispatchAudit { @@ -22,4 +23,88 @@ public function __construct(Auditable $model) { $this->model = $model; } + + /** + * Prepare the instance values for serialization. + * + * @return array + */ + public function __serialize() + { + $values = [ + 'class' => get_class($this->model), + 'model_data' => [ + 'exists' => true, + 'connection' => $this->model->getQueueableConnection() + ] + ]; + + $customProperties = array_merge([ + 'attributes', + 'original', + 'excludedAttributes', + 'auditEvent', + 'auditExclude', + 'auditCustomOld', + 'auditCustomNew', + 'isCustomEvent', + 'preloadedResolverData', + ], $this->model->auditEventSerializedProperties ?? []); + + $reflection = new ReflectionClass($this->model); + + foreach ($customProperties as $key) { + try { + $values['model_data'][$key] = $this->getModelPropertyValue($reflection, $key); + } catch (\Throwable $e){ + // + } + } + + return $values; + } + + /** + * Restore the model after serialization. + * + * @param array $values + * @return array + */ + public function __unserialize(array $values) + { + $this->model = new $values['class']; + + $reflection = new ReflectionClass($this->model); + foreach ($values['model_data'] as $key => $value) { + $this->setModelPropertyValue($reflection, $key, $value); + } + + return $values; + } + + /** + * Set the property value for the given property. + */ + protected function setModelPropertyValue(ReflectionClass $reflection, string $name, $value) + { + $property = $reflection->getProperty($name); + + $property->setAccessible(true); + + $property->setValue($this->model, $value); + } + + /** + * Get the property value for the given property. + * + * @return mixed + */ + protected function getModelPropertyValue(ReflectionClass $reflection, string $name) + { + $property = $reflection->getProperty($name); + + $property->setAccessible(true); + + return $property->getValue($this->model); + } } diff --git a/tests/Models/Article.php b/tests/Models/Article.php index f1bcb98d..9e97ab61 100644 --- a/tests/Models/Article.php +++ b/tests/Models/Article.php @@ -42,12 +42,16 @@ class Article extends Model implements Auditable 'reviewed', ]; + public $customClosure; + public function __construct(array $attributes = []) { if (class_exists(\Illuminate\Database\Eloquent\Casts\AsArrayObject::class)) { $this->casts['config'] = \Illuminate\Database\Eloquent\Casts\AsArrayObject::class; } + $this->customClosure = function () {}; + parent::__construct($attributes); }