Last active
November 27, 2021 03:50
-
-
Save kkiernan/8d258e74b6fd0a30f1c88420f7068c28 to your computer and use it in GitHub Desktop.
Versioning trait for Laravel models
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use App\Traits\Versionable; | |
use Illuminate\Database\Eloquent\Model; | |
class Post extends Model | |
{ | |
use Versionable; | |
/** | |
* @var array | |
*/ | |
protected $fillable = ['title', 'body', 'status_id', 'user_id']; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use Illuminate\Database\Eloquent\Model; | |
class PostVersion extends Model | |
{ | |
/** | |
* @var array | |
*/ | |
protected $fillable = ['title', 'body', 'status_id', 'user_id', 'post_id']; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Traits; | |
use ReflectionClass; | |
/** | |
* Save a copy of the model to the model's corresponding | |
* "versions" table on create and update. | |
* | |
* Idea: Look into handling all model versioning with a | |
* single db table that stores the attributes as json. | |
* | |
* Currently this trait requires manually creating the | |
* corresponding model and database migration. | |
*/ | |
trait Versionable | |
{ | |
/** | |
* Boot the trait. | |
* | |
* @return void | |
*/ | |
public static function bootVersionable() | |
{ | |
static::created(function ($model) { | |
$model->snapshot(); | |
}); | |
static::updated(function ($model) { | |
$model->snapshot(); | |
}); | |
} | |
/** | |
* Save a snapshot of the current model. | |
* | |
* @return void | |
*/ | |
protected function snapshot() | |
{ | |
$oidFieldName = $this->getOriginalIdFieldName(); | |
$class = $this->getVersionModelClassName(); | |
$class::create($this->toArray() + ['id' => null, $oidFieldName => $this->id]); | |
} | |
/** | |
* Get the name of the foreign key field that references the original record. | |
* | |
* @example For a Post model, this returns "post_id" by default | |
* | |
* @return string | |
*/ | |
protected function getOriginalIdFieldName() | |
{ | |
return strtolower((new ReflectionClass($this))->getShortName()) . '_id'; | |
} | |
/** | |
* Get the class name of the "version model". | |
* | |
* @example For an App\Post model, this returns "App\PostVersion" by default | |
* | |
* @return string | |
*/ | |
protected function getVersionModelClassName() | |
{ | |
return get_class($this) . 'Version'; | |
} | |
/** | |
* This model can have many versions. | |
* | |
* @return Illuminate\Database\Eloquent\Relations\HasMany | |
*/ | |
public function versions() | |
{ | |
return $this->hasMany($this->getVersionModelClassName(), $this->getOriginalIdFieldName()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment