diff --git a/src/Concerns/MustBeApproved.php b/src/Concerns/MustBeApproved.php index 21a52d0..183353a 100644 --- a/src/Concerns/MustBeApproved.php +++ b/src/Concerns/MustBeApproved.php @@ -58,7 +58,7 @@ protected static function insertApprovalRequest($model) if ($noNeedToProceed) { return false; } - return; + } /** @@ -127,4 +127,20 @@ public function withoutApproval(): static return $this; } + + /** + * Wrapper to access the castAttribute function + * + * @param $key + * @param $value + * @return mixed + */ + public function callCastAttribute($key, $value): mixed + { + if (array_key_exists($key, $this->casts)) { + return $this->castAttribute($key, $value); + } + + return $value; + } } diff --git a/src/Scopes/ApprovalStateScope.php b/src/Scopes/ApprovalStateScope.php index abb3e7e..15faf35 100644 --- a/src/Scopes/ApprovalStateScope.php +++ b/src/Scopes/ApprovalStateScope.php @@ -104,7 +104,15 @@ protected function addApprove(Builder $builder): void $model = $model->find($modelId); } - $model->forceFill($builder->getModel()->new_data->toArray()); + $newData = $builder->getModel()->new_data->toArray(); + + // make sure we cast all attributes + foreach ($newData as $key => $value) { + $newData[$key] = $model->callCastAttribute($key, $value); + } + + $model->forceFill($newData); + $model->withoutApproval()->save(); } diff --git a/tests/Feature/MustBeApprovedTraitTest.php b/tests/Feature/MustBeApprovedTraitTest.php index 7d0ca6d..ab71acd 100644 --- a/tests/Feature/MustBeApprovedTraitTest.php +++ b/tests/Feature/MustBeApprovedTraitTest.php @@ -5,6 +5,8 @@ use Cjmellor\Approval\Models\Approval; use Cjmellor\Approval\Tests\Models\FakeModel; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; it(description: 'stores the data correctly in the database') ->defer( @@ -166,3 +168,59 @@ 'meta' => 'blue', ]); }); + +test(description: 'approve a attribute of the type Array', closure: function () { + Schema::create('fake_models_with_array', function (Blueprint $table) { + $table->id(); + $table->string('name')->nullable(); + $table->string('meta')->nullable(); + + $table->json('data')->nullable(); + }); + + $model = new class extends Model + { + use MustBeApproved; + + protected $table = 'fake_models_with_array'; + + protected $guarded = []; + + public $timestamps = false; + + protected $casts = ['data' => 'array']; + }; + + // create a model + $model->create([ + 'name' => 'Neo', + 'data' => ['foo', 'bar'], + ]); + + // check if the data is stored correctly in the approval table + $this->assertDatabaseHas(table: Approval::class, data: [ + 'new_data' => json_encode(['name' => 'Neo', 'data' => json_encode(['foo', 'bar'])]), + 'original_data' => json_encode([]), + ]); + + // nothing should be in the 'fake_models_with_array' table + $this->assertDatabaseCount('fake_models_with_array', 0); + + // approve the model + Approval::first()->approve(); + + // after approval, there should be in an entry in the 'fake_models_with_array' table + $this->assertDatabaseCount('fake_models_with_array', 1); + + // After Approval, the contents of the database should look like this + $this->assertDatabaseHas(table: 'fake_models_with_array', data: [ + 'name' => 'Neo', + 'data' => json_encode(['foo', 'bar']), + ]); + + // double check the model + $modelFromDatabase = $model->firstWhere('name', 'Neo'); + + expect($modelFromDatabase->data) + ->toBe(['foo', 'bar']); +});