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

fix: Rolling Back Model Fields with JSON Data #55

Merged
Merged
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
12 changes: 10 additions & 2 deletions src/Concerns/MustBeApproved.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ protected static function insertApprovalRequest($model)
{
$filteredDirty = $model->getDirtyAttributes();

if (auth()->check()) {
$filteredDirty['user_id'] = auth()->id();
foreach ($filteredDirty as $key => $value) {
if (isset($model->casts[$key]) && $model->casts[$key] === 'json') {
$filteredDirty[$key] = json_decode(json: $value, associative: true);
}
}

if ($model->isApprovalBypassed() || empty($filteredDirty)) {
Expand Down Expand Up @@ -141,6 +143,12 @@ public function withoutApproval(): static
public function callCastAttribute($key, $value): mixed
{
if (array_key_exists($key, $this->casts)) {
// If the value is already an array, return it as is
if (is_array($value)) {
return $value;
}

// Otherwise, cast the attribute to its defined type
return $this->castAttribute($key, $value);
}

Expand Down
67 changes: 62 additions & 5 deletions tests/Feature/MustBeApprovedTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,7 @@
});

test(description: 'an approvals model is created when a model is created with MustBeApproved trait set and has the approvalInclude array set', closure: function () {
$model = new class extends Model
{
$model = new class extends Model {
use MustBeApproved;

protected $table = 'fake_models';
Expand Down Expand Up @@ -179,8 +178,7 @@
$table->json('data')->nullable();
});

$model = new class extends Model
{
$model = new class extends Model {
use MustBeApproved;

protected $table = 'fake_models_with_array';
Expand Down Expand Up @@ -219,9 +217,68 @@
'data' => json_encode(['foo', 'bar']),
]);

// double check the model
// double-check the model
$modelFromDatabase = $model->firstWhere('name', 'Neo');

expect($modelFromDatabase->data)
->toBe(['foo', 'bar']);
});

test(description: 'a Model can be rolled back when the data contains JSON fields', closure: function () {
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('content');
$table->json('config');
$table->timestamps();
});

$model = new class extends Model {
use MustBeApproved;

protected $table = 'posts';

protected $guarded = [];

protected $casts = ['config' => 'json'];
};

// create a model
$model->create([
'title' => 'My First Post',
'content' => 'This is my first post',
'config' => ['checked' => true],
]);

// check if the data is stored correctly in the approval table
$this->assertDatabaseHas(table: Approval::class, data: [
'new_data' => json_encode([
'title' => 'My First Post',
'content' => 'This is my first post',
'config' => ['checked' => true],
]),
'original_data' => json_encode([]),
]);

// nothing should be in the 'posts' table
$this->assertDatabaseCount('posts', 0);

// approve the model
Approval::first()->approve();

// after approval, there should be in an entry in the 'posts' table
$this->assertDatabaseCount('posts', 1);

// After Approval, the contents of the database should look like this
$this->assertDatabaseHas(table: 'posts', data: [
'title' => 'My First Post',
'content' => 'This is my first post',
'config' => json_encode(['checked' => true]),
]);

// double-check the model
$modelFromDatabase = $model->firstWhere('title', 'My First Post');

expect($modelFromDatabase->config)
->toBe(['checked' => true]);
});
Loading