{"id":35850799,"url":"https://github.com/m1x0n/opis-error-presenter","last_synced_at":"2026-01-08T08:00:46.141Z","repository":{"id":54858531,"uuid":"178961573","full_name":"m1x0n/opis-error-presenter","owner":"m1x0n","description":"JSON-schema error presenter for opis/json-schema library","archived":false,"fork":false,"pushed_at":"2023-03-14T11:12:38.000Z","size":74,"stargazers_count":17,"open_issues_count":2,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-25T04:22:06.182Z","etag":null,"topics":["json-schema","opis","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/m1x0n.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-01T23:16:27.000Z","updated_at":"2023-03-14T11:08:42.000Z","dependencies_parsed_at":"2024-06-18T21:43:54.113Z","dependency_job_id":null,"html_url":"https://github.com/m1x0n/opis-error-presenter","commit_stats":{"total_commits":44,"total_committers":6,"mean_commits":7.333333333333333,"dds":0.2272727272727273,"last_synced_commit":"ba692327a67a4581a599be5e9a0539c542c42c93"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/m1x0n/opis-error-presenter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m1x0n%2Fopis-error-presenter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m1x0n%2Fopis-error-presenter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m1x0n%2Fopis-error-presenter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m1x0n%2Fopis-error-presenter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/m1x0n","download_url":"https://codeload.github.com/m1x0n/opis-error-presenter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m1x0n%2Fopis-error-presenter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28000515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json-schema","opis","php"],"created_at":"2026-01-08T08:00:19.185Z","updated_at":"2026-01-08T08:00:46.125Z","avatar_url":"https://github.com/m1x0n.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"opis-json-schema-error-presenter ![Build Status](https://github.com/m1x0n/opis-error-presenter/workflows/Test/badge.svg)\n=====\n\n### Warning\n⚠️This library might become obsolote since new major version (2.0.0) of [opis/json-schema](https://github.com/opis/json-schema/releases/tag/2.0.0) already supports [Error formating](https://opis.io/json-schema/2.x/php-error-formatter.html).\n\n\nCustomizable error presenter for json schema validation errors produced\nby [opis/json-schema](https://github.com/opis/json-schema) library: [JSON schema](http://json-schema.org/) implementation.\n\nIn other words it's a raw attempt to represent `Opis\\JsonSchema\\ValidationError` collection in\nhuman readable way.\n\n### Requirements\n- php \u003e= 7.1\n- opis/json-schema\n\n### Installation\n\n```bash\ncomposer require m1x0n/opis-json-schema-error-presenter\n```\n\n### Usage example\n```php\nuse Opis\\JsonSchema\\Schema;\nuse Opis\\JsonSchema\\ValidationResult;\nuse Opis\\JsonSchema\\Validator;\nuse OpisErrorPresenter\\Contracts\\PresentedValidationError;\nuse OpisErrorPresenter\\Implementation\\MessageFormatterFactory;\nuse OpisErrorPresenter\\Implementation\\PresentedValidationErrorFactory;\nuse OpisErrorPresenter\\Implementation\\ValidationErrorPresenter;\n\nrequire __DIR__ . '/../vendor/autoload.php';\n\n$jsonSchema ='{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"http://example.com/product.schema.json\",\n  \"title\": \"Product\",\n  \"description\": \"A product from Acme\\'s catalog\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"productId\": {\n      \"type\": \"integer\",\n      \"minimum\": 1\n    },\n    \"productName\": {\n      \"type\": \"string\",\n      \"minLength\": 3\n    },\n    \"price\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"amount\": {\n          \"type\": \"integer\",\n          \"minimum\": 0,\n          \"maximum\": 1000\n        },\n        \"currency\": {\n          \"type\": \"string\",\n          \"enum\": [\"USD\", \"EUR\", \"BTC\"]\n        }\n      },\n      \"required\": [\"amount\", \"currency\"]\n    }\n  },\n  \"required\": [ \"productId\", \"productName\", \"price\" ]\n}';\n\n$data = '{\n  \"productId\": \"123\",\n  \"productName\": \"XX\",\n  \"price\": {\n    \"amount\": 200,\n    \"currency\": \"GBP\"\n  }\n}';\n\n$data = json_decode($data);\n$jsonSchema = Schema::fromJsonString($jsonSchema);\n$validator = new Validator();\n\n// Get all errors. Yeah -1 here.\n/** @var ValidationResult $result */\n$result = $validator-\u003eschemaValidation($data, $jsonSchema, -1);\n\n// Default strategy is AllErrors\n$presenter = new ValidationErrorPresenter(\n    new PresentedValidationErrorFactory(\n        new MessageFormatterFactory()\n    )\n);\n\n$presented = $presenter-\u003epresent(...$result-\u003egetErrors());\n\n// Inspected presenter error\nprint_r(array_map(static function (PresentedValidationError $error) {\n    return $error-\u003etoArray();\n}, $presented));\n\n// Json-serializable\necho json_encode($presented);\n```\n\n### Output result example\n```\nArray\n(\n    [0] =\u003e Array\n        (\n            [keyword] =\u003e type\n            [pointer] =\u003e productId\n            [message] =\u003e The attribute expected to be of type 'integer' but 'string' given.\n        )\n\n    [1] =\u003e Array\n        (\n            [keyword] =\u003e minLength\n            [pointer] =\u003e productName\n            [message] =\u003e The attribute length should be at least 3 characters.\n        )\n\n    [2] =\u003e Array\n        (\n            [keyword] =\u003e enum\n            [pointer] =\u003e price/currency\n            [message] =\u003e The attribute must be one of the following values: 'USD', 'EUR', 'BTC'.\n        )\n\n)\n```\n\n### Presenting Strategies\n- `AllErrors` - shows all available presented errors\n- `FirstError` - picks the first of the presented errors\n- `BestMatchError` - evaluates best matching error\n\nIn order to specify strategy simply pass selected one to\n`PresentedValidationErrorFactory`, e.g:\n\n```php\n$presenter = new ValidationErrorPresenter(\n    new PresentedValidationErrorFactory(\n        new MessageFormatterFactory()\n    ),\n    new BestMatchError()\n);\n```\n\n### Custom translations\nThere is a possibility to have custom translations.\nCurrently there is only `DefaultTranslator` which exposes some generic messages like:\n\n`The attribute length should be at least 3 characters`\n\nIn order to replace or extend or come up with new translations `MessageTranslator` interface\nmust be implemented.\nFor example:\n\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nnamespace Acme;\n\nuse OpisErrorPresenter\\Contracts\\Keyword;\nuse OpisErrorPresenter\\Implementation\\MessageFormatterFactory;\nuse OpisErrorPresenter\\Implementation\\PresentedValidationErrorFactory;\nuse OpisErrorPresenter\\Implementation\\Translators\\DefaultTranslator;\nuse OpisErrorPresenter\\Implementation\\ValidationErrorPresenter;\n\nclass InternationalTranslator extends DefaultTranslator\n{\n    protected $messages = [];\n\n    private const DEFAULT_MESSAGE = 'The attribute is invalid';\n\n    public function __construct()\n    {\n        parent::__construct();\n        $this-\u003eloadMessages();\n    }\n\n    public function translate(string $key, array $replacements = [], $locale = null): string\n    {\n        if ($locale \u0026\u0026 array_key_exists($locale, $this-\u003emessages)) {\n            $message = $this-\u003emessages[$locale][$key] ?? self::DEFAULT_MESSAGE;\n            return strtr($message, $replacements);\n        }\n\n        // Fallback on default locale\n        return parent::translate($key, $replacements, $locale);\n    }\n\n    private function loadMessages(): void\n    {\n        /*\n            Locales structure example:\n            [\n               'locale_1' =\u003e [\n                  'keyword' =\u003e 'translation_1'\n                  ...\n               ],\n               'locale_2' =\u003e [\n                  'keyword' =\u003e 'translation_2'\n                  ...\n               ],\n               ...\n            ]\n        */\n        $this-\u003emessages = [\n            'de_DE' =\u003e [\n                // The rest of other keywords ...\n                Keyword::MIN_LENGTH =\u003e 'Die Attributlänge sollte mindestens betragen: min: Zeichen.'\n                // ...\n            ],\n            'ru_RU' =\u003e [\n                // ...\n                Keyword::ENUM =\u003e 'Длина атрибута должна быть минимум :min: символов.'\n                // ....\n            ]\n        ];\n    }\n}\n\n// Then configure presenter factory\n$presenter = new ValidationErrorPresenter(\n    new PresentedValidationErrorFactory(\n        new MessageFormatterFactory(),\n        new InternationalTranslator()\n    )\n);\n\n```\n\n### Locale resolving\nFor better experience with different localizations custom translator could be used\nalongside with automatic locale resolution.\n\nCurrently next locale resolvers are implemented:\n- `NullLocaleResolver` as fallback to generic messages.\n- `HttpLocaleResolver` tries to detect locale based on `HTTP_ACCEPT_LANGUAGE` header and requires `ext-intl` to be installed.\n\nIt's also possible to implement custom locale resolver by implementing `LocaleResolver` interface.\n\nTo set up `HttpLocaleResolver` or custom-crafted one:\n```php\n$presenter = new ValidationErrorPresenter(\n    new PresentedValidationErrorFactory(\n        new MessageFormatterFactory(),\n        new InternationalTranslator(),\n        new HttpLocaleResolver()\n    )\n);\n```\n\n### Locale support\nCurrently there is a possibility to use locales defined in php arrays\nvia `ArrayLocaleLoader`. See `lang/en.php`.\n\nIn order to load more languages `ValidationErrorPresenter` might be configured in following way:\n\n```php\n$presenter = new ValidationErrorPresenter(\n    new PresentedValidationErrorFactory(\n        new MessageFormatterFactory(),\n        new DefaultTranslator(\n            (new ArrayLocaleLoader())-\u003eaddPath('de', '/path_to_lang/lang/de.php')\n        )\n    )\n);\n```\n\nHowever it's possible to load locale strings from anywhere by implementing\n`LocaleLoader` interface.\n\nAlso presenter could be configured with single locale.\nFor doing that `FixedLocaleResolver` will be helpful.\nFor example:\n```php\n$presenter = new ValidationErrorPresenter(\n    new PresentedValidationErrorFactory(\n        new MessageFormatterFactory(),\n        new DefaultTranslator(\n            (new ArrayLocaleLoader())-\u003eaddPath('cs', '../lang')\n        ),\n        new FixedLocaleResolver('cs')\n    )\n);\n```\n\nAll the configurations might be slightly simplified by using DI-container.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm1x0n%2Fopis-error-presenter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fm1x0n%2Fopis-error-presenter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm1x0n%2Fopis-error-presenter/lists"}