Skip to content

Commit

Permalink
Translate JSON schema validation errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominic Tubach committed Nov 6, 2023
1 parent 023a027 commit a6dc256
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/*
* Copyright (C) 2023 SYSTOPIA GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation in version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

declare(strict_types = 1);

namespace Civi\RemoteTools\JsonSchema\Validation\Translation;

use Opis\JsonSchema\Errors\ValidationError;
use Systopia\JsonSchema\Translation\TranslatorFactory;
use Systopia\JsonSchema\Translation\TranslatorInterface;

/**
* @codeCoverageIgnore
*/
final class CiviValidationTranslator implements TranslatorInterface {

private string $lastLocale = '';

/**
* @phpstan-ignore-next-line Not initialized in constructor.
*/
private TranslatorInterface $translator;

/**
* @inheritDoc
*/
public function trans(string $id, array $parameters, ValidationError $error): string {
return $this->getTranslator()->trans($id, $parameters, $error);
}

private function getTranslator(): TranslatorInterface {
if (\CRM_Core_I18n::getLocale() !== $this->lastLocale) {
$this->lastLocale = \CRM_Core_I18n::getLocale();
$this->translator = TranslatorFactory::createTranslator($this->lastLocale);
}

return $this->translator;
}

}
23 changes: 10 additions & 13 deletions Civi/RemoteTools/JsonSchema/Validation/ValidationResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@

namespace Civi\RemoteTools\JsonSchema\Validation;

use Opis\JsonSchema\Errors\ErrorFormatter;
use Opis\JsonSchema\Errors\ValidationError;
use Systopia\JsonSchema\Errors\ErrorCollector;
use Systopia\JsonSchema\Translation\ErrorTranslator;
use Systopia\JsonSchema\Translation\NullTranslator;
use Systopia\JsonSchema\Translation\TranslatorInterface;

final class ValidationResult {

Expand All @@ -32,20 +34,16 @@ final class ValidationResult {

private ErrorCollector $errorCollector;

private static function getErrorFormatter(): ErrorFormatter {
static $errorFormatter;
$errorFormatter ??= new ErrorFormatter();

return $errorFormatter;
}
private ErrorTranslator $errorTranslator;

/**
* @param array<string, mixed> $data
* @param \Systopia\JsonSchema\Errors\ErrorCollector $errorCollector
*/
public function __construct(array $data, ErrorCollector $errorCollector) {
public function __construct(array $data, ErrorCollector $errorCollector, ?TranslatorInterface $translator = NULL) {
$this->data = $data;
$this->errorCollector = $errorCollector;
$this->errorTranslator = new ErrorTranslator($translator ?? new NullTranslator());
}

/**
Expand All @@ -59,14 +57,14 @@ public function getData(): array {
* @return array<string, non-empty-array<string>>
*/
public function getErrorMessages(): array {
return static::mapErrorsToMessages($this->errorCollector->getErrors());
return $this->mapErrorsToMessages($this->errorCollector->getErrors());
}

/**
* @return array<string, non-empty-array<string>>
*/
public function getLeafErrorMessages(): array {
return static::mapErrorsToMessages($this->errorCollector->getLeafErrors());
return $this->mapErrorsToMessages($this->errorCollector->getLeafErrors());
}

public function hasErrors(): bool {
Expand All @@ -82,11 +80,10 @@ public function isValid(): bool {
*
* @return array<string, non-empty-array<string>>
*/
private static function mapErrorsToMessages(array $errors): array {
$errorFormatter = static::getErrorFormatter();
private function mapErrorsToMessages(array $errors): array {
return array_map(
fn (array $errors): array => array_map(
fn (ValidationError $error): string => $errorFormatter->formatErrorMessage($error),
fn (ValidationError $error): string => $this->errorTranslator->trans($error),
$errors
), $errors
);
Expand Down
8 changes: 6 additions & 2 deletions Civi/RemoteTools/JsonSchema/Validation/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@
use Civi\RemoteTools\Util\JsonConverter;
use Opis\JsonSchema\Validator as OpisValidator;
use Systopia\JsonSchema\Errors\ErrorCollector;
use Systopia\JsonSchema\Translation\TranslatorInterface;

final class Validator implements ValidatorInterface {

private TranslatorInterface $translator;

private OpisValidator $validator;

public function __construct(OpisValidator $validator) {
public function __construct(TranslatorInterface $translator, OpisValidator $validator) {
$this->translator = $translator;
$this->validator = $validator;
}

Expand All @@ -48,7 +52,7 @@ public function validate(JsonSchema $jsonSchema, array $data, int $maxErrors = 1
$this->validator->setMaxErrors($prevMaxErrors);
}

return new ValidationResult(JsonConverter::toArray($validationData), $errorCollector);
return new ValidationResult(JsonConverter::toArray($validationData), $errorCollector, $this->translator);
}

}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"require": {
"webmozart/assert": "^1",
"systopia/expression-language-ext": "~0.1",
"systopia/opis-json-schema-ext": "~0.1",
"systopia/opis-json-schema-ext": "~0.2",
"psr/log": "<3"
},
"scripts": {
Expand Down
4 changes: 4 additions & 0 deletions services/json-forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@
use Civi\RemoteTools\JsonSchema\FormSpec\JsonSchemaFactory;
use Civi\RemoteTools\JsonSchema\FormSpec\JsonSchemaFactoryInterface;
use Civi\RemoteTools\JsonSchema\Validation\OpisValidatorFactory;
use Civi\RemoteTools\JsonSchema\Validation\Translation\CiviValidationTranslator;
use Civi\RemoteTools\JsonSchema\Validation\Validator;
use Civi\RemoteTools\JsonSchema\Validation\ValidatorInterface;
use Opis\JsonSchema\Validator as OpisValidator;
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
use Systopia\JsonSchema\Translation\TranslatorInterface;

$container->register(OpisValidator::class)->setFactory([OpisValidatorFactory::class, 'getValidator']);
$container->autowire(ValidatorInterface::class, Validator::class);

$container->autowire(TranslatorInterface::class, CiviValidationTranslator::class);

$container->autowire(JsonSchemaFactoryInterface::class, JsonSchemaFactory::class)
->addArgument(new TaggedIteratorArgument(
FieldJsonSchemaFactoryInterface::SERVICE_TAG,
Expand Down

0 comments on commit a6dc256

Please sign in to comment.