From 127e81af67fdeb9d25b1566bf316f4e8e9c70847 Mon Sep 17 00:00:00 2001 From: Jonathan van Rij Date: Tue, 6 Dec 2022 15:23:48 +0100 Subject: [PATCH 1/5] adds static pre and post save event handlers to make versioning possible outside this --- src/Mpociot/Versionable/VersionableTrait.php | 80 +++++++++++--------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/src/Mpociot/Versionable/VersionableTrait.php b/src/Mpociot/Versionable/VersionableTrait.php index f9ff17e..82e8734 100644 --- a/src/Mpociot/Versionable/VersionableTrait.php +++ b/src/Mpociot/Versionable/VersionableTrait.php @@ -1,8 +1,10 @@ versioningEnabled === true) { - $this->versionableDirtyData = $this->getDirty(); - $this->updating = $this->exists; - } + self::modelPreSave($this); } /** @@ -160,47 +159,21 @@ protected function versionablePreSave() */ protected function versionablePostSave() { - /** - * We'll save new versions on updating and first creation - */ - if ( - ( $this->versioningEnabled === true && $this->updating && $this->isValidForVersioning() ) || - ( $this->versioningEnabled === true && !$this->updating && !is_null($this->versionableDirtyData) && count($this->versionableDirtyData)) - ) { - // Save a new version - $class = $this->getVersionClass(); - $version = new $class(); - $version->versionable_id = $this->getKey(); - $version->versionable_type = method_exists($this, 'getMorphClass') ? $this->getMorphClass() : get_class($this); - $version->user_id = $this->getAuthUserId(); - - $versionedHiddenFields = $this->versionedHiddenFields ?? []; - $this->makeVisible($versionedHiddenFields); - $version->model_data = serialize($this->attributesToArray()); - $this->makeHidden($versionedHiddenFields); - - if (!empty( $this->reason )) { - $version->reason = $this->reason; - } - - $version->save(); - - $this->purgeOldVersions(); - } + self::modelPostSave($this); } /** * Delete old versions of this model when they reach a specific count. - * + * * @return void */ private function purgeOldVersions() { $keep = isset($this->keepOldVersions) ? $this->keepOldVersions : 0; - + if ((int)$keep > 0) { $count = $this->versions()->count(); - + if ($count > $keep) { $this->getLatestVersions() ->take($count) @@ -246,5 +219,42 @@ protected function getLatestVersions() return $this->versions()->orderByDesc('version_id'); } + protected static function modelPreSave(Model $model) + { + if ($model->versioningEnabled === true) { + $model->versionableDirtyData = $model->getDirty(); + $model->updating = $model->exists; + } + } + + protected static function modelPostSave(Model $model) + { + /** + * We'll save new versions on updating and first creation + */ + if ( + ( $model->versioningEnabled === true && $model->updating && $model->isValidForVersioning() ) || + ( $model->versioningEnabled === true && !$model->updating && !is_null($model->versionableDirtyData) && count($model->versionableDirtyData)) + ) { + // Save a new version + $class = $model->getVersionClass(); + $version = new $class(); + $version->versionable_id = $model->getKey(); + $version->versionable_type = method_exists($model, 'getMorphClass') ? $model->getMorphClass() : get_class($model); + $version->user_id = $model->getAuthUserId(); + + $versionedHiddenFields = $model->versionedHiddenFields ?? []; + $model->makeVisible($versionedHiddenFields); + $version->model_data = serialize($model->attributesToArray()); + $model->makeHidden($versionedHiddenFields); + + if (!empty( $model->reason )) { + $version->reason = $model->reason; + } + $version->save(); + + $model->purgeOldVersions(); + } + } } From e20062fcd934286f2d8cda7a29b3a4b137692cb7 Mon Sep 17 00:00:00 2001 From: Jonathan van Rij Date: Tue, 6 Dec 2022 16:00:54 +0100 Subject: [PATCH 2/5] adds versionableJob --- .../Versionable/Jobs/VersionableJob.php | 28 +++++++ src/Mpociot/Versionable/VersionableTrait.php | 78 +++++++++---------- src/config/config.php | 10 ++- 3 files changed, 72 insertions(+), 44 deletions(-) create mode 100644 src/Mpociot/Versionable/Jobs/VersionableJob.php diff --git a/src/Mpociot/Versionable/Jobs/VersionableJob.php b/src/Mpociot/Versionable/Jobs/VersionableJob.php new file mode 100644 index 0000000..3112469 --- /dev/null +++ b/src/Mpociot/Versionable/Jobs/VersionableJob.php @@ -0,0 +1,28 @@ +model->versionablePostSave(); + } +} diff --git a/src/Mpociot/Versionable/VersionableTrait.php b/src/Mpociot/Versionable/VersionableTrait.php index 82e8734..7e0b7bf 100644 --- a/src/Mpociot/Versionable/VersionableTrait.php +++ b/src/Mpociot/Versionable/VersionableTrait.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Auth; use Illuminate\Database\Eloquent\Relations\MorphMany; -use phpDocumentor\Reflection\Types\Self_; +use Mpociot\Versionable\Jobs\VersionableJob; /** * Class VersionableTrait @@ -150,7 +150,10 @@ public function getVersionModel($version_id) */ protected function versionablePreSave() { - self::modelPreSave($this); + if ($this->versioningEnabled === true) { + $this->versionableDirtyData = $this->getDirty(); + $this->updating = $this->exists; + } } /** @@ -159,7 +162,37 @@ protected function versionablePreSave() */ protected function versionablePostSave() { - self::modelPostSave($this); + if (config('versionable.use_queue', false)) { + VersionableJob::dispatch($this); + } else { + /** + * We'll save new versions on updating and first creation + */ + if ( + ( $this->versioningEnabled === true && $this->updating && $this->isValidForVersioning() ) || + ( $this->versioningEnabled === true && !$this->updating && !is_null($this->versionableDirtyData) && count($this->versionableDirtyData)) + ) { + // Save a new version + $class = $this->getVersionClass(); + $version = new $class(); + $version->versionable_id = $this->getKey(); + $version->versionable_type = method_exists($this, 'getMorphClass') ? $this->getMorphClass() : get_class($this); + $version->user_id = $this->getAuthUserId(); + + $versionedHiddenFields = $this->versionedHiddenFields ?? []; + $this->makeVisible($versionedHiddenFields); + $version->model_data = serialize($this->attributesToArray()); + $this->makeHidden($versionedHiddenFields); + + if (!empty( $this->reason )) { + $version->reason = $this->reason; + } + + $version->save(); + + $this->purgeOldVersions(); + } + } } /** @@ -218,43 +251,4 @@ protected function getLatestVersions() { return $this->versions()->orderByDesc('version_id'); } - - protected static function modelPreSave(Model $model) - { - if ($model->versioningEnabled === true) { - $model->versionableDirtyData = $model->getDirty(); - $model->updating = $model->exists; - } - } - - protected static function modelPostSave(Model $model) - { - /** - * We'll save new versions on updating and first creation - */ - if ( - ( $model->versioningEnabled === true && $model->updating && $model->isValidForVersioning() ) || - ( $model->versioningEnabled === true && !$model->updating && !is_null($model->versionableDirtyData) && count($model->versionableDirtyData)) - ) { - // Save a new version - $class = $model->getVersionClass(); - $version = new $class(); - $version->versionable_id = $model->getKey(); - $version->versionable_type = method_exists($model, 'getMorphClass') ? $model->getMorphClass() : get_class($model); - $version->user_id = $model->getAuthUserId(); - - $versionedHiddenFields = $model->versionedHiddenFields ?? []; - $model->makeVisible($versionedHiddenFields); - $version->model_data = serialize($model->attributesToArray()); - $model->makeHidden($versionedHiddenFields); - - if (!empty( $model->reason )) { - $version->reason = $model->reason; - } - - $version->save(); - - $model->purgeOldVersions(); - } - } } diff --git a/src/config/config.php b/src/config/config.php index 637864c..f8c453e 100644 --- a/src/config/config.php +++ b/src/config/config.php @@ -7,6 +7,12 @@ * Feel free to change this, if you need specific version * model logic. */ - 'version_model' => \Mpociot\Versionable\Version::class + 'version_model' => \Mpociot\Versionable\Version::class, -]; \ No newline at end of file + + /* + * Here you can configure the versioning logic + * to be handled within a separate job. + */ + 'use_queue' => env('VERSIONING_USE_QUEUE', false) +]; From a6e588a473a924e0af65d52735aa36abd8188b41 Mon Sep 17 00:00:00 2001 From: Jonathan van Rij Date: Tue, 6 Dec 2022 23:07:21 +0100 Subject: [PATCH 3/5] wip get versioning working from the queue job --- .../Versionable/Jobs/VersionableJob.php | 32 ++++++++++++-- src/Mpociot/Versionable/Version.php | 36 ++++++++++++++++ src/Mpociot/Versionable/VersionableTrait.php | 42 ++++--------------- 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/src/Mpociot/Versionable/Jobs/VersionableJob.php b/src/Mpociot/Versionable/Jobs/VersionableJob.php index 3112469..f82bd44 100644 --- a/src/Mpociot/Versionable/Jobs/VersionableJob.php +++ b/src/Mpociot/Versionable/Jobs/VersionableJob.php @@ -2,12 +2,16 @@ namespace Mpociot\Versionable\Jobs; +use Adaptor\Core\Classes\ServiceExecutionData; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Arr; +use Illuminate\Support\Str; +use Mpociot\Versionable\Version; +use ReflectionException; class VersionableJob implements ShouldQueue { @@ -16,13 +20,33 @@ class VersionableJob implements ShouldQueue use Queueable; use SerializesModels; - public function __construct(private Model $model) + public function __construct(private int $id, private string $modelClass, private array $attributes, private array $originalAttributes) { +// \Log::info('model', ['id' => $id, 'class' => $modelClass, 'attributes' => $this->attributes, 'original' => $this->originalAttributes]); } + /** + * @throws ReflectionException + */ public function handle() { - // TODO test - $this->model->versionablePostSave(); + $resourceReflection = new \ReflectionClass($this->modelClass); + $staticResource = $resourceReflection->newInstanceWithoutConstructor(); + $model = $staticResource->find($this->id); + + foreach ($this->originalAttributes as $key => $value) { + $model->setAttribute($key, $value); + } + + $model->syncOriginal(); + + foreach ($this->attributes as $key => $value) { + $model->setAttribute($key, $value); + } + + $model->versionableDirtyData = $model->getDirty(); + $model->updating = $model->exists; + + Version::createVersionForModel($model); } } diff --git a/src/Mpociot/Versionable/Version.php b/src/Mpociot/Versionable/Version.php index add5cba..7c60a3f 100644 --- a/src/Mpociot/Versionable/Version.php +++ b/src/Mpociot/Versionable/Version.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Config; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Eloquent\Model; +use Mpociot\Versionable\Jobs\VersionableJob; /** * Class Version @@ -105,4 +106,39 @@ public function diff(Version $againstVersion = null) return $diffArray; } + public static function createVersionForModel(Model $model) + { + if ( + ( $model->versioningEnabled === true && $model->updating && $model->isValidForVersioning() ) || + ( $model->versioningEnabled === true && !$model->updating && !is_null($model->versionableDirtyData) && count($model->versionableDirtyData)) + ) { + \Log::info('2'); + + // Save a new version + $class = $model->getVersionClass(); + $version = new $class(); + $version->versionable_id = $model->getKey(); + $version->versionable_type = method_exists($model, 'getMorphClass') ? $model->getMorphClass() : get_class($model); + $version->user_id = $model->getAuthUserId(); + + \Log::info('3'); + + $versionedHiddenFields = $model->versionedHiddenFields ?? []; + $model->makeVisible($versionedHiddenFields); + $version->model_data = serialize($model->attributesToArray()); + $model->makeHidden($versionedHiddenFields); + + \Log::info('4'); + + if (!empty( $model->reason )) { + $version->reason = $model->reason; + } + + \Log::info('5'); + + $version->save(); + + $model->purgeOldVersions(); + } + } } diff --git a/src/Mpociot/Versionable/VersionableTrait.php b/src/Mpociot/Versionable/VersionableTrait.php index 7e0b7bf..4212935 100644 --- a/src/Mpociot/Versionable/VersionableTrait.php +++ b/src/Mpociot/Versionable/VersionableTrait.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Auth; use Illuminate\Database\Eloquent\Relations\MorphMany; +use Log; use Mpociot\Versionable\Jobs\VersionableJob; /** @@ -12,7 +13,6 @@ */ trait VersionableTrait { - /** * Retrieve, if exists, the property that define that Version model. * If no property defined, use the default Version model. @@ -21,7 +21,7 @@ trait VersionableTrait * http://php.net/manual/en/language.oop5.traits.php * @return unknown|string */ - protected function getVersionClass() + public function getVersionClass() { if( property_exists( self::class, 'versionClass') ) { return $this->versionClass; @@ -42,7 +42,7 @@ protected function getVersionClass() * * @var array */ - private $versionableDirtyData; + public $versionableDirtyData; /** * Optional reason, why this version was created @@ -54,7 +54,7 @@ protected function getVersionClass() * Flag that determines if the model allows versioning at all * @var bool */ - protected $versioningEnabled = true; + public $versioningEnabled = true; /** * @return $this @@ -163,35 +163,9 @@ protected function versionablePreSave() protected function versionablePostSave() { if (config('versionable.use_queue', false)) { - VersionableJob::dispatch($this); + VersionableJob::dispatch($this->id, get_class($this), $this->getAttributes(), $this->getRawOriginal()); } else { - /** - * We'll save new versions on updating and first creation - */ - if ( - ( $this->versioningEnabled === true && $this->updating && $this->isValidForVersioning() ) || - ( $this->versioningEnabled === true && !$this->updating && !is_null($this->versionableDirtyData) && count($this->versionableDirtyData)) - ) { - // Save a new version - $class = $this->getVersionClass(); - $version = new $class(); - $version->versionable_id = $this->getKey(); - $version->versionable_type = method_exists($this, 'getMorphClass') ? $this->getMorphClass() : get_class($this); - $version->user_id = $this->getAuthUserId(); - - $versionedHiddenFields = $this->versionedHiddenFields ?? []; - $this->makeVisible($versionedHiddenFields); - $version->model_data = serialize($this->attributesToArray()); - $this->makeHidden($versionedHiddenFields); - - if (!empty( $this->reason )) { - $version->reason = $this->reason; - } - - $version->save(); - - $this->purgeOldVersions(); - } + Version::createVersionForModel($this); } } @@ -200,7 +174,7 @@ protected function versionablePostSave() * * @return void */ - private function purgeOldVersions() + public function purgeOldVersions() { $keep = isset($this->keepOldVersions) ? $this->keepOldVersions : 0; @@ -224,7 +198,7 @@ private function purgeOldVersions() * * @return bool */ - private function isValidForVersioning() + public function isValidForVersioning() { $dontVersionFields = isset( $this->dontVersionFields ) ? $this->dontVersionFields : []; $removeableKeys = array_merge($dontVersionFields, [$this->getUpdatedAtColumn()]); From d1a88b8bbfa3887c79928cfb3677039498e85914 Mon Sep 17 00:00:00 2001 From: Jonathan van Rij Date: Wed, 7 Dec 2022 08:13:48 +0100 Subject: [PATCH 4/5] passes the model to the job --- .../Versionable/Jobs/VersionableJob.php | 22 +++++++++++++------ src/Mpociot/Versionable/Version.php | 8 ------- src/Mpociot/Versionable/VersionableTrait.php | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Mpociot/Versionable/Jobs/VersionableJob.php b/src/Mpociot/Versionable/Jobs/VersionableJob.php index f82bd44..f738dfb 100644 --- a/src/Mpociot/Versionable/Jobs/VersionableJob.php +++ b/src/Mpociot/Versionable/Jobs/VersionableJob.php @@ -2,15 +2,14 @@ namespace Mpociot\Versionable\Jobs; -use Adaptor\Core\Classes\ServiceExecutionData; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Arr; -use Illuminate\Support\Str; use Mpociot\Versionable\Version; +use ReflectionClass; use ReflectionException; class VersionableJob implements ShouldQueue @@ -20,9 +19,17 @@ class VersionableJob implements ShouldQueue use Queueable; use SerializesModels; - public function __construct(private int $id, private string $modelClass, private array $attributes, private array $originalAttributes) + private int $id; + private string $modelClass; + private array $attributes; + private array $originalAttributes; + + public function __construct(private Model $model, private string $reason) { -// \Log::info('model', ['id' => $id, 'class' => $modelClass, 'attributes' => $this->attributes, 'original' => $this->originalAttributes]); + $this->attributes = $this->model->getAttributes(); + $this->originalAttributes = $this->model->getOriginal(); + $this->id = $this->model->id; + $this->modelClass = get_class($this->model); } /** @@ -30,7 +37,7 @@ public function __construct(private int $id, private string $modelClass, private */ public function handle() { - $resourceReflection = new \ReflectionClass($this->modelClass); + $resourceReflection = new ReflectionClass($this->modelClass); $staticResource = $resourceReflection->newInstanceWithoutConstructor(); $model = $staticResource->find($this->id); @@ -45,7 +52,8 @@ public function handle() } $model->versionableDirtyData = $model->getDirty(); - $model->updating = $model->exists; + $model->updating = $model->exists; + $model->reason = $this->reason; Version::createVersionForModel($model); } diff --git a/src/Mpociot/Versionable/Version.php b/src/Mpociot/Versionable/Version.php index 7c60a3f..f05aff9 100644 --- a/src/Mpociot/Versionable/Version.php +++ b/src/Mpociot/Versionable/Version.php @@ -112,8 +112,6 @@ public static function createVersionForModel(Model $model) ( $model->versioningEnabled === true && $model->updating && $model->isValidForVersioning() ) || ( $model->versioningEnabled === true && !$model->updating && !is_null($model->versionableDirtyData) && count($model->versionableDirtyData)) ) { - \Log::info('2'); - // Save a new version $class = $model->getVersionClass(); $version = new $class(); @@ -121,21 +119,15 @@ public static function createVersionForModel(Model $model) $version->versionable_type = method_exists($model, 'getMorphClass') ? $model->getMorphClass() : get_class($model); $version->user_id = $model->getAuthUserId(); - \Log::info('3'); - $versionedHiddenFields = $model->versionedHiddenFields ?? []; $model->makeVisible($versionedHiddenFields); $version->model_data = serialize($model->attributesToArray()); $model->makeHidden($versionedHiddenFields); - \Log::info('4'); - if (!empty( $model->reason )) { $version->reason = $model->reason; } - \Log::info('5'); - $version->save(); $model->purgeOldVersions(); diff --git a/src/Mpociot/Versionable/VersionableTrait.php b/src/Mpociot/Versionable/VersionableTrait.php index 4212935..32be169 100644 --- a/src/Mpociot/Versionable/VersionableTrait.php +++ b/src/Mpociot/Versionable/VersionableTrait.php @@ -48,7 +48,7 @@ public function getVersionClass() * Optional reason, why this version was created * @var string */ - private $reason; + public $reason; /** * Flag that determines if the model allows versioning at all @@ -163,7 +163,7 @@ protected function versionablePreSave() protected function versionablePostSave() { if (config('versionable.use_queue', false)) { - VersionableJob::dispatch($this->id, get_class($this), $this->getAttributes(), $this->getRawOriginal()); + VersionableJob::dispatch($this, $this?->reason); } else { Version::createVersionForModel($this); } From e4a1285920a46fc0beb7db298862062609b0a9ab Mon Sep 17 00:00:00 2001 From: Jonathan van Rij Date: Wed, 7 Dec 2022 09:18:56 +0100 Subject: [PATCH 5/5] gives reason a default of null when dispatching the job --- src/Mpociot/Versionable/Jobs/VersionableJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mpociot/Versionable/Jobs/VersionableJob.php b/src/Mpociot/Versionable/Jobs/VersionableJob.php index f738dfb..3b27bdc 100644 --- a/src/Mpociot/Versionable/Jobs/VersionableJob.php +++ b/src/Mpociot/Versionable/Jobs/VersionableJob.php @@ -24,7 +24,7 @@ class VersionableJob implements ShouldQueue private array $attributes; private array $originalAttributes; - public function __construct(private Model $model, private string $reason) + public function __construct(private Model $model, private string|null $reason = null) { $this->attributes = $this->model->getAttributes(); $this->originalAttributes = $this->model->getOriginal();