Problem/Motivation
Sometimes during schema traversal, validation of data may fail when trying to validate empty object data against a schema. In some scenarios, provided pattern configuration containing an empty object may get cast as an empty array which then fails validation resulting in a type error containing output like the following:
Swaggest\JsonSchema\Exception\TypeException : Object expected, [] received
A hallmark of this issue is that the pattern configuration validates at the top level of the schema, but once it is being passed into the field processing logic in \Drupal\patternkit\PatternFieldProcessorPluginManager::processSchemaValues, the validation fails at a lower level when handling schema composition in \Drupal\patternkit\Schema\SchemaHelper::getCompositionSchema.
Steps to reproduce
Proposed resolution
This seems to be getting caused by inconsistent handling of encoding and decoding of JSON data which converts empty objects into empty arrays along the way as described in #3294740. Fixing that issue directly may help for all new data moving forward, but I'm concerned that existing site data may already be impacted and wouldn't be resolved easily with an automated update of the data.
As an alternative, we could approach this problem by adding more flexibility to the validation process where array values being checked against an object schema could be cast during validation. The Swaggest library offers a mechanic for this through a DataPreProcessor implementation.
User interface changes
None
API changes
New service method: SchemaFactory::getDefaultContext()
The SchemaFactory service (patternkit.schema.schema_factory), introduced in #3293860, exposes a new getDefaultContext() method that provides a globally configured default context for use in schema operations beyond the initial import completed by the existing createInstance() method on the schema factory. Without this context, any schema reference lookup operations will fail, and array-to-object conversions this issue seeks to fix will fail. Below is an example usage of this context with an existing schema:
// Get a globally configured execution context for use in schema
// operations. This will ensure expected options as well as configured
// remote reference providers and data preprocessors are available.
$context = \Drupal::service('patternkit.schema.schema_factory')->getDefaultContext();
$validationResult = $schema->in($value, $context);
Issue fork patternkit-3295055
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
sluceroI've uploaded some new tests that demonstrate this issue and are currently failing. I'll follow up with additional work to make these pass and ideally resolve the issue.
This work will be dependent on the new SchemaFactory service introduced in #3293860, so release of this work will be blocked by completion of that issue.
Comment #4
sluceroReady for review and manual testing. For this solution, I implemented a new data preprocessor and exposed a new public
getDefaultContext()method that produces a context ready for schema operations with the data preprocessor and remote reference provider already configured. In the future, this may be expanded if we find we need other default configuration options prepared for schema operations throughout the module. The only existing schema operation outside of the initial schema import that was already handled by the SchemaFactory service was in theSchemaHelper::getCompositionSchema()method which was the source of this validation error. An example usage with an existing schema may be found in that method as shown below:Comment #5
sluceroI merged in #3293860 this morning, which this work was dependent on. With that completed, I've rebased and updated this merge request on top of the 9.1.x branch again to get it mergeable once more. It is once again ready for review and manual testing.
Testing Installation Instructions
If you're using a composer patching configuration, add the following snippet to the patches section of your composer.json file:
Comment #6
sluceroFollowing direct feedback from internal testers I'm considering this tested and reviewed. Merging in now for release in the upcoming beta 4 release.
Comment #8
slucero