Skip to content

Commit

Permalink
Merge pull request #268 from ergebnis/feature/result
Browse files Browse the repository at this point in the history
Enhancement: Implement validate() and return result with error messages
  • Loading branch information
localheinz authored Apr 19, 2020
2 parents 85a4a1f + 61cb762 commit 766c037
Show file tree
Hide file tree
Showing 16 changed files with 400 additions and 31 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ on: # yamllint disable-line rule:truthy
- "master"

env:
MIN_COVERED_MSI: 96
MIN_MSI: 96
MIN_COVERED_MSI: 91
MIN_MSI: 91
REQUIRED_PHP_EXTENSIONS: "mbstring"

jobs:
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

For a full diff see [`0.11.0...master`][0.11.0...master].

### Added

* Added `SchemaValidator::validate()`, which returns a `Result` composing validation error messages ([#268]), by [@localheinz]

## [`0.11.0`][0.11.0]

For a full diff see [`0.10.1...0.11.0`][0.10.1...0.11.0].
Expand Down Expand Up @@ -307,6 +311,7 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0].
[#191]: https://github.com/ergebnis/json-normalizer/pull/191
[#202]: https://github.com/ergebnis/json-normalizer/pull/202
[#203]: https://github.com/ergebnis/json-normalizer/pull/203
[#268]: https://github.com/ergebnis/json-normalizer/pull/268

[@BackEndTea]: https://github.com/BackEndTea
[@ergebnis]: https://github.com/ergebnis
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MIN_COVERED_MSI:=96
MIN_MSI:=96
MIN_COVERED_MSI:=91
MIN_MSI:=91

.PHONY: it
it: coding-standards static-code-analysis tests ## Runs the coding-standards, static-code-analysis, and tests targets
Expand Down
12 changes: 10 additions & 2 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,19 @@
</MixedMethodCall>
</file>
<file src="test/Unit/Validator/SchemaValidatorTest.php">
<MixedArgument occurrences="2">
<MixedArgument occurrences="6">
<code>$data</code>
<code>$schema</code>
<code>$data</code>
<code>$schema</code>
<code>$data</code>
<code>$schema</code>
</MixedArgument>
<MixedAssignment occurrences="2">
<MixedAssignment occurrences="6">
<code>$data</code>
<code>$schema</code>
<code>$data</code>
<code>$schema</code>
<code>$data</code>
<code>$schema</code>
</MixedAssignment>
Expand Down
16 changes: 15 additions & 1 deletion src/Exception/NormalizedInvalidAccordingToSchemaException.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ final class NormalizedInvalidAccordingToSchemaException extends \RuntimeExceptio
*/
private $schemaUri = '';

public static function fromSchemaUri(string $schemaUri): self
/**
* @var string[]
*/
private $errors = [];

public static function fromSchemaUriAndErrors(string $schemaUri, string ...$errors): self
{
$exception = new self(\sprintf(
'Normalized JSON is not valid according to schema "%s".',
$schemaUri
));

$exception->schemaUri = $schemaUri;
$exception->errors = $errors;

return $exception;
}
Expand All @@ -36,4 +42,12 @@ public function schemaUri(): string
{
return $this->schemaUri;
}

/**
* @return string[]
*/
public function errors(): array
{
return $this->errors;
}
}
16 changes: 15 additions & 1 deletion src/Exception/OriginalInvalidAccordingToSchemaException.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ final class OriginalInvalidAccordingToSchemaException extends \RuntimeException
*/
private $schemaUri = '';

public static function fromSchemaUri(string $schemaUri): self
/**
* @var string[]
*/
private $errors = [];

public static function fromSchemaUriAndErrors(string $schemaUri, string ...$errors): self
{
$exception = new self(\sprintf(
'Original JSON is not valid according to schema "%s".',
$schemaUri
));

$exception->schemaUri = $schemaUri;
$exception->errors = $errors;

return $exception;
}
Expand All @@ -36,4 +42,12 @@ public function schemaUri(): string
{
return $this->schemaUri;
}

/**
* @return string[]
*/
public function errors(): array
{
return $this->errors;
}
}
31 changes: 26 additions & 5 deletions src/SchemaNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,33 @@ public function normalize(Json $json): Json
throw Exception\SchemaUriReferencesInvalidJsonDocumentException::fromSchemaUri($this->schemaUri);
}

if (!$this->schemaValidator->isValid($decoded, $schema)) {
throw Exception\OriginalInvalidAccordingToSchemaException::fromSchemaUri($this->schemaUri);
$resultBeforeNormalization = $this->schemaValidator->validate(
$decoded,
$schema
);

if (!$resultBeforeNormalization->isValid()) {
throw Exception\OriginalInvalidAccordingToSchemaException::fromSchemaUriAndErrors(
$this->schemaUri,
...$resultBeforeNormalization->errors()
);
}

$normalized = $this->normalizeData(
$decoded,
$schema
);

if (!$this->schemaValidator->isValid($normalized, $schema)) {
throw Exception\NormalizedInvalidAccordingToSchemaException::fromSchemaUri($this->schemaUri);
$resultAfterNormalization = $this->schemaValidator->validate(
$normalized,
$schema
);

if (!$resultAfterNormalization->isValid()) {
throw Exception\NormalizedInvalidAccordingToSchemaException::fromSchemaUriAndErrors(
$this->schemaUri,
...$resultAfterNormalization->errors()
);
}

/** @var string $encoded */
Expand Down Expand Up @@ -214,7 +230,12 @@ private function resolveSchema($data, \stdClass $schema): \stdClass
*/
if (\property_exists($schema, 'oneOf') && \is_array($schema->oneOf)) {
foreach ($schema->oneOf as $oneOfSchema) {
if ($this->schemaValidator->isValid($data, $oneOfSchema)) {
$result = $this->schemaValidator->validate(
$data,
$oneOfSchema
);

if ($result->isValid()) {
return $this->resolveSchema(
$data,
$oneOfSchema
Expand Down
45 changes: 45 additions & 0 deletions src/Validator/Result.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2020 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/json-normalizer
*/

namespace Ergebnis\Json\Normalizer\Validator;

final class Result
{
/**
* @var string[]
*/
private $errors;

private function __construct(string ...$errors)
{
$this->errors = $errors;
}

public static function create(string ...$errors): self
{
return new self(...$errors);
}

public function isValid(): bool
{
return [] === $this->errors;
}

/**
* @return string[]
*/
public function errors(): array
{
return $this->errors;
}
}
51 changes: 51 additions & 0 deletions src/Validator/SchemaValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,55 @@ public function isValid($data, \stdClass $schema): bool

return $this->validator->isValid();
}

public function validate($data, \stdClass $schema): Result
{
$this->validator->reset();

$this->validator->check(
$data,
$schema
);

/** @var array $originalErrors */
$originalErrors = $this->validator->getErrors();

$errors = \array_map(static function (array $error): string {
$property = '';

if (
\array_key_exists('property', $error)
&& \is_string($error['property'])
&& '' !== \trim($error['property'])
) {
$property = \trim($error['property']);
}

$message = '';

if (
\array_key_exists('message', $error)
&& \is_string($error['message'])
&& '' !== \trim($error['message'])
) {
$message = \trim($error['message']);
}

if ('' === $property) {
return $message;
}

return \sprintf(
'%s: %s',
$property,
$message
);
}, $originalErrors);

$filtered = \array_filter($errors, static function (string $error): bool {
return '' !== $error;
});

return Result::create(...$filtered);
}
}
8 changes: 8 additions & 0 deletions src/Validator/SchemaValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,12 @@ interface SchemaValidatorInterface
* @return bool
*/
public function isValid($data, \stdClass $schema): bool;

/**
* @param null|array<mixed>|bool|float|int|\stdClass|string $data
* @param \stdClass $schema
*
* @return Result
*/
public function validate($data, \stdClass $schema): Result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,25 @@ public function testDefaults(): void
$exception = new NormalizedInvalidAccordingToSchemaException();

self::assertSame('', $exception->schemaUri());
self::assertSame([], $exception->errors());
}

public function testFromSchemaUriReturnsNormalizedInvalidAccordingToSchemaException(): void
{
$schemaUri = self::faker()->url;
$faker = self::faker();

$exception = NormalizedInvalidAccordingToSchemaException::fromSchemaUri($schemaUri);
$schemaUri = $faker->url;

$errors = [
$faker->sentence,
$faker->sentence,
$faker->sentence,
];

$exception = NormalizedInvalidAccordingToSchemaException::fromSchemaUriAndErrors(
$schemaUri,
...$errors
);

$message = \sprintf(
'Normalized JSON is not valid according to schema "%s".',
Expand All @@ -42,5 +54,6 @@ public function testFromSchemaUriReturnsNormalizedInvalidAccordingToSchemaExcept

self::assertSame($message, $exception->getMessage());
self::assertSame($schemaUri, $exception->schemaUri());
self::assertSame($errors, $exception->errors());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,26 @@ public function testDefaults(): void
{
$exception = new OriginalInvalidAccordingToSchemaException();

self::assertSame([], $exception->errors());
self::assertSame('', $exception->schemaUri());
}

public function testFromSchemaUriReturnsOriginalInvalidAccordingToSchemaException(): void
public function testFromSchemaUriAndErrorsReturnsOriginalInvalidAccordingToSchemaException(): void
{
$schemaUri = self::faker()->url;
$faker = self::faker();

$exception = OriginalInvalidAccordingToSchemaException::fromSchemaUri($schemaUri);
$schemaUri = $faker->url;

$errors = [
$faker->sentence,
$faker->sentence,
$faker->sentence,
];

$exception = OriginalInvalidAccordingToSchemaException::fromSchemaUriAndErrors(
$schemaUri,
...$errors
);

$message = \sprintf(
'Original JSON is not valid according to schema "%s".',
Expand All @@ -42,5 +54,6 @@ public function testFromSchemaUriReturnsOriginalInvalidAccordingToSchemaExceptio

self::assertSame($message, $exception->getMessage());
self::assertSame($schemaUri, $exception->schemaUri());
self::assertSame($errors, $exception->errors());
}
}
Loading

0 comments on commit 766c037

Please sign in to comment.