Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ parameters:
level: 9
paths:
- src
treatPhpDocTypesAsCertain: false
89 changes: 86 additions & 3 deletions src/Exception/InvalidOpenAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,100 @@ public static function typeArrayInWrongVersion(Identifier $identifier): self
return new self($message);
}

public static function numericExclusiveMinMaxIn30(
Identifier $identifier,
string $keyword,
): self {
$message = <<<TEXT
$identifier
$keyword MUST be a boolean in OpenAPI ^3.0
TEXT;

return new self($message);
}

public static function arrayItemsIn31(Identifier $identifier): self
{
$message = <<<TEXT
$identifier
items MUST be a Schema in OpenAPI ^3.1
TEXT;

return new self($message);
}

public static function boolExclusiveMinMaxIn31(
Identifier $identifier,
string $keyword,
): self {
$message = <<<TEXT
$identifier
$keyword MUST be a number in OpenAPI ^3.1
TEXT;

return new self($message);
}

public static function keywordMustBeStrictlyPositiveNumber(
Identifier $identifier,
string $keyword,
): self {
$message = <<<TEXT
$identifier
$keyword MUST be strictly greater than zero
TEXT;

return new self($message);
}

public static function keywordMustBeNegativeInteger(
Identifier $identifier,
string $keyword,
): self {
$message = <<<TEXT
$identifier
$keyword MUST be greater than or equal to zero
TEXT;

return new self($message);
}

public static function failedCebeValidation(string ...$errors): self
{
$message = sprintf("OpenAPI is invalid for the following reasons:\n\t- %s", implode("\n\t- ", $errors));
return new self($message);
}

public static function emptyComplexSchema(Identifier $identifier): self
{
public static function mustBeNonEmpty(
Identifier $identifier,
string $keyword
): self {
$message = <<<TEXT
$identifier
$keyword MUST be a non-empty array
TEXT;

return new self($message);
}

public static function mustContainUniqueItems(
Identifier $identifier,
string $keyword
): self {
$message = <<<TEXT
$identifier
$keyword MUST be an array of unique strings
TEXT;

return new self($message);
}

public static function mustSpecifyItemsForArrayType(
Identifier $identifier,
): self {
$message = <<<TEXT
$identifier
complex schemas MUST have atleast one sub-schema
items MUST be specified if type is array
TEXT;

return new self($message);
Expand Down
52 changes: 45 additions & 7 deletions src/Factory/V30/FromCebe.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
use Membrane\OpenAPIReader\ValueObject\Partial\Schema;
use Membrane\OpenAPIReader\ValueObject\Partial\Server;
use Membrane\OpenAPIReader\ValueObject\Partial\ServerVariable;
use Membrane\OpenAPIReader\ValueObject\Valid;
use Membrane\OpenAPIReader\ValueObject\Valid\V30;
use Membrane\OpenAPIReader\ValueObject\Value;

final class FromCebe
{
public static function createOpenAPI(
Cebe\OpenApi $openApi
): Valid\V30\OpenAPI {
): V30\OpenAPI {
$servers = count($openApi->servers) === 1 && $openApi->servers[0]->url === '/' ?
[] :
$openApi->servers;
Expand All @@ -30,7 +31,7 @@ public static function createOpenAPI(
* The reason for this is the cebe library does not specify that info is nullable
* However it is not always set, so it can be null
*/
return Valid\V30\OpenAPI::fromPartial(new OpenAPI(
return V30\OpenAPI::fromPartial(new OpenAPI(
$openApi->openapi,
$openApi->info?->title, // @phpstan-ignore-line
$openApi->info?->version, // @phpstan-ignore-line
Expand Down Expand Up @@ -143,10 +144,47 @@ private static function createSchema(
);

return new Schema(
$schema->type,
isset($schema->allOf) ? $createSchemas($schema->allOf) : null,
isset($schema->anyOf) ? $createSchemas($schema->anyOf) : null,
isset($schema->oneOf) ? $createSchemas($schema->oneOf) : null,
type: $schema->type,
enum: $schema->enum ?? null,
const: $schema->const ?? null,
default: isset($schema->default) ? new Value($schema->default) : null,
nullable: $schema->nullable ?? false,
multipleOf: $schema->multipleOf ?? null,
exclusiveMaximum: $schema->exclusiveMaximum ?? false,
exclusiveMinimum: $schema->exclusiveMinimum ?? false,
maximum: $schema->maximum ?? null,
minimum: $schema->minimum ?? null,
maxLength: $schema->maxLength ?? null,
minLength: $schema->minLength ?? 0,
pattern: $schema->pattern ?? null,
maxItems: $schema->maxItems ?? null,
minItems: $schema->minItems ?? 0,
uniqueItems: $schema->uniqueItems ?? false,
maxContains: $schema->maxContains ?? null,
minContains: $schema->minContains ?? null,
maxProperties: $schema->maxProperties ?? null,
minProperties: $schema->minProperties ?? 0,
required: $schema->required ?? null,
dependentRequired: $schema->dependentRequired ?? null,
allOf: isset($schema->allOf) ? $createSchemas($schema->allOf) : null,
anyOf: isset($schema->anyOf) ? $createSchemas($schema->anyOf) : null,
oneOf: isset($schema->oneOf) ? $createSchemas($schema->oneOf) : null,
not: isset($schema->not) ? self::createSchema($schema->not) : null,
if: isset($schema->if) ? self::createSchema($schema->if) : null,
then: isset($schema->then) ? self::createSchema($schema->then) : null,
else: isset($schema->else) ? self::createSchema($schema->else) : null,
dependentSchemas: isset($schema->dependentSchemas) ?
$createSchemas($schema->dependentSchemas) :
null,
items: isset($schema->items) ? (is_array($schema->items) ?
$createSchemas($schema->items) :
self::createSchema($schema->items)) :
null,
properties: isset($schema->properties) ? $createSchemas($schema->properties) : null,
additionalProperties: isset($schema->additionalProperties) ? (is_bool($schema->additionalProperties) ?
$schema->additionalProperties :
self::createSchema($schema->additionalProperties) ?? true) :
true,
);
}

Expand Down
14 changes: 14 additions & 0 deletions src/ValueObject/Limit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Membrane\OpenAPIReader\ValueObject;

final class Limit
{
public function __construct(
public readonly float|int $limit,
public readonly bool $exclusive,
) {
}
}
111 changes: 107 additions & 4 deletions src/ValueObject/Partial/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Membrane\OpenAPIReader\ValueObject\Partial;

use Membrane\OpenAPIReader\ValueObject\Value;

final class Schema
{
/**
Expand All @@ -13,10 +15,111 @@ final class Schema
* @param ?self[] $oneOf
*/
public function __construct(
public array|string|null $type = null,
public ?array $allOf = null,
public ?array $anyOf = null,
public ?array $oneOf = null,
/**
* Keywords for any type
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#autoid-11
* 3.1 https://json-schema.org/draft/2020-12/json-schema-validation#name-validation-keywords-for-any
*/
/** @var null|string|array<string> */
public null|string|array $type = null,
/** @var array<Value>|null */
public array|null $enum = null,
public Value|null $const = null,
public Value|null $default = null,
/**
* 3.0 keywords that are extensions to the spec
* https://github.com/OAI/OpenAPI-Specification/blob/3.1.1/versions/3.0.4.md#fixed-fields-21
*/
public bool $nullable = false,
/**
* Keywords for numeric type
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#autoid-11
* 3.1 https://json-schema.org/draft/2020-12/json-schema-validation#name-validation-keywords-for-num
*/
public float|int|null $multipleOf = null,
public bool|float|int|null $exclusiveMaximum = null,
public bool|float|int|null $exclusiveMinimum = null,
public float|int|null $maximum = null,
public float|int|null $minimum = null,
/**
* Keywords for string type
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#autoid-11
* 3.1 https://json-schema.org/draft/2020-12/json-schema-validation#name-validation-keywords-for-str
*/
public int|null $maxLength = null,
public int $minLength = 0,
public string|null $pattern = null,
/**
* Keywords for array type
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#autoid-11
* 3.1 https://json-schema.org/draft/2020-12/json-schema-validation#name-validation-keywords-for-arr
*/
public int|null $maxItems = null,
public int $minItems = 0,
public bool $uniqueItems = false,
public int|null $maxContains = null,
public int|null $minContains = null,
/**
* Keywords for object type
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#autoid-11
* 3.1 https://json-schema.org/draft/2020-12/json-schema-validation#name-validation-keywords-for-obj
*/
public int|null $maxProperties = null,
public int $minProperties = 0,
/** @var array<string>|null */
public array|null $required = null,
/** @var array<string,array<string>>|null */
public array|null $dependentRequired = null,
/**
* Keywords for applying subschemas with logic
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.22
* 3.1 https://json-schema.org/draft/2020-12/json-schema-core#name-keywords-for-applying-subsch
*/
/** @var array<Schema>|null */
public array|null $allOf = null,
/** @var array<Schema>|null */
public array|null $anyOf = null,
/** @var array<Schema>|null */
public array|null $oneOf = null,
public Schema|null $not = null,
/**
* Keywords for applying subschemas conditionally
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.22
* 3.1 https://json-schema.org/draft/2020-12/json-schema-core#name-keywords-for-applying-subsche
*/
public Schema|null $if = null,
public Schema|null $then = null,
public Schema|null $else = null,
/** @var array<string,Schema>|null */
public array|null $dependentSchemas = null,
/**
* Keywords for applying subschemas to arrays
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.22
* 3.1 https://json-schema.org/draft/2020-12/json-schema-core#name-keywords-for-applying-subschema
*/
/** @var array<Schema> */
public array|null $prefixItems = null,
/** @var array<Schema>|Schema|null */
public array|Schema|null $items = null,
public Schema|null $contains = null,
/**
* Keywords for applying subschemas to arrays
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.22
* 3.1 https://json-schema.org/draft/2020-12/json-schema-core#name-keywords-for-applying-subschemas
*/
/** @var array<string, Schema>|null */
public array|null $properties = [],
/** @var array<string, Schema> */
public array $patternProperties = [],
public bool|Schema $additionalProperties = true,
public bool|Schema $propertyNames = true,
/**
* Keywords that are exceptions to the usual "keyword independence"
* 3.0 https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.22
* 3.1 https://json-schema.org/draft/2020-12/json-schema-core#name-keyword-independence-2
*/
public bool|Schema $unevaluatedItems = true,
public bool|Schema $unevaluatedProperties = true,
) {
}
}
13 changes: 13 additions & 0 deletions src/ValueObject/Valid/Schema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Membrane\OpenAPIReader\ValueObject\Valid;

use Membrane\OpenAPIReader\ValueObject\Limit;

interface Schema
{
public function getRelevantMinimum(): ?Limit;
public function getRelevantMaximum(): ?Limit;
}
Loading