Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds the option to run the versioning logic within a queue job #95

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/Mpociot/Versionable/Jobs/VersionableJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace Mpociot\Versionable\Jobs;

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 Mpociot\Versionable\Version;
use ReflectionClass;
use ReflectionException;

class VersionableJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;

private int $id;
private string $modelClass;
private array $attributes;
private array $originalAttributes;

public function __construct(private Model $model, private string|null $reason = null)
{
$this->attributes = $this->model->getAttributes();
$this->originalAttributes = $this->model->getOriginal();
$this->id = $this->model->id;
$this->modelClass = get_class($this->model);
}

/**
* @throws ReflectionException
*/
public function handle()
{
$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;
$model->reason = $this->reason;

Version::createVersionForModel($model);
}
}
28 changes: 28 additions & 0 deletions src/Mpociot/Versionable/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -105,4 +106,31 @@ 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))
) {
// 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();
}
}
}
56 changes: 17 additions & 39 deletions src/Mpociot/Versionable/VersionableTrait.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
<?php
namespace Mpociot\Versionable;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Log;
use Mpociot\Versionable\Jobs\VersionableJob;

/**
* Class VersionableTrait
* @package Mpociot\Versionable
*/
trait VersionableTrait
{

/**
* Retrieve, if exists, the property that define that Version model.
* If no property defined, use the default Version model.
*
*
* Trait cannot share properties whth their class !
* 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;
Expand All @@ -40,19 +42,19 @@ protected function getVersionClass()
*
* @var array
*/
private $versionableDirtyData;
public $versionableDirtyData;

/**
* Optional reason, why this version was created
* @var string
*/
private $reason;
public $reason;

/**
* Flag that determines if the model allows versioning at all
* @var bool
*/
protected $versioningEnabled = true;
public $versioningEnabled = true;

/**
* @return $this
Expand Down Expand Up @@ -160,47 +162,25 @@ 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();
if (config('versionable.use_queue', false)) {
VersionableJob::dispatch($this, $this?->reason);
} else {
Version::createVersionForModel($this);
}
}

/**
* Delete old versions of this model when they reach a specific count.
*
*
* @return void
*/
private function purgeOldVersions()
public function purgeOldVersions()
{
$keep = isset($this->keepOldVersions) ? $this->keepOldVersions : 0;

if ((int)$keep > 0) {
$count = $this->versions()->count();

if ($count > $keep) {
$this->getLatestVersions()
->take($count)
Expand All @@ -218,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()]);
Expand All @@ -245,6 +225,4 @@ protected function getLatestVersions()
{
return $this->versions()->orderByDesc('version_id');
}


}
10 changes: 8 additions & 2 deletions src/config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,

];

/*
* Here you can configure the versioning logic
* to be handled within a separate job.
*/
'use_queue' => env('VERSIONING_USE_QUEUE', false)
];