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

Adapting the library to be used with API #280

Open
wants to merge 4 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
309 changes: 309 additions & 0 deletions src/Venturecraft/Revisionable/CommonTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
<?php
namespace Venturecraft\Revisionable;

use Venturecraft\Revisionable\Revision;

trait CommonTrait
{
/**
* @var array
*/
private $originalData = array();

/**
* @var array
*/
private $updatedData = array();

/**
* @var boolean
*/
private $updating = false;

/**
* @var array
*/
private $dontKeep = array();

/**
* @var array
*/
private $doKeep = array();

/**
* Keeps the list of values that have been updated
*
* @var array
*/
protected $dirtyData = array();


/**
* Ensure that the bootRevisionableTrait is called only
* if the current installation is a laravel 4 installation
* Laravel 5 will call bootRevisionableTrait() automatically
*/
public static function boot()
{
parent::boot();

if (!method_exists(get_called_class(), 'bootTraits')) {
static::bootRevisionableTrait();
}
}

/**
* Create the event listeners for the saving and saved events
* This lets us save revisions whenever a save is made, no matter the
* http method.
*
*/
public static function bootRevisionableTrait()
{
static::saving(function ($model) {
$model->preSave();
});

static::saved(function ($model) {
$model->postSave();
});

static::created(function($model){
$model->postCreate();
});

static::deleted(function ($model) {
$model->preSave();
$model->postDelete();
});
}

/**
* @return mixed
*/
public function revisionHistory()
{
return $this->morphMany(Revision::class, 'revisionable');
}

/**
* Invoked before a model is saved. Return false to abort the operation.
*
* @return bool
*/
public function preSave()
{
if (!isset($this->revisionEnabled) || $this->revisionEnabled) {
// if there's no revisionEnabled. Or if there is, if it's true

$this->originalData = $this->original;
$this->updatedData = $this->attributes;

// we can only safely compare basic items,
// so for now we drop any object based items, like DateTime
foreach ($this->updatedData as $key => $val) {
if (gettype($val) == 'object' && !method_exists($val, '__toString')) {
unset($this->originalData[$key]);
unset($this->updatedData[$key]);
array_push($this->dontKeep, $key);
}
}

// the below is ugly, for sure, but it's required so we can save the standard model
// then use the keep / dontkeep values for later, in the isRevisionable method
$this->dontKeep = isset($this->dontKeepRevisionOf) ?
array_merge($this->dontKeepRevisionOf, $this->dontKeep)
: $this->dontKeep;

$this->doKeep = isset($this->keepRevisionOf) ?
array_merge($this->keepRevisionOf, $this->doKeep)
: $this->doKeep;

unset($this->attributes['dontKeepRevisionOf']);
unset($this->attributes['keepRevisionOf']);

$this->dirtyData = $this->getDirty();
$this->updating = $this->exists;
}
}

/**
* Attempt to find the user id of the currently logged in user
* Supports Cartalyst Sentry/Sentinel based authentication, as well as stock Auth
**/
public function getSystemUserId()
{
$sessionUserId = app('request')->input('session_user_id', null);

try {
if (class_exists($class = '\SleepingOwl\AdminAuth\Facades\AdminAuth')
|| class_exists($class = '\Cartalyst\Sentry\Facades\Laravel\Sentry')
|| class_exists($class = '\Cartalyst\Sentinel\Laravel\Facades\Sentinel')
) {
return ($class::check()) ? $class::getUser()->id : null;
} elseif (\Auth::check()) {
return \Auth::user()->getAuthIdentifier();
} elseif ($sessionUserId) {
return $sessionUserId;
}
} catch (\Exception $e) {
return null;
}

return null;
}

/**
* Get all of the changes that have been made, that are also supposed
* to have their changes recorded
*
* @return array fields with new data, that should be recorded
*/
private function changedRevisionableFields()
{
$changes_to_record = array();
foreach ($this->dirtyData as $key => $value) {
// check that the field is revisionable, and double check
// that it's actually new data in case dirty is, well, clean
if ($this->isRevisionable($key) && !is_array($value)) {
if (!isset($this->originalData[$key]) || $this->originalData[$key] != $this->updatedData[$key]) {
$changes_to_record[$key] = $value;
}
} else {
// we don't need these any more, and they could
// contain a lot of data, so lets trash them.
unset($this->updatedData[$key]);
unset($this->originalData[$key]);
}
}

return $changes_to_record;
}

/**
* Check if this field should have a revision kept
*
* @param string $key
*
* @return bool
*/
private function isRevisionable($key)
{

// If the field is explicitly revisionable, then return true.
// If it's explicitly not revisionable, return false.
// Otherwise, if neither condition is met, only return true if
// we aren't specifying revisionable fields.
if (isset($this->doKeep) && in_array($key, $this->doKeep)) {
return true;
}
if (isset($this->dontKeep) && in_array($key, $this->dontKeep)) {
return false;
}

return empty($this->doKeep);
}

/**
* Check if soft deletes are currently enabled on this model
*
* @return bool
*/
private function isSoftDelete()
{
// check flag variable used in laravel 4.2+
if (isset($this->forceDeleting)) {
return !$this->forceDeleting;
}

// otherwise, look for flag used in older versions
if (isset($this->softDelete)) {
return $this->softDelete;
}

return false;
}

/**
* @return mixed
*/
public function getRevisionFormattedFields()
{
return $this->revisionFormattedFields;
}

/**
* @return mixed
*/
public function getRevisionFormattedFieldNames()
{
return $this->revisionFormattedFieldNames;
}

/**
* Identifiable Name
* When displaying revision history, when a foreign key is updated
* instead of displaying the ID, you can choose to display a string
* of your choice, just override this method in your model
* By default, it will fall back to the models ID.
*
* @return string an identifying name for the model
*/
public function identifiableName()
{
return $this->getKey();
}

/**
* Revision Unknown String
* When displaying revision history, when a foreign key is updated
* instead of displaying the ID, you can choose to display a string
* of your choice, just override this method in your model
* By default, it will fall back to the models ID.
*
* @return string an identifying name for the model
*/
public function getRevisionNullString()
{
return isset($this->revisionNullString) ? $this->revisionNullString : 'nothing';
}

/**
* No revision string
* When displaying revision history, if the revisions value
* cant be figured out, this is used instead.
* It can be overridden.
*
* @return string an identifying name for the model
*/
public function getRevisionUnknownString()
{
return isset($this->revisionUnknownString) ? $this->revisionUnknownString : 'unknown';
}

/**
* Disable a revisionable field temporarily
* Need to do the adding to array longhanded, as there's a
* PHP bug https://bugs.php.net/bug.php?id=42030
*
* @param mixed $field
*
* @return void
*/
public function disableRevisionField($field)
{
if (!isset($this->dontKeepRevisionOf)) {
$this->dontKeepRevisionOf = array();
}
if (is_array($field)) {
foreach ($field as $one_field) {
$this->disableRevisionField($one_field);
}
} else {
$donts = $this->dontKeepRevisionOf;
$donts[] = $field;
$this->dontKeepRevisionOf = $donts;
unset($donts);
}
}
}
Loading