From 4901a7060b7bf2904be910c3502ca2a06fb76993 Mon Sep 17 00:00:00 2001 From: erikn69 Date: Thu, 28 Dec 2023 17:25:21 -0500 Subject: [PATCH 1/3] Fix DispatchAudit Serialization Problems --- src/Events/DispatchAudit.php | 98 ++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/Events/DispatchAudit.php b/src/Events/DispatchAudit.php index 28bf8d3c..c762ac89 100644 --- a/src/Events/DispatchAudit.php +++ b/src/Events/DispatchAudit.php @@ -2,10 +2,17 @@ namespace OwenIt\Auditing\Events; +use Illuminate\Queue\SerializesModels; use OwenIt\Auditing\Contracts\Auditable; +use ReflectionClass; class DispatchAudit { + use SerializesModels { + __serialize as __serialize_model; + __unserialize as __unserialize_model; + } + /** * The Auditable model. * @@ -22,4 +29,95 @@ public function __construct(Auditable $model) { $this->model = $model; } + + /** + * Prepare the instance values for serialization. + * + * @return array + */ + public function __serialize() + { + $values = $this->__serialize_model(); + + $values['model_data'] = ['exists' => true]; + $reflection = new ReflectionClass($this->model); + $customProperties = array_merge([ + 'attributes', + 'original', + 'excludedAttributes', + 'auditEvent', + 'auditExclude', + 'auditCustomOld', + 'auditCustomNew', + 'isCustomEvent', + 'preloadedResolverData', + ], $this->model->auditEventSerializedProperties ?? []); + + foreach ($customProperties as $key) { + try { + $values['model_data'][$key] = $this->getSerializedPropertyValue( + $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->__unserialize_model($values); + + $reflection = new ReflectionClass($this->model); + foreach ($values['model_data'] as $key => $value) { + $this->setModelPropertyValue($reflection, $key, $value); + } + + return $values; + } + + /** + * Restore the model from the model identifier instance. + * + * @param \Illuminate\Contracts\Database\ModelIdentifier $value + * @return \Illuminate\Database\Eloquent\Model + */ + public function restoreModel($value) + { + return (new $value->class)->setConnection($value->connection); + } + + /** + * 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, $this->getRestoredPropertyValue($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); + } } From da23bab5c6f04f1412f46e858c938540590e5563 Mon Sep 17 00:00:00 2001 From: erikn69 Date: Thu, 28 Dec 2023 17:55:12 -0500 Subject: [PATCH 2/3] Remove SerializesModels trait --- src/Events/DispatchAudit.php | 37 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/Events/DispatchAudit.php b/src/Events/DispatchAudit.php index c762ac89..3acfd144 100644 --- a/src/Events/DispatchAudit.php +++ b/src/Events/DispatchAudit.php @@ -2,17 +2,11 @@ namespace OwenIt\Auditing\Events; -use Illuminate\Queue\SerializesModels; use OwenIt\Auditing\Contracts\Auditable; use ReflectionClass; class DispatchAudit { - use SerializesModels { - __serialize as __serialize_model; - __unserialize as __unserialize_model; - } - /** * The Auditable model. * @@ -37,10 +31,14 @@ public function __construct(Auditable $model) */ public function __serialize() { - $values = $this->__serialize_model(); + $values = [ + 'class' => get_class($this->model), + 'model_data' => [ + 'exists' => true, + 'connection' => $this->model->getQueueableConnection() + ] + ]; - $values['model_data'] = ['exists' => true]; - $reflection = new ReflectionClass($this->model); $customProperties = array_merge([ 'attributes', 'original', @@ -53,11 +51,11 @@ public function __serialize() 'preloadedResolverData', ], $this->model->auditEventSerializedProperties ?? []); + $reflection = new ReflectionClass($this->model); + foreach ($customProperties as $key) { try { - $values['model_data'][$key] = $this->getSerializedPropertyValue( - $this->getModelPropertyValue($reflection, $key) - ); + $values['model_data'][$key] = $this->getModelPropertyValue($reflection, $key); } catch (\Throwable $e){ // } @@ -74,7 +72,7 @@ public function __serialize() */ public function __unserialize(array $values) { - $this->__unserialize_model($values); + $this->model = new $values['class']; $reflection = new ReflectionClass($this->model); foreach ($values['model_data'] as $key => $value) { @@ -84,17 +82,6 @@ public function __unserialize(array $values) return $values; } - /** - * Restore the model from the model identifier instance. - * - * @param \Illuminate\Contracts\Database\ModelIdentifier $value - * @return \Illuminate\Database\Eloquent\Model - */ - public function restoreModel($value) - { - return (new $value->class)->setConnection($value->connection); - } - /** * Set the property value for the given property. */ @@ -104,7 +91,7 @@ protected function setModelPropertyValue(ReflectionClass $reflection, string $na $property->setAccessible(true); - $property->setValue($this->model, $this->getRestoredPropertyValue($value)); + $property->setValue($this->model, $value); } /** From c5ab121f6f477831613163b6fec7340634ff38b7 Mon Sep 17 00:00:00 2001 From: erikn69 Date: Fri, 29 Dec 2023 09:08:37 -0500 Subject: [PATCH 3/3] Tests for `Serialization of 'Closure' is not allowed` --- tests/Models/Article.php | 4 ++++ 1 file changed, 4 insertions(+) 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); }