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

Adding pivot attach and detach revisions #424

Open
wants to merge 6 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
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"require": {
"php": ">=5.4.0",
"illuminate/support": "~4.0|~5.0|~5.1|^6.0|^7.0|^8.0|^9.0|^10.0",
"laravel/framework": "~5.4|^6.0|^7.0|^8.0|^9.0|^10.0"
"laravel/framework": "~5.4|^6.0|^7.0|^8.0|^9.0|^10.0",
"fico7489/laravel-pivot": "3.0.*"
},
"autoload": {
"classmap": [
Expand Down
9 changes: 9 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ If you want to store the creation as a revision you can override this behavior b
protected $revisionCreationsEnabled = true;
```

### Traccking many to many relationship
By default the many to many relationship is not stored as a revision.
You can track BelongsToMany and MorphToMany attach and detach events.

If you want to store these events as a revision you can override this behavior by setting `manyToManyRevisionEnabled` to `true` by adding the following to your model:
```php
protected $manyToManyRevisionEnabled = true;
```

## More Control

No doubt, there'll be cases where you don't want to store a revision history only for certain fields of the model, this is supported in two different ways. In your model you can either specifiy which fields you explicitly want to track and all other fields are ignored:
Expand Down
92 changes: 78 additions & 14 deletions src/Venturecraft/Revisionable/RevisionableTrait.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php namespace Venturecraft\Revisionable;
<?php

namespace Venturecraft\Revisionable;

use Illuminate\Support\Arr;
use Fico7489\Laravel\Pivot\Traits\PivotEventTrait;

/*
* This file is part of the Revisionable package by Venture Craft
Expand All @@ -15,6 +18,8 @@
*/
trait RevisionableTrait
{
use PivotEventTrait;

/**
* @var array
*/
Expand Down Expand Up @@ -86,6 +91,17 @@ public static function bootRevisionableTrait()
$model->postDelete();
$model->postForceDelete();
});

// ManyToMany listeners
static::pivotAttached(function ($model, $relationName, $pivotIds, $pivotIdsAttributes) {
$pivotClass = get_class($model->$relationName()->getRelated());
$model->postPivotSimpleEvent('attached', $pivotClass, $pivotIds[0], $pivotIdsAttributes);
});

static::pivotDetached(function ($model, $relationName, $pivotIds, $pivotIdsAttributes) {
$pivotClass = get_class($model->$relationName()->getRelated());
$model->postPivotSimpleEvent('detached', $pivotClass, $pivotIds[0], $pivotIdsAttributes);
});
}

/**
Expand Down Expand Up @@ -173,10 +189,11 @@ public function postSave()
} else {
$LimitReached = false;
}

if (isset($this->revisionCleanup)){
$RevisionCleanup=$this->revisionCleanup;
}else{
$RevisionCleanup=false;
$RevisionCleanup = $this->revisionCleanup;
} else {
$RevisionCleanup = false;
}

// check if the model already exists
Expand All @@ -203,12 +220,13 @@ public function postSave()
}

if (count($revisions) > 0) {
if($LimitReached && $RevisionCleanup){
if ($LimitReached && $RevisionCleanup) {
$toDelete = $this->revisionHistory()->orderBy('id','asc')->limit(count($revisions))->get();
foreach($toDelete as $delete){
foreach($toDelete as $delete) {
$delete->delete();
}
}

$revision = Revisionable::newModel();
\DB::table($revision->getTable())->insert($revisions);
\Event::dispatch('revisionable.saved', array('model' => $this, 'revisions' => $revisions));
Expand All @@ -224,14 +242,12 @@ public function postCreate()

// Check if we should store creations in our revision history
// Set this value to true in your model if you want to
if(empty($this->revisionCreationsEnabled))
{
if (empty($this->revisionCreationsEnabled)) {
// We should not store creations.
return false;
}

if ((!isset($this->revisionEnabled) || $this->revisionEnabled))
{
if ((!isset($this->revisionEnabled) || $this->revisionEnabled)) {
$revisions[] = array(
'revisionable_type' => $this->getMorphClass(),
'revisionable_id' => $this->getKey(),
Expand Down Expand Up @@ -314,6 +330,51 @@ public function postForceDelete()
}
}

/**
* Called after many to many record successfully attached or detached
*
* @param string $event
* @param string $pivotModel
* @param integer $pivotId
* @param array $pivotAttributes
* @return void
*/
public function postPivotSimpleEvent(string $event, string $pivotModel, int $pivotId, array $pivotAttributes): void
{
// Many to many revisions are disabled by default
if (!isset($this->manyToManyRevisionEnabled) || !$this->manyToManyRevisionEnabled) {
return;
}

// Revision for pivots
$revisions[] = [
'revisionable_type' => $pivotModel,
'revisionable_id' => $pivotId,
'key' => "{$event}-to",
'old_value' => get_class($this),
'new_value' => $this->id,
'user_id' => $this->getSystemUserId(),
'created_at' => new \DateTime(),
'updated_at' => new \DateTime(),
];

// Revision for yourself
$revisions[] = [
'revisionable_type' => get_class($this),
'revisionable_id' => $this->id,
'key' => "{$event}-from",
'old_value' => $pivotModel,
'new_value' => $pivotId,
'user_id' => $this->getSystemUserId(),
'created_at' => new \DateTime(),
'updated_at' => new \DateTime(),
];

$revision = Revisionable::newModel();
\DB::table($revision->getTable())->insert($revisions);
\Event::dispatch("revisionable.pivot.{$event}", ['model' => $this, 'revisions' => $revisions]);
}

/**
* Attempt to find the user id of the currently logged in user
* Supports Cartalyst Sentry/Sentinel based authentication, as well as stock Auth
Expand All @@ -338,15 +399,14 @@ public function getSystemUserId()
return null;
}


public function getAdditionalFields()
{
$additional = [];
//Determine if there are any additional fields we'd like to add to our model contained in the config file, and
//get them into an array.
$fields = config('revisionable.additional_fields', []);
foreach($fields as $field) {
if(Arr::has($this->originalData, $field)) {
if (Arr::has($this->originalData, $field)) {
$additional[$field] = Arr::get($this->originalData, $field);
}
}
Expand Down Expand Up @@ -398,6 +458,7 @@ private function isRevisionable($key)
if (isset($this->doKeep) && in_array($key, $this->doKeep)) {
return true;
}

if (isset($this->dontKeep) && in_array($key, $this->dontKeep)) {
return false;
}
Expand Down Expand Up @@ -496,6 +557,7 @@ public function disableRevisionField($field)
if (!isset($this->dontKeepRevisionOf)) {
$this->dontKeepRevisionOf = array();
}

if (is_array($field)) {
foreach ($field as $one_field) {
$this->disableRevisionField($one_field);
Expand All @@ -522,10 +584,12 @@ public function disableRevisionField($field)
*/
private function sortJsonKeys($attribute)
{
if(empty($attribute)) return $attribute;
if (empty($attribute)) {
return $attribute;
}

foreach ($attribute as $key=>$value) {
if(is_array($value) || is_object($value)){
if (is_array($value) || is_object($value)) {
$value = $this->sortJsonKeys($value);
} else {
continue;
Expand Down