diff --git a/src/Schema/Exception/NotEnoughValidSchemas.php b/src/Schema/Exception/NotEnoughValidSchemas.php new file mode 100644 index 00000000..f17e281d --- /dev/null +++ b/src/Schema/Exception/NotEnoughValidSchemas.php @@ -0,0 +1,41 @@ +keyword = $keyword; + $instance->data = $data; + $instance->innerExceptions = $innerExceptions; + + return $instance; + } + + /** + * @return Throwable[] + */ + public function innerExceptions() : array + { + return $this->innerExceptions; + } +} diff --git a/src/Schema/Exception/TooManyValidSchemas.php b/src/Schema/Exception/TooManyValidSchemas.php new file mode 100644 index 00000000..619cea14 --- /dev/null +++ b/src/Schema/Exception/TooManyValidSchemas.php @@ -0,0 +1,41 @@ +keyword = $keyword; + $instance->data = $data; + $instance->validSchemas = $validSchemas; + + return $instance; + } + + /** + * @return Schema[] + */ + public function validSchemas() : array + { + return $this->validSchemas; + } +} diff --git a/src/Schema/Keywords/AnyOf.php b/src/Schema/Keywords/AnyOf.php index 0d2b8888..c31183fc 100644 --- a/src/Schema/Keywords/AnyOf.php +++ b/src/Schema/Keywords/AnyOf.php @@ -8,6 +8,7 @@ use League\OpenAPIValidation\Schema\BreadCrumb; use League\OpenAPIValidation\Schema\Exception\InvalidSchema; use League\OpenAPIValidation\Schema\Exception\KeywordMismatch; +use League\OpenAPIValidation\Schema\Exception\NotEnoughValidSchemas; use League\OpenAPIValidation\Schema\Exception\SchemaMismatch; use League\OpenAPIValidation\Schema\SchemaValidator; use Respect\Validation\Exceptions\ExceptionInterface; @@ -51,6 +52,8 @@ public function validate($data, array $anyOf) : void throw InvalidSchema::becauseDefensiveSchemaValidationFailed($e); } + $innerExceptions = []; + foreach ($anyOf as $schema) { $schemaValidator = new SchemaValidator($this->validationDataType); try { @@ -58,10 +61,15 @@ public function validate($data, array $anyOf) : void return; } catch (SchemaMismatch $e) { - // that did not match... its ok + $innerExceptions[] = $e; } } - throw KeywordMismatch::fromKeyword('anyOf', $data, 'Data must match at least one schema'); + throw NotEnoughValidSchemas::fromKeywordWithInnerExceptions( + 'anyOf', + $data, + $innerExceptions, + 'Data must match at least one schema' + ); } } diff --git a/src/Schema/Keywords/OneOf.php b/src/Schema/Keywords/OneOf.php index 675185cd..99f46138 100644 --- a/src/Schema/Keywords/OneOf.php +++ b/src/Schema/Keywords/OneOf.php @@ -8,10 +8,13 @@ use League\OpenAPIValidation\Schema\BreadCrumb; use League\OpenAPIValidation\Schema\Exception\InvalidSchema; use League\OpenAPIValidation\Schema\Exception\KeywordMismatch; +use League\OpenAPIValidation\Schema\Exception\NotEnoughValidSchemas; use League\OpenAPIValidation\Schema\Exception\SchemaMismatch; +use League\OpenAPIValidation\Schema\Exception\TooManyValidSchemas; use League\OpenAPIValidation\Schema\SchemaValidator; use Respect\Validation\Exceptions\ExceptionInterface; use Respect\Validation\Validator; +use function count; use function sprintf; class OneOf extends BaseKeyword @@ -53,19 +56,37 @@ public function validate($data, array $oneOf) : void } // Validate against all schemas - $matchedCount = 0; $schemaValidator = new SchemaValidator($this->validationDataType); + $innerExceptions = []; + $validSchemas = []; + foreach ($oneOf as $schema) { try { $schemaValidator->validate($data, $schema, $this->dataBreadCrumb); - $matchedCount++; + $validSchemas[] = $schema; } catch (SchemaMismatch $e) { - // that did not match... its ok + $innerExceptions[] = $e; } } - if ($matchedCount !== 1) { - throw KeywordMismatch::fromKeyword('oneOf', $data, sprintf('Data must match exactly one schema, but matched %d', $matchedCount)); + if (count($validSchemas) === 1) { + return; + } + + if (count($validSchemas) < 1) { + throw NotEnoughValidSchemas::fromKeywordWithInnerExceptions( + 'oneOf', + $data, + $innerExceptions, + 'Data must match exactly one schema, but matched none' + ); } + + throw TooManyValidSchemas::fromKeywordWithValidSchemas( + 'oneOf', + $data, + $validSchemas, + sprintf('Data must match exactly one schema, but matched %d', count($validSchemas)) + ); } }