diff --git a/ArrayAccess/ArrayAccess.php b/ArrayAccess/ArrayAccess.php index 968ab96..9603233 100644 --- a/ArrayAccess/ArrayAccess.php +++ b/ArrayAccess/ArrayAccess.php @@ -42,7 +42,7 @@ public static function createWithJsonSchemaValidation($value, string $jsonSchema $result = (new Validator())->schemaValidation(\json_decode(\json_encode($value)), $schema, 10); if (!$result->isValid()) { - throw ArrayAccessFailed::jsonSchemaValidationFailed(...$result->getErrors()); + throw ArrayAccessValidationFailed::withValidationErrors(...$result->getErrors()); } return new self($value); @@ -63,15 +63,19 @@ public static function newFromDotAnnotation(DotAnnotation ...$dotAnnotations): s return new self($newArray); } - public function writeAtPath($value, ...$path): self + public function writeAtPath($value, string ...$path): self { - $pointer = &$this->data; + $instance = new self($this->data); + + $path = empty($path) ? [0] : $path; + + $pointer = &$instance->data; foreach ($path as $key) { $pointer = &$pointer[$key]; } $pointer = $value; - return new self($this->data); + return $instance; } public function hasPath(...$path): bool diff --git a/ArrayAccess/ArrayAccessValidationFailed.php b/ArrayAccess/ArrayAccessValidationFailed.php new file mode 100644 index 0000000..c1f198c --- /dev/null +++ b/ArrayAccess/ArrayAccessValidationFailed.php @@ -0,0 +1,44 @@ +keyword(), + \implode(', ', $error->dataPointer()), + ); + }, + $errors + ); + + $instance = new self( + \sprintf('Json schema validation failed: %s', \implode(', ', $messages)) + ); + + $instance->errors = $errors; + $instance->errorMapping = ArrayAccess::create([]); + foreach ($errors as $error) { + $instance->errorMapping = $instance->errorMapping->writeAtPath((string) $error->keyword(), ...$error->dataPointer()); + } + + return $instance; + } + + public function errorMapping(): ArrayAccess + { + return $this->errorMapping; + } +} \ No newline at end of file diff --git a/README.md b/README.md index 1c26040..b000edf 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,9 @@ JSON schema: } ``` +If validation fails, an `ArrayAccessValidationFailed` exception will be thrown. +You can get an `ArrayAccess` object of validation errors by calling the method `errorMapping()` on the exception. + ### Access values ``` $array = [ diff --git a/Tests/ArrayAccess/ArrayAccessTest.php b/Tests/ArrayAccess/ArrayAccessTest.php index 175c9d3..277387a 100644 --- a/Tests/ArrayAccess/ArrayAccessTest.php +++ b/Tests/ArrayAccess/ArrayAccessTest.php @@ -6,6 +6,7 @@ use BadMethodCallException; use Mschindler83\ArrayAccess\ArrayAccess; use Mschindler83\ArrayAccess\ArrayAccessFailed; +use Mschindler83\ArrayAccess\ArrayAccessValidationFailed; use Mschindler83\ArrayAccess\DotAnnotation\SimpleDotAnnotation; use PHPUnit\Framework\TestCase; @@ -48,7 +49,7 @@ public function it_validates_with_json_schema_validator(): void */ public function it_raises_an_exception_on_failed_json_schema_validation(): void { - $this->expectException(ArrayAccessFailed::class); + $this->expectException(ArrayAccessValidationFailed::class); $this->expectExceptionMessage('Json schema validation failed: Error: [minLength], Data pointer: [key1], Error: [type], Data pointer: [key2], Error: [additionalProperties], Data pointer: []'); $data = [ @@ -155,7 +156,8 @@ public function it_can_write_at_path(): void ]; $access = ArrayAccess::create($testArray); - $newAccess = $access->writeAtPath('new-value', 'Foo', 'Bar', 'New'); + $access = $access->writeAtPath('new-value', 'Foo', 'Bar', 'New'); + $access = $access->writeAtPath('new-value-2', 'Foo', 'Bar', 'New-2'); static::assertSame( [ @@ -163,6 +165,49 @@ public function it_can_write_at_path(): void 'Bar' => [ 'Baz' => 'Buz', 'New' => 'new-value', + 'New-2' => 'new-value-2', + ], + ], + ], + $access->data() + ); + } + + /** + * @test + */ + public function it_can_write_value_at_single_path(): void + { + $access = ArrayAccess::create([]); + $newAccess = $access->writeAtPath('new-value', 'Foo'); + + static::assertSame('new-value', $newAccess->string('Foo')); + } + + /** + * @test + */ + public function it_can_write_empty_array(): void + { + $access = ArrayAccess::create([]); + $access = $access->writeAtPath([], '0'); + + static::assertSame([], $access->array(0)); + } + + /** + * @test + */ + public function it_can_write_at_path_on_empty_access(): void + { + $access = ArrayAccess::create([]); + $newAccess = $access->writeAtPath('new-value', 'Foo', 'Bar', 'New'); + + static::assertSame( + [ + 'Foo' => [ + 'Bar' => [ + 'New' => 'new-value', ], ], ], @@ -170,6 +215,28 @@ public function it_can_write_at_path(): void ); } + /** + * @test + */ + public function it_writes_on_zero_index_if_empty_path_provided(): void + { + $access = ArrayAccess::create([]); + $access = $access->writeAtPath('foo'); + + static::assertSame(['foo'], $access->data()); + } + + /** + * @test + */ + public function it_writes_null_value_on_zero_index(): void + { + $access = ArrayAccess::create([]); + $access = $access->writeAtPath(null); + + static::assertSame([0 => null], $access->data()); + } + /** * @test */ diff --git a/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php b/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php new file mode 100644 index 0000000..4a1174f --- /dev/null +++ b/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php @@ -0,0 +1,34 @@ + [ + 'e1dp2' => 'kw1' + ], + 'e2dp1' => [ + 'e2dp2' => 'kw2' + ], + ], + $exception->errorMapping()->data() + ); + } +} \ No newline at end of file