diff --git a/src/Casts/SchemalessAttributes.php b/src/Casts/SchemalessAttributes.php index 8f483bc..1cc6db2 100644 --- a/src/Casts/SchemalessAttributes.php +++ b/src/Casts/SchemalessAttributes.php @@ -32,19 +32,31 @@ public function get($model, $key, $value, $attributes) */ public function set($model, $key, $value, $attributes) { - if ($this->isJson($value)) { + if ($this->isJsonArray($value)) { return $value; } - return json_encode($value); + $json = json_encode($value); + + if (! is_array(json_decode($json, true))) { + return null; + } + + return $json; } - protected function isJson($value): bool + protected function isJsonArray($value): bool { if (! is_string($value)) { return false; } - return $value === json_encode(json_decode($value)); + $array = json_decode($value, true); + + if (! is_array($array)) { + return false; + } + + return $value === json_encode($array); } } diff --git a/src/SchemalessAttributes.php b/src/SchemalessAttributes.php index cfd7f18..ff7e7d9 100644 --- a/src/SchemalessAttributes.php +++ b/src/SchemalessAttributes.php @@ -177,7 +177,9 @@ protected function getRawSchemalessAttributes(): array { $attributes = $this->model->getAttributes()[$this->sourceAttributeName] ?? '{}'; - return $attributes === '""' ? [] : $this->model->fromJson($attributes); + $array = $this->model->fromJson($attributes); + + return is_array($array) ? $array : []; } protected function override(iterable $collection): static diff --git a/tests/HasSchemalessAttributesTest.php b/tests/HasSchemalessAttributesTest.php index ed92e3c..73c75b9 100644 --- a/tests/HasSchemalessAttributesTest.php +++ b/tests/HasSchemalessAttributesTest.php @@ -49,6 +49,31 @@ public function an_schemaless_attribute_can_be_set_from_json() $this->assertEquals('value', $this->testModel->schemaless_attributes->name); } + /** @test */ + public function an_schemaless_attribute_uses_fallback_empty_array_on_non_valid_values() + { + $this->testModel->schemaless_attributes = 'string'; + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + + $this->testModel->schemaless_attributes = '""'; // not array json + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + + $this->testModel->schemaless_attributes = "{'name':'value'}"; // invalid json format + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + + $this->testModel->schemaless_attributes = null; + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + + $this->testModel->schemaless_attributes = false; + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + + $this->testModel->schemaless_attributes = 1; + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + + $this->testModel->schemaless_attributes = 0.1; + $this->assertEquals([], $this->testModel->schemaless_attributes->all()); + } + /** @test */ public function it_can_determine_if_it_has_a_schemaless_attribute() { @@ -266,6 +291,31 @@ public function it_can_and_save_schemaless_attributes_from_json() $this->assertEquals($array, $testModel->schemaless_attributes->all()); } + /** @test */ + public function it_can_and_save_schemaless_attributes_as_null_when_non_valid_values() + { + $testModel = TestModel::create(['schemaless_attributes' => 'string']); + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + + $testModel = TestModel::create(['schemaless_attributes' => '""']); // not array json + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + + $testModel = TestModel::create(['schemaless_attributes' => "{'name':'value'}"]); // invalid json format + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + + $testModel = TestModel::create(['schemaless_attributes' => null]); + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + + $testModel = TestModel::create(['schemaless_attributes' => false]); + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + + $testModel = TestModel::create(['schemaless_attributes' => 1]); + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + + $testModel = TestModel::create(['schemaless_attributes' => 0.1]); + $this->assertEquals(null, $testModel->getAttributes()['schemaless_attributes']); + } + /** @test */ public function it_has_a_scope_to_get_models_with_the_given_schemaless_attributes() {