diff --git a/src/PSR7/Validators/SerializedParameter.php b/src/PSR7/Validators/SerializedParameter.php index 1fe17fb2..812efd29 100644 --- a/src/PSR7/Validators/SerializedParameter.php +++ b/src/PSR7/Validators/SerializedParameter.php @@ -11,10 +11,12 @@ use League\OpenAPIValidation\Schema\Exception\InvalidSchema; use League\OpenAPIValidation\Schema\Exception\SchemaMismatch; use League\OpenAPIValidation\Schema\Exception\TypeMismatch; +use League\OpenAPIValidation\Schema\SchemaValidator; use Respect\Validation\Exceptions\Exception; use Respect\Validation\Exceptions\ExceptionInterface; use Respect\Validation\Validator; +use function count; use function explode; use function in_array; use function is_array; @@ -181,6 +183,14 @@ protected function convertToSerializationStyle($value, ?CebeSchema $schema) if ($schema && $this->style === self::STYLE_DEEP_OBJECT) { foreach ($value as $key => &$val) { $childSchema = $this->getChildSchema($schema, (string) $key); + + if (isset($childSchema->oneOf)) { + $suitableSchema = $this->findSuitableOneOf($childSchema, $val); + if ($suitableSchema) { + $childSchema = $suitableSchema; + } + } + if (is_array($val)) { $val = $this->convertToSerializationStyle($val, $childSchema); } else { @@ -217,4 +227,29 @@ protected function getChildSchema(CebeSchema $schema, string $key): ?CebeSchema return null; } + + /** + * @param mixed $val + */ + private function findSuitableOneOf(CebeSchema $schema, $val): ?CebeSchema + { + if (! count($schema->oneOf)) { + return null; + } + + $schemaValidator = new SchemaValidator(SchemaValidator::VALIDATE_AS_REQUEST); + $validSchemas = []; + foreach ($schema->oneOf as $schemaCandidate) { + try { + $valCandidate = $this->convertToSerializationStyle($val, $schemaCandidate); + + $schemaValidator->validate($valCandidate, $schemaCandidate); + $validSchemas[] = $schemaCandidate; + } catch (SchemaMismatch $e) { + // nothing to do + } + } + + return count($validSchemas) === 1 ? $validSchemas[0] : null; + } } diff --git a/tests/FromCommunity/Issue166Test.php b/tests/FromCommunity/Issue166Test.php new file mode 100644 index 00000000..6733e2fc --- /dev/null +++ b/tests/FromCommunity/Issue166Test.php @@ -0,0 +1,72 @@ +fromYaml($yaml)->getServerRequestValidator(); + + $queryString = 'filter[filters][min]=1'; + $query = null; + parse_str($queryString, $query); + + $psrRequest = (new ServerRequest('get', 'http://localhost:8000/api/list')) + ->withHeader('Content-Type', 'application/json') + ->withQueryParams($query); + + try { + $validator->validate($psrRequest); + $this->assertTrue(true); + } catch (InvalidQueryArgs $e) { + self::fail('Should not throw an exception'); + } + } +}