swaggest / php-json-schema

High definition PHP structures with JSON-schema based validation
MIT License
446 stars 50 forks source link

Inconsistent Validation Result Output Makes it Difficult to Identify Applied Composition Rules #143

Open slucero opened 2 years ago

slucero commented 2 years ago

Background

I've been using this library to work with JSON schemas and do some traversal of the schema alongside configuration data to match it. As part of this need, I need to be able to identify both the configuration value being processed at a certain level, and the related schema property the value maps to. In most cases, this works pretty well as I can traverse the properties of the schema and the configuration data in parallel, but it gets more difficult whenever I encounter anything in the schema with composition rules like anyOf or oneOf.

Whenever I'm traversing the schema and encounter one of these rules, the best solution I've come to was passing the data at that level into the schema for validation and checking the document path on the result to determine which rule was used. This works for complex data when an ObjectItem is returned and the document path is available, but when simpler values, like a string, are passed in, the value itself is returned and a document path is unavailable.

Examples

   $schema_json = <<<JSON
    {
      "\$schema": "http://json-schema.org/draft-04/schema#",
      "title": "Example",
      "type": "object",
      "properties": {
        "text": {
          "title": "Text",
          "type": "string",
          "options": {
            "grid_columns": 4
          }
        },
        "nested_items": {
          "title": "Nested items of various types",
          "type": "array",
          "items": {
            "anyOf": [
              {
                "title": "Simple object",
                "type": "object"
              },
              {
                "title": "Simple string",
                "type": "string"
              }
            ]
          }
        }
      }
    }
    JSON;

    $string_value = [
      'my_string',
    ];

    $object_value = [
      (object) [
        'my_object' => 'my_value',
      ],
    ];

    // Import the whole schema to start with.
    $schema = Schema::import(json_decode($schema_json));
    // Traverse to a lower property containing composition rules to be tested.
    $nested = $schema->getProperties()->nested_items;

    // Test a more complex value. This will return an ObjectItem.
    $object_result = $nested->in($object_value);
    echo $object_result[0]->getDocumentPath(); // "#->items[0]:0->anyOf[0]"

    // Test a simple value. This will return the value itself.
    $string_result = $nested->in($string_value);
    echo $string_result[0] // "my_string"

Based on this example, is there something I'm doing wrong or a better way to determine which composition rule(s) apply to a value? Currently I'm testing if the result is an instance of ObjectItemContract, and if it is I'm doing my own cycling through the composition rules to test, but ideally this step wouldn't be required if the return value for a validation result were consistent.

slucero commented 1 year ago

Would it be possible to get some insight on this at all?