From d3538200368d4fd5ea91ee1d461758ec20941ed1 Mon Sep 17 00:00:00 2001 From: Markus Schindler Date: Wed, 19 Feb 2020 09:38:51 +0100 Subject: [PATCH 1/2] - Retrieving validation errors via validation exception - Extended tests - fixed writeToPath not beeing immutable --- ArrayAccess/ArrayAccess.php | 12 ++-- ArrayAccess/ArrayAccessValidationFailed.php | 44 ++++++++++++ README.md | 3 + Tests/ArrayAccess/ArrayAccessTest.php | 71 ++++++++++++++++++- .../ArrayAccessValidationFailedTest.php | 34 +++++++++ 5 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 ArrayAccess/ArrayAccessValidationFailed.php create mode 100644 Tests/ArrayAccess/ArrayAccessValidationFailedTest.php 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..06267c7 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..fef598b --- /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 From baf2736e65a56a8638e8a8970dc4e39d5cdb49cf Mon Sep 17 00:00:00 2001 From: Markus Schindler Date: Wed, 19 Feb 2020 09:50:12 +0100 Subject: [PATCH 2/2] style fix --- Tests/ArrayAccess/ArrayAccessTest.php | 36 +++++++++---------- .../ArrayAccessValidationFailedTest.php | 32 ++++++++--------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Tests/ArrayAccess/ArrayAccessTest.php b/Tests/ArrayAccess/ArrayAccessTest.php index 06267c7..277387a 100644 --- a/Tests/ArrayAccess/ArrayAccessTest.php +++ b/Tests/ArrayAccess/ArrayAccessTest.php @@ -176,24 +176,24 @@ public function it_can_write_at_path(): void /** * @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)); - } + 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 diff --git a/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php b/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php index fef598b..4a1174f 100644 --- a/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php +++ b/Tests/ArrayAccess/ArrayAccessValidationFailedTest.php @@ -12,23 +12,23 @@ class ArrayAccessValidationFailedTest extends TestCase /** * @test */ - public function it_can_return_errors(): void - { - $error1 = new ValidationError(null, ['e1dp1', 'e1dp2'], [], false, 'kw1'); - $error2 = new ValidationError(null, ['e2dp1', 'e2dp2'], [], false, 'kw2'); + public function it_can_return_errors(): void + { + $error1 = new ValidationError(null, ['e1dp1', 'e1dp2'], [], false, 'kw1'); + $error2 = new ValidationError(null, ['e2dp1', 'e2dp2'], [], false, 'kw2'); - $exception = ArrayAccessValidationFailed::withValidationErrors($error1, $error2); + $exception = ArrayAccessValidationFailed::withValidationErrors($error1, $error2); - static::assertSame( - [ - 'e1dp1' => [ - 'e1dp2' => 'kw1' - ], - 'e2dp1' => [ - 'e2dp2' => 'kw2' - ], - ], - $exception->errorMapping()->data() + static::assertSame( + [ + 'e1dp1' => [ + 'e1dp2' => 'kw1' + ], + 'e2dp1' => [ + 'e2dp2' => 'kw2' + ], + ], + $exception->errorMapping()->data() ); - } + } } \ No newline at end of file