-
Notifications
You must be signed in to change notification settings - Fork 0
Improved json schema validation handling #7
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
Changes from all commits
55c6822
c3edbc6
502d692
d468a31
422c4a6
b980650
c83b0d6
b9fd233
346ee33
8fd7dea
736a70a
ddc87be
28020d9
4c147c3
2eca39f
dc8e9e8
af7f849
1490c79
d19b539
b630463
75c30aa
89b9d08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,9 +5,8 @@ | |
| namespace MyParcelCom\JsonSchema\FormBuilder\Form; | ||
|
|
||
| use ArrayObject; | ||
| use JsonSchema\Constraints\Constraint; | ||
| use JsonSchema\Validator; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Exceptions\FormValidationException; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Validation\Validator; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Validation\Exceptions\FormValidationException; | ||
|
|
||
| /** | ||
| * @extends ArrayObject<array-key, FormElement> | ||
|
|
@@ -18,6 +17,7 @@ public function toJsonSchema(): array | |
| { | ||
| return [ | ||
| '$schema' => 'https://json-schema.org/draft/2020-12/schema', | ||
| 'type' => 'object', | ||
| 'additionalProperties' => false, | ||
| 'required' => $this->getRequired(), | ||
| 'properties' => $this->getProperties()->toArray(), | ||
|
|
@@ -29,16 +29,11 @@ public function toJsonSchema(): array | |
| * @param array<string, mixed> $values a key value array of form values | ||
| * @throws FormValidationException | ||
| */ | ||
| public function validate(array $values): void | ||
| public function validate(array $values, ?Validator $validator = null): void | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! I really like this entire method and how it reads now! Good job. |
||
| { | ||
| /** | ||
| * CHECK_MODE_TYPE_CAST: Enable fuzzy type checking for associative arrays and objects | ||
| * src: https://github.com/jsonrainbow/json-schema?tab=readme-ov-file#configuration-options | ||
| **/ | ||
| $validator = new Validator; | ||
| $validator->validate($values, $this->toJsonSchema(), Constraint::CHECK_MODE_TYPE_CAST); | ||
| if (!$validator->isValid()) { | ||
| throw new FormValidationException("Form validation failed", $validator->getErrors()); | ||
| $validator ??= new Validator($values, $this->toJsonSchema()); | ||
| if(!$validator->isValid()) { | ||
| throw new FormValidationException(errors: $validator->getErrors()); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace MyParcelCom\JsonSchema\FormBuilder\Validation; | ||
|
|
||
| use Opis\JsonSchema\Errors\ErrorFormatter; | ||
| use Opis\JsonSchema\Helper; | ||
| use Opis\JsonSchema\ValidationResult; | ||
| use Opis\JsonSchema\Validator as JsonSchemaValidator; | ||
|
|
||
| class Validator | ||
| { | ||
| private ValidationResult $validationResult; | ||
| public function __construct( | ||
| private readonly array $values, | ||
| private readonly array $schema, | ||
| ) { | ||
| $jsonSchemaValidator = new JsonSchemaValidator(); | ||
| $this->validationResult = $jsonSchemaValidator->validate(Helper::toJSON($this->values), Helper::toJSON($this->schema)); | ||
| } | ||
|
|
||
| /** | ||
| * Validates the form values against the JSON Schema. | ||
| */ | ||
| public function isValid(): bool | ||
| { | ||
| return $this->validationResult->isValid(); | ||
| } | ||
| public function getErrors(): array | ||
| { | ||
| return $this->validationResult->hasError() | ||
| ? new ErrorFormatter()->format($this->validationResult->error()) | ||
| : []; | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,15 +4,17 @@ | |
|
|
||
| namespace Tests\Form; | ||
|
|
||
| use Mockery; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Checkbox; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Exceptions\FormValidationException; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Form; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\FormElementCollection; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Group; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Option; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\OptionCollection; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\RadioButtons; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Form\Text; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Validation\Exceptions\FormValidationException; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Validation\Validator; | ||
| use PHPUnit\Framework\TestCase; | ||
|
|
||
| use function PHPUnit\Framework\assertEquals; | ||
|
|
@@ -136,6 +138,7 @@ public function test_it_converts_to_json_schema(): void | |
| { | ||
| assertEquals([ | ||
| '$schema' => 'https://json-schema.org/draft/2020-12/schema', | ||
| 'type' => 'object', | ||
| 'additionalProperties' => false, | ||
| 'required' => ['name_2', 'name_3'], | ||
| 'properties' => [ | ||
|
|
@@ -250,9 +253,15 @@ public function test_it_gets_values(): void | |
| /** | ||
| * @throws FormValidationException | ||
| */ | ||
| public function test_it_validates(): void | ||
| public function test_it_validates_success(): void | ||
| { | ||
| $this->expectNotToPerformAssertions(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not super important, but maybe there is a
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There doesn't seem to be such an assertion. Copilot seems to agree:
|
||
|
|
||
| $validator = Mockery::mock(Validator::class); | ||
|
|
||
| $validator->expects('isValid')->andReturnTrue(); | ||
| $validator->expects('getErrors')->never(); | ||
|
|
||
| $this->form->validate([ | ||
| 'name_1' => 'value', | ||
| 'name_2' => false, | ||
|
|
@@ -262,54 +271,26 @@ public function test_it_validates(): void | |
| 'name_2' => false, | ||
| 'name_3' => 'a', | ||
| ], | ||
| ]); | ||
|
|
||
| $this->form->validate([ | ||
| 'name_1' => 'value', | ||
| 'name_2' => false, | ||
| 'name_3' => 'a', | ||
| ]); | ||
| ], $validator); | ||
| } | ||
|
|
||
| public function test_it_fails_to_validate_required_missing(): void | ||
| public function test_it_validates_failure(): void | ||
| { | ||
| $this->expectException(FormValidationException::class); | ||
|
|
||
| $validator = Mockery::mock(Validator::class); | ||
| $validator->expects('isValid')->andReturnFalse(); | ||
| $validator->expects('getErrors'); | ||
|
|
||
| $this->form->validate([ | ||
| 'name_1' => 'value', | ||
| 'name_2' => false, | ||
| 'name_4' => [ | ||
| 'name_1' => 'value', | ||
| 'name_3' => 'a', | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| public function test_it_fails_to_validate_wrong_property_type(): void | ||
| { | ||
| $this->expectException(FormValidationException::class); | ||
| $this->form->validate([ | ||
| 'name_1' => 5, | ||
| 'name_2' => 'hello', | ||
| 'name_3' => 'a', | ||
| 'name_4' => [ | ||
| 'name_1' => 'value', | ||
| 'name_2' => false, | ||
| 'name_3' => 'a', | ||
| ], | ||
| ]); | ||
| } | ||
|
|
||
| public function test_it_fails_to_validate_invalid_enum_value(): void | ||
| { | ||
| $this->expectException(FormValidationException::class); | ||
| $this->form->validate([ | ||
| 'name_1' => 'value', | ||
| 'name_2' => true, | ||
| 'name_3' => 'x', | ||
| 'name_4' => [ | ||
| 'name_1' => 'value', | ||
| 'name_2' => true, | ||
| 'name_3' => 'y', | ||
| ], | ||
| ]); | ||
| ], $validator); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Tests\Validation\Exceptions; | ||
|
|
||
| use Mockery; | ||
| use MyParcelCom\JsonSchema\FormBuilder\Validation\Exceptions\FormValidationException; | ||
| use Opis\JsonSchema\Errors\ErrorFormatter; | ||
| use Opis\JsonSchema\Errors\ValidationError; | ||
| use Opis\JsonSchema\ValidationResult; | ||
| use PHPUnit\Framework\TestCase; | ||
|
|
||
| use function PHPUnit\Framework\assertEquals; | ||
|
|
||
| class FormValidationExceptionTest extends TestCase | ||
| { | ||
| public function test_it_renders(): void | ||
| { | ||
| $exception = new FormValidationException('What a failure', [ | ||
| 'foo.bar' => 'Foo is required', | ||
| 'bar.foo' => 'Bar is required', | ||
| ]); | ||
|
|
||
| $response = $exception->render(); | ||
|
|
||
| assertEquals(422, $response->getStatusCode()); | ||
| assertEquals($response->getData(true), [ | ||
| 'message' => 'What a failure', | ||
| 'errors' => [ | ||
| 'foo.bar' => 'Foo is required', | ||
| 'bar.foo' => 'Bar is required', | ||
| ], | ||
| ]); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.