diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e328ee7..90ad77a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,6 +19,8 @@ jobs:
php-version:
- "8.1"
- "8.2"
+ - "8.3"
+ - "8.4"
dependencies:
- "lowest"
- "highest"
@@ -53,7 +55,7 @@ jobs:
operating-system:
- "ubuntu-latest"
php-version:
- - "8.2"
+ - "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
@@ -81,7 +83,7 @@ jobs:
operating-system:
- "ubuntu-latest"
php-version:
- - "8.2"
+ - "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
@@ -109,7 +111,7 @@ jobs:
operating-system:
- "ubuntu-latest"
php-version:
- - "8.2"
+ - "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
@@ -137,7 +139,7 @@ jobs:
operating-system:
- "ubuntu-latest"
php-version:
- - "8.2"
+ - "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
@@ -170,7 +172,7 @@ jobs:
operating-system:
- "ubuntu-latest"
php-version:
- - "8.2"
+ - "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
@@ -201,7 +203,7 @@ jobs:
operating-system:
- "ubuntu-latest"
php-version:
- - "8.2"
+ - "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
diff --git a/composer.json b/composer.json
index b104815..cb3dca3 100644
--- a/composer.json
+++ b/composer.json
@@ -21,19 +21,13 @@
"email": "dk@csgo.com"
}
],
- "repositories": [
- {
- "type": "vcs",
- "url": "https://github.com/onmoon/php-openapi"
- }
- ],
"require": {
"php": "^8.1",
"ext-json": "*",
- "cebe/php-openapi": "1.6.99",
+ "devizzent/cebe-php-openapi": "^1.1.4",
"league/openapi-psr7-validator": "^0.22.0",
"lukasoppermann/http-status": "^4.0",
- "nikic/php-parser": "^4.19",
+ "nikic/php-parser": "^4.19|^v5.0",
"nyholm/psr7": "^1.5",
"phpdocumentor/reflection-docblock": "^5.3",
"sspat/reserved-words": "^3.0",
@@ -47,23 +41,23 @@
"symfony/psr-http-message-bridge": "^6.4|^7.0",
"symfony/routing": "^6.4|^7.0",
"symfony/yaml": "^6.4|^7.0",
- "thecodingmachine/safe": "^1.3|^2"
+ "thecodingmachine/safe": "^1.3|^2|^3.1"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
"matthiasnoback/symfony-config-test": "^5.1",
"matthiasnoback/symfony-dependency-injection-test": "^5.1",
- "phpstan/phpstan": "^1.11",
- "phpstan/phpstan-phpunit": "^1.4",
- "phpstan/phpstan-strict-rules": "^1.6",
+ "phpstan/phpstan": "^1.11|^2.1",
+ "phpstan/phpstan-phpunit": "^1.4|^2.0",
+ "phpstan/phpstan-strict-rules": "^1.6|^2.0",
"phpunit/phpunit": "^10.5",
"roave/infection-static-analysis-plugin": "^1.35",
"squizlabs/php_codesniffer": "^3.10",
"symfony/browser-kit": "^6.4|^7.0",
"symfony/dom-crawler": "^6.4|^7.0",
"symfony/framework-bundle": "^6.4|^7.0",
- "thecodingmachine/phpstan-safe-rule": "^1.2",
- "vimeo/psalm": "^5.24"
+ "thecodingmachine/phpstan-safe-rule": "^1.2|v1.4",
+ "vimeo/psalm": "^5.24|^6.10"
},
"minimum-stability": "stable",
"prefer-stable": true,
diff --git a/phpstan.neon b/phpstan.neon
index 2cc69f0..0045c6b 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -30,10 +30,6 @@ parameters:
message: '#Method OnMoon\\OpenApiServerBundle\\Specification\\SpecificationParser::getResponseDtoDefinitions\(\) has parameter \$responses with no value type specified in iterable type array\.#'
paths:
- %currentWorkingDirectory%/src/Specification/SpecificationParser.php
- -
- message: '#Parameter \#1 \$json of function Safe\\json_decode expects string, resource\|string given\.#'
- paths:
- - %currentWorkingDirectory%/src/Serializer/ArrayDtoSerializer.php
includes:
- vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
diff --git a/psalm.xml b/psalm.xml
index 970e114..e9a4f81 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -7,6 +7,7 @@
findUnusedVariablesAndParams="true"
ensureArrayStringOffsetsExist="true"
findUnusedBaselineEntry="true"
+ ensureOverrideAttribute="false"
findUnusedCode="false"
phpVersion="8.1"
>
@@ -19,25 +20,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/CodeGenerator/ApiServerCodeGenerator.php b/src/CodeGenerator/ApiServerCodeGenerator.php
index 74c1385..df2f099 100644
--- a/src/CodeGenerator/ApiServerCodeGenerator.php
+++ b/src/CodeGenerator/ApiServerCodeGenerator.php
@@ -11,7 +11,7 @@
use const DIRECTORY_SEPARATOR;
-class ApiServerCodeGenerator
+final class ApiServerCodeGenerator
{
private GraphGenerator $graphGenerator;
private NameGenerator $nameGenerator;
diff --git a/src/CodeGenerator/AttributeGenerator.php b/src/CodeGenerator/AttributeGenerator.php
index 68216d3..f31502d 100644
--- a/src/CodeGenerator/AttributeGenerator.php
+++ b/src/CodeGenerator/AttributeGenerator.php
@@ -10,6 +10,7 @@
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\PropertyDefinition;
use OnMoon\OpenApiServerBundle\Specification\Definitions\Property;
+/** @psalm-suppress ClassMustBeFinal */
class AttributeGenerator
{
public function setAllAttributes(GraphDefinition $graph): void
diff --git a/src/CodeGenerator/Definitions/ClassDefinition.php b/src/CodeGenerator/Definitions/ClassDefinition.php
index ee07611..775fe0e 100644
--- a/src/CodeGenerator/Definitions/ClassDefinition.php
+++ b/src/CodeGenerator/Definitions/ClassDefinition.php
@@ -4,8 +4,8 @@
namespace OnMoon\OpenApiServerBundle\CodeGenerator\Definitions;
-use function Safe\substr;
use function strrpos;
+use function substr;
class ClassDefinition implements ClassReference
{
diff --git a/src/CodeGenerator/Definitions/ComponentDefinition.php b/src/CodeGenerator/Definitions/ComponentDefinition.php
index ab8956c..c71be5d 100644
--- a/src/CodeGenerator/Definitions/ComponentDefinition.php
+++ b/src/CodeGenerator/Definitions/ComponentDefinition.php
@@ -4,7 +4,7 @@
namespace OnMoon\OpenApiServerBundle\CodeGenerator\Definitions;
-class ComponentDefinition
+final class ComponentDefinition
{
private DtoDefinition $dto;
diff --git a/src/CodeGenerator/Definitions/ComponentReference.php b/src/CodeGenerator/Definitions/ComponentReference.php
index d488201..0161942 100644
--- a/src/CodeGenerator/Definitions/ComponentReference.php
+++ b/src/CodeGenerator/Definitions/ComponentReference.php
@@ -4,7 +4,7 @@
namespace OnMoon\OpenApiServerBundle\CodeGenerator\Definitions;
-class ComponentReference implements DtoReference
+final class ComponentReference implements DtoReference
{
public function __construct(private ComponentDefinition $referencedComponent)
{
diff --git a/src/CodeGenerator/Definitions/DtoDefinition.php b/src/CodeGenerator/Definitions/DtoDefinition.php
index 0c36486..9fe087a 100644
--- a/src/CodeGenerator/Definitions/DtoDefinition.php
+++ b/src/CodeGenerator/Definitions/DtoDefinition.php
@@ -8,7 +8,7 @@
use function count;
-class DtoDefinition extends GeneratedClassDefinition implements DtoReference
+final class DtoDefinition extends GeneratedClassDefinition implements DtoReference
{
/** @var PropertyDefinition[] $properties; */
private array $properties;
diff --git a/src/CodeGenerator/FileGenerator.php b/src/CodeGenerator/FileGenerator.php
index 7f3e966..c184828 100644
--- a/src/CodeGenerator/FileGenerator.php
+++ b/src/CodeGenerator/FileGenerator.php
@@ -14,6 +14,7 @@
use function array_push;
+/** @psalm-suppress ClassMustBeFinal */
class FileGenerator
{
private DtoCodeGenerator $dtoGenerator;
diff --git a/src/CodeGenerator/GraphGenerator.php b/src/CodeGenerator/GraphGenerator.php
index 2eee373..4aa6af1 100644
--- a/src/CodeGenerator/GraphGenerator.php
+++ b/src/CodeGenerator/GraphGenerator.php
@@ -25,6 +25,7 @@
use function array_map;
use function count;
+/** @psalm-suppress ClassMustBeFinal */
class GraphGenerator
{
private SpecificationLoader $loader;
diff --git a/src/CodeGenerator/NameGenerator.php b/src/CodeGenerator/NameGenerator.php
index 2ecade1..658a3f9 100644
--- a/src/CodeGenerator/NameGenerator.php
+++ b/src/CodeGenerator/NameGenerator.php
@@ -13,6 +13,7 @@
use function ucfirst;
+/** @psalm-suppress ClassMustBeFinal */
class NameGenerator
{
private const DTO_NAMESPACE = 'Dto';
diff --git a/src/CodeGenerator/Naming/CannotCreateNamespace.php b/src/CodeGenerator/Naming/CannotCreateNamespace.php
index 80da985..9394401 100644
--- a/src/CodeGenerator/Naming/CannotCreateNamespace.php
+++ b/src/CodeGenerator/Naming/CannotCreateNamespace.php
@@ -6,7 +6,7 @@
use OnMoon\OpenApiServerBundle\Exception\OpenApiError;
-use function Safe\sprintf;
+use function sprintf;
final class CannotCreateNamespace extends OpenApiError
{
diff --git a/src/CodeGenerator/Naming/CannotCreatePropertyName.php b/src/CodeGenerator/Naming/CannotCreatePropertyName.php
index 22b8b87..2e15083 100644
--- a/src/CodeGenerator/Naming/CannotCreatePropertyName.php
+++ b/src/CodeGenerator/Naming/CannotCreatePropertyName.php
@@ -6,7 +6,7 @@
use OnMoon\OpenApiServerBundle\Exception\OpenApiError;
-use function Safe\sprintf;
+use function sprintf;
final class CannotCreatePropertyName extends OpenApiError
{
diff --git a/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php
index be417a1..87e7976 100644
--- a/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php
@@ -16,7 +16,7 @@
use function array_map;
use function count;
use function implode;
-use function Safe\sprintf;
+use function sprintf;
use function trim;
use const PHP_EOL;
diff --git a/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
index 04b4b3e..6903afb 100644
--- a/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
@@ -34,9 +34,9 @@
use function array_map;
use function count;
-use function Safe\sprintf;
+use function sprintf;
-class DtoCodeGenerator extends CodeGenerator
+final class DtoCodeGenerator extends CodeGenerator
{
public function generate(DtoDefinition $definition): GeneratedFileDefinition
{
@@ -160,9 +160,10 @@ private function generateClassProperty(FileBuilder $builder, PropertyDefinition
$property->setType($this->getTypePhp($builder, $definition));
$docCommentLines = [];
+ $description = $definition->getDescription();
- if ($definition->getDescription() !== null) {
- $docCommentLines[] = sprintf('%s', $definition->getDescription());
+ if ($description !== null) {
+ $docCommentLines[] = sprintf('%s', $description);
$docCommentLines[] = '';
}
@@ -302,7 +303,7 @@ private function generateFromArray(FileBuilder $builder, DtoDefinition $definiti
$statements = [];
if (count($setters) > 0) {
- $statements[] = new Assign($dto, $new);
+ $statements[] = new Expression(new Assign($dto, $new));
foreach ($setters as $setter) {
$statements[] = $setter;
}
@@ -317,8 +318,8 @@ private function generateFromArray(FileBuilder $builder, DtoDefinition $definiti
->method('fromArray')
->makePublic()
->makeStatic()
- ->setReturnType('self')
- ->addParam(new Param_($source, null, 'array'))
+ ->setReturnType(new Name('self'))
+ ->addParam(new Param_($source, null, new Name('array')))
->setDocComment($this->getDocComment(['@inheritDoc']))
->addStmts($statements);
}
diff --git a/src/CodeGenerator/PhpParserGenerators/FileBuilder.php b/src/CodeGenerator/PhpParserGenerators/FileBuilder.php
index 6dedcad..2dd9cf7 100644
--- a/src/CodeGenerator/PhpParserGenerators/FileBuilder.php
+++ b/src/CodeGenerator/PhpParserGenerators/FileBuilder.php
@@ -15,8 +15,9 @@
use function in_array;
use function Safe\preg_match;
use function Safe\preg_replace;
-use function Safe\substr;
+use function substr;
+/** @psalm-suppress ClassMustBeFinal */
class FileBuilder
{
private ClassDefinition $definition;
diff --git a/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php
index 7312472..68cc340 100644
--- a/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php
@@ -11,9 +11,9 @@
use function array_map;
use function count;
use function implode;
-use function Safe\sprintf;
+use function sprintf;
-class InterfaceCodeGenerator extends CodeGenerator
+final class InterfaceCodeGenerator extends CodeGenerator
{
public function generate(RequestHandlerInterfaceDefinition $definition): GeneratedFileDefinition
{
diff --git a/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php
index cefe0a0..4119ef5 100644
--- a/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php
@@ -24,9 +24,9 @@
use PhpParser\Node\Stmt\Return_;
use Psr\Container\ContainerInterface;
-use function Safe\sprintf;
+use function sprintf;
-class ServiceSubscriberCodeGenerator extends CodeGenerator
+final class ServiceSubscriberCodeGenerator extends CodeGenerator
{
public function generate(GraphDefinition $graphDefinition): GeneratedFileDefinition
{
@@ -69,7 +69,9 @@ public function generate(GraphDefinition $graphDefinition): GeneratedFileDefinit
} else {
foreach ($operation->getResponses() as $response) {
$responseTypes[] = new ArrayItem(
+ // @codeCoverageIgnoreStart
new Array_([new ArrayItem(new String_($response->getStatusCode()))], ['kind' => Array_::KIND_SHORT]),
+ // @codeCoverageIgnoreEnd
new ClassConstFetch(
new Name($fileBuilder->getReference($response->getResponseBody())),
'class'
@@ -79,7 +81,9 @@ public function generate(GraphDefinition $graphDefinition): GeneratedFileDefinit
}
$responseCodeMapper[] = new ArrayItem(
+ // @codeCoverageIgnoreStart
new Array_($responseTypes, ['kind' => Array_::KIND_SHORT]),
+ // @codeCoverageIgnoreEnd
new ClassConstFetch(
new Name($fileBuilder->getReference($operation->getRequestHandlerInterface())),
'class'
@@ -90,7 +94,9 @@ public function generate(GraphDefinition $graphDefinition): GeneratedFileDefinit
$httpCodeMapper = $this
->factory
+ // @codeCoverageIgnoreStart
->classConst('HTTP_CODES', new Array_($responseCodeMapper, ['kind' => Array_::KIND_SHORT]))
+ // @codeCoverageIgnoreEnd
->makePrivate();
$property = $this
@@ -125,6 +131,7 @@ public function generate(GraphDefinition $graphDefinition): GeneratedFileDefinit
->setDocComment('/**
* @inheritDoc
*/')
+ // @codeCoverageIgnoreStart
->addStmt(
new Return_(
new Array_(
@@ -133,6 +140,7 @@ public function generate(GraphDefinition $graphDefinition): GeneratedFileDefinit
)
)
);
+ // @codeCoverageIgnoreEnd
$getRequestHandler = $this
->factory
diff --git a/src/Command/DeleteGeneratedCodeCommand.php b/src/Command/DeleteGeneratedCodeCommand.php
index 6001b1b..05fac36 100644
--- a/src/Command/DeleteGeneratedCodeCommand.php
+++ b/src/Command/DeleteGeneratedCodeCommand.php
@@ -4,6 +4,7 @@
namespace OnMoon\OpenApiServerBundle\Command;
+use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
@@ -18,8 +19,8 @@
use function is_dir;
use function Safe\rmdir;
-use function Safe\sprintf;
use function Safe\unlink;
+use function sprintf;
#[AsCommand(name: 'open-api:delete')]
final class DeleteGeneratedCodeCommand extends Command
@@ -83,15 +84,15 @@ private function recursiveDelete(string $directoryPath): void
return;
}
- /** @var SplFileInfo[] $iterator */
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$directoryPath,
- RecursiveDirectoryIterator::SKIP_DOTS
+ FilesystemIterator::SKIP_DOTS
),
RecursiveIteratorIterator::CHILD_FIRST
);
+ /** @var SplFileInfo $directoryOrFile */
foreach ($iterator as $directoryOrFile) {
if ($directoryOrFile->isDir()) {
rmdir($directoryOrFile->getPathname());
diff --git a/src/Command/GenerateApiCodeCommand.php b/src/Command/GenerateApiCodeCommand.php
index 97e3e2b..d0db4f0 100644
--- a/src/Command/GenerateApiCodeCommand.php
+++ b/src/Command/GenerateApiCodeCommand.php
@@ -21,8 +21,8 @@
use function is_dir;
use function iterator_count;
use function Safe\rmdir;
-use function Safe\sprintf;
use function Safe\unlink;
+use function sprintf;
#[AsCommand(name: 'open-api:generate')]
final class GenerateApiCodeCommand extends Command
@@ -89,7 +89,6 @@ private function removeExtraFiles(string $root, array $generatedFiles): void
return;
}
- /** @var SplFileInfo[] $iterator */
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$root,
@@ -98,6 +97,7 @@ private function removeExtraFiles(string $root, array $generatedFiles): void
RecursiveIteratorIterator::CHILD_FIRST
);
+ /** @var SplFileInfo $directoryOrFile */
foreach ($iterator as $directoryOrFile) {
if ($directoryOrFile->isDir() || in_array($directoryOrFile->getPathname(), $generatedFiles, true)) {
continue;
diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php
index 25362be..e66df13 100644
--- a/src/Controller/ApiController.php
+++ b/src/Controller/ApiController.php
@@ -39,7 +39,7 @@
use function intdiv;
use function is_numeric;
use function ltrim;
-use function Safe\sprintf;
+use function sprintf;
use function strcasecmp;
use const JSON_THROW_ON_ERROR;
diff --git a/src/Exception/ApiCallFailed.php b/src/Exception/ApiCallFailed.php
index 4898bec..bee70ef 100644
--- a/src/Exception/ApiCallFailed.php
+++ b/src/Exception/ApiCallFailed.php
@@ -5,7 +5,7 @@
namespace OnMoon\OpenApiServerBundle\Exception;
use function implode;
-use function Safe\sprintf;
+use function sprintf;
final class ApiCallFailed extends OpenApiError
{
diff --git a/src/Exception/CannotParseOpenApi.php b/src/Exception/CannotParseOpenApi.php
index 4e08891..fd2c626 100644
--- a/src/Exception/CannotParseOpenApi.php
+++ b/src/Exception/CannotParseOpenApi.php
@@ -4,7 +4,7 @@
namespace OnMoon\OpenApiServerBundle\Exception;
-use function Safe\sprintf;
+use function sprintf;
final class CannotParseOpenApi extends OpenApiError
{
@@ -82,6 +82,21 @@ public static function becauseOnlyScalarAreAllowed(string $propertyName, array $
);
}
+ /** @param array{location:string,method:string,url:string,path:string} $context */
+ public static function becauseOpenapi31TypesNotSupported(string $propertyName, array $context): self
+ {
+ return new self(
+ sprintf(
+ 'Cannot generate property for DTO class, property "%s" has multiple types in %s for operation: "%s" of path: "%s" in specification file: "%s".',
+ $propertyName,
+ $context['location'],
+ $context['method'],
+ $context['url'],
+ $context['path']
+ )
+ );
+ }
+
/** @param array{location:string,method:string,url:string,path:string} $context */
public static function becauseArrayIsNotDescribed(string $propertyName, array $context): self
{
diff --git a/src/Router/RouteLoader.php b/src/Router/RouteLoader.php
index 2eb6df2..9b30a7a 100644
--- a/src/Router/RouteLoader.php
+++ b/src/Router/RouteLoader.php
@@ -14,6 +14,7 @@
use function array_key_exists;
+/** @psalm-suppress ClassMustBeFinal */
class RouteLoader extends Loader
{
private SpecificationLoader $loader;
@@ -41,7 +42,6 @@ public function load(mixed $resource, ?string $type = null): RouteCollection
$parameters = $operation->getRequestParameters();
if (array_key_exists('path', $parameters)) {
- /** @psalm-var array<(string|Stringable)> $requirements */
$requirements = $this->argumentResolver->resolveArgumentPatterns($parameters['path']);
}
diff --git a/src/Serializer/ArrayDtoSerializer.php b/src/Serializer/ArrayDtoSerializer.php
index 474dcb7..51ba0d8 100644
--- a/src/Serializer/ArrayDtoSerializer.php
+++ b/src/Serializer/ArrayDtoSerializer.php
@@ -4,7 +4,6 @@
namespace OnMoon\OpenApiServerBundle\Serializer;
-use Exception;
use OnMoon\OpenApiServerBundle\Interfaces\Dto;
use OnMoon\OpenApiServerBundle\Specification\Definitions\ObjectSchema;
use OnMoon\OpenApiServerBundle\Specification\Definitions\Operation;
@@ -13,7 +12,6 @@
use function array_key_exists;
use function array_map;
-use function is_resource;
use function Safe\json_decode;
final class ArrayDtoSerializer implements DtoSerializer
@@ -49,11 +47,7 @@ public function createRequestDto(
$bodyType = $operation->getRequestBody();
if ($bodyType !== null) {
- /** @var resource|string $source */
$source = $request->getContent();
- if (is_resource($source)) {
- throw new Exception('Expecting string as contents, resource received');
- }
/** @var mixed[] $rawBody */
$rawBody = json_decode($source, true);
diff --git a/src/Specification/Definitions/ComponentArray.php b/src/Specification/Definitions/ComponentArray.php
index 242c88c..d7b1385 100644
--- a/src/Specification/Definitions/ComponentArray.php
+++ b/src/Specification/Definitions/ComponentArray.php
@@ -7,6 +7,6 @@
use ArrayObject;
/** @extends ArrayObject */
-class ComponentArray extends ArrayObject
+final class ComponentArray extends ArrayObject
{
}
diff --git a/src/Specification/Definitions/ObjectReference.php b/src/Specification/Definitions/ObjectReference.php
index 630ad7e..8fde388 100644
--- a/src/Specification/Definitions/ObjectReference.php
+++ b/src/Specification/Definitions/ObjectReference.php
@@ -4,7 +4,7 @@
namespace OnMoon\OpenApiServerBundle\Specification\Definitions;
-class ObjectReference implements GetSchema
+final class ObjectReference implements GetSchema
{
public function __construct(private string $schemaName, private ObjectSchema $referencedObject)
{
diff --git a/src/Specification/SpecificationLoader.php b/src/Specification/SpecificationLoader.php
index 5fcc345..5376d02 100644
--- a/src/Specification/SpecificationLoader.php
+++ b/src/Specification/SpecificationLoader.php
@@ -17,11 +17,12 @@
use function file_exists;
use function implode;
use function pathinfo;
-use function Safe\sprintf;
+use function sprintf;
use function stream_is_local;
use const PATHINFO_EXTENSION;
+/** @psalm-suppress ClassMustBeFinal */
class SpecificationLoader
{
public const CACHE_TAG = 'openapi.server.bundle.specifications';
diff --git a/src/Specification/SpecificationParser.php b/src/Specification/SpecificationParser.php
index fea367a..87bbac6 100644
--- a/src/Specification/SpecificationParser.php
+++ b/src/Specification/SpecificationParser.php
@@ -42,6 +42,7 @@
use function strcasecmp;
use function substr;
+/** @psalm-suppress ClassMustBeFinal */
class SpecificationParser
{
private ScalarTypesResolver $typeResolver;
@@ -374,8 +375,14 @@ private function getProperty(
$itemProperty = $property;
}
- if (Type::isScalar($itemProperty->type)) {
- $scalarTypeId = $this->typeResolver->findScalarType($itemProperty->type, $itemProperty->format);
+ $propertyType = $itemProperty->type;
+
+ if (is_array($propertyType)) {
+ throw CannotParseOpenApi::becauseOpenapi31TypesNotSupported($propertyName, $exceptionContext);
+ }
+
+ if (Type::isScalar($propertyType)) {
+ $scalarTypeId = $this->typeResolver->findScalarType($propertyType, $itemProperty->format);
$propertyDefinition->setScalarTypeId($scalarTypeId);
if ($this->typeResolver->isDateTime($scalarTypeId) && $this->dateTimeClass !== null) {
@@ -397,7 +404,7 @@ private function getProperty(
$propertyDefinition->setOutputType($this->dateTimeClass);
}
- } elseif ($itemProperty->type === Type::OBJECT) {
+ } elseif ($propertyType === Type::OBJECT) {
$objectType = $this->getObjectSchema(
$itemProperty,
$isRequest,
@@ -407,7 +414,7 @@ private function getProperty(
$propertyDefinition->setObjectTypeDefinition($objectType);
$isScalar = false;
} else {
- throw CannotParseOpenApi::becauseTypeNotSupported($propertyName, $itemProperty->type, $exceptionContext);
+ throw CannotParseOpenApi::becauseTypeNotSupported($propertyName, $propertyType, $exceptionContext);
}
/** @var string|int|float|bool|null $schemaDefaultValue */
diff --git a/src/Types/ArgumentResolver.php b/src/Types/ArgumentResolver.php
index 947309e..4974861 100644
--- a/src/Types/ArgumentResolver.php
+++ b/src/Types/ArgumentResolver.php
@@ -9,6 +9,7 @@
use function Safe\preg_match;
+/** @psalm-suppress ClassMustBeFinal */
class ArgumentResolver
{
private ScalarTypesResolver $typesResolver;
@@ -20,7 +21,9 @@ public function __construct(ScalarTypesResolver $typesResolver)
/**
* @return string[]
- * @psalm-return array
+ * @psalm-return array
+ *
+ * @psalm-suppress InvalidReturnType
*/
public function resolveArgumentPatterns(ObjectSchema $pathParameters): array
{
@@ -46,6 +49,7 @@ public function resolveArgumentPatterns(ObjectSchema $pathParameters): array
}
}
+ /** @psalm-suppress InvalidReturnStatement */
return $patterns;
}
}
diff --git a/src/Types/TypeSerializer.php b/src/Types/TypeSerializer.php
index a78f702..6f94a68 100644
--- a/src/Types/TypeSerializer.php
+++ b/src/Types/TypeSerializer.php
@@ -15,7 +15,7 @@
use function Safe\base64_decode;
use function sprintf;
-class TypeSerializer
+final class TypeSerializer
{
private const DATE_FORMAT = 'Y-m-d';
private const DATETIME_FORMAT = 'c';
diff --git a/test/functional/Command/DeleteGeneratedCodeCommandTest.php b/test/functional/Command/DeleteGeneratedCodeCommandTest.php
index 3f30b67..db5ad3a 100644
--- a/test/functional/Command/DeleteGeneratedCodeCommandTest.php
+++ b/test/functional/Command/DeleteGeneratedCodeCommandTest.php
@@ -9,10 +9,11 @@
use PHPUnit\Framework\Assert;
use Symfony\Component\Console\Tester\CommandTester;
+use function is_dir;
use function rtrim;
use function Safe\file_put_contents;
use function Safe\mkdir;
-use function Safe\sprintf;
+use function sprintf;
/** @covers \OnMoon\OpenApiServerBundle\Command\DeleteGeneratedCodeCommand */
class DeleteGeneratedCodeCommandTest extends CommandTestCase
@@ -24,7 +25,10 @@ public function setUp(): void
$command = $this->application->find(DeleteGeneratedCodeCommand::COMMAND);
$this->commandTester = new CommandTester($command);
- mkdir(TestKernel::$bundleRootPath);
+ if (! is_dir(TestKernel::$bundleRootPath)) {
+ mkdir(TestKernel::$bundleRootPath);
+ }
+
file_put_contents(TestKernel::$bundleRootPath . '/test.txt', '');
}
diff --git a/test/functional/Command/GenerateApiCodeCommandTest.php b/test/functional/Command/GenerateApiCodeCommandTest.php
index 081ab9d..4c14b39 100644
--- a/test/functional/Command/GenerateApiCodeCommandTest.php
+++ b/test/functional/Command/GenerateApiCodeCommandTest.php
@@ -10,7 +10,7 @@
use Symfony\Component\Console\Tester\CommandTester;
use function rtrim;
-use function Safe\sprintf;
+use function sprintf;
use function ucfirst;
use const DIRECTORY_SEPARATOR;
diff --git a/test/functional/DependencyInjection/ConfigurationTest.php b/test/functional/DependencyInjection/ConfigurationTest.php
index b861252..f700e80 100644
--- a/test/functional/DependencyInjection/ConfigurationTest.php
+++ b/test/functional/DependencyInjection/ConfigurationTest.php
@@ -9,7 +9,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Kernel;
-use function Safe\sprintf;
+use function sprintf;
use function version_compare;
/** @covers \OnMoon\OpenApiServerBundle\DependencyInjection\Configuration */
diff --git a/test/functional/Specification/SpecificationLoaderTest.php b/test/functional/Specification/SpecificationLoaderTest.php
index e6289e9..408ea05 100644
--- a/test/functional/Specification/SpecificationLoaderTest.php
+++ b/test/functional/Specification/SpecificationLoaderTest.php
@@ -22,7 +22,7 @@
use Symfony\Contracts\Cache\TagAwareCacheInterface;
use function array_pop;
-use function Safe\sprintf;
+use function sprintf;
/** @covers \OnMoon\OpenApiServerBundle\Specification\SpecificationLoader */
class SpecificationLoaderTest extends TestCase
diff --git a/test/functional/openapi_specification.yaml b/test/functional/openapi_specification.yaml
index 680a4b3..4aedfe0 100644
--- a/test/functional/openapi_specification.yaml
+++ b/test/functional/openapi_specification.yaml
@@ -3,7 +3,7 @@ info:
title: 'Test Goods API'
version: '1.0'
paths:
- '/goods/{goodId}':
+ /goods/{goodId}:
get:
operationId: "getGood"
parameters:
diff --git a/test/generation/GeneratedClassAsserter.php b/test/generation/GeneratedClassAsserter.php
index 174a558..52b6770 100644
--- a/test/generation/GeneratedClassAsserter.php
+++ b/test/generation/GeneratedClassAsserter.php
@@ -23,11 +23,12 @@
use PhpParser\NodeFinder;
use PhpParser\ParserFactory;
use PHPUnit\Framework\Assert;
+use ReflectionClass;
use function array_pop;
use function explode;
use function is_array;
-use function Safe\sprintf;
+use function sprintf;
use function strpos;
final class GeneratedClassAsserter
@@ -39,9 +40,14 @@ final class GeneratedClassAsserter
public function __construct(InMemoryFileWriter $fileWriter, string $path)
{
$this->nodeFinder = new NodeFinder();
- $phpParser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
- $phpCode = $fileWriter->getContentsByFullPath($path);
- $statements = $phpParser->parse($phpCode);
+ if ((new ReflectionClass(ParserFactory::class))->hasMethod('create')) {
+ $phpParser = (new ParserFactory())->create(1);
+ } else {
+ $phpParser = (new ParserFactory())->createForHostVersion();
+ }
+
+ $phpCode = $fileWriter->getContentsByFullPath($path);
+ $statements = $phpParser->parse($phpCode);
if ($statements === null) {
throw new InvalidArgumentException('No statements found in provided PHP code');
}
diff --git a/test/generation/GenerationTestCase.php b/test/generation/GenerationTestCase.php
index 3b5c79d..593bcf2 100644
--- a/test/generation/GenerationTestCase.php
+++ b/test/generation/GenerationTestCase.php
@@ -10,6 +10,7 @@
use PhpParser\Parser;
use PhpParser\ParserFactory;
use PHPUnit\Framework\TestCase;
+use ReflectionClass;
abstract class GenerationTestCase extends TestCase
{
@@ -18,7 +19,12 @@ abstract class GenerationTestCase extends TestCase
public function setUp(): void
{
- $this->phpParser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
+ if ((new ReflectionClass(ParserFactory::class))->hasMethod('create')) {
+ $this->phpParser = (new ParserFactory())->create(1);
+ } else {
+ $this->phpParser = (new ParserFactory())->createForHostVersion();
+ }
+
$this->nodeFinder = new NodeFinder();
}
diff --git a/test/unit/CodeGenerator/Naming/CannotCreateNamespaceTest.php b/test/unit/CodeGenerator/Naming/CannotCreateNamespaceTest.php
index 3993cf1..cf12839 100644
--- a/test/unit/CodeGenerator/Naming/CannotCreateNamespaceTest.php
+++ b/test/unit/CodeGenerator/Naming/CannotCreateNamespaceTest.php
@@ -7,7 +7,7 @@
use OnMoon\OpenApiServerBundle\CodeGenerator\Naming\CannotCreateNamespace;
use PHPUnit\Framework\TestCase;
-use function Safe\sprintf;
+use function sprintf;
/** @covers \OnMoon\OpenApiServerBundle\CodeGenerator\Naming\CannotCreateNamespace */
final class CannotCreateNamespaceTest extends TestCase
diff --git a/test/unit/CodeGenerator/Naming/CannotCreatePropertyNameTest.php b/test/unit/CodeGenerator/Naming/CannotCreatePropertyNameTest.php
index 45b0ee5..0dfae5f 100644
--- a/test/unit/CodeGenerator/Naming/CannotCreatePropertyNameTest.php
+++ b/test/unit/CodeGenerator/Naming/CannotCreatePropertyNameTest.php
@@ -7,7 +7,7 @@
use OnMoon\OpenApiServerBundle\CodeGenerator\Naming\CannotCreatePropertyName;
use PHPUnit\Framework\TestCase;
-use function Safe\sprintf;
+use function sprintf;
/** @covers \OnMoon\OpenApiServerBundle\CodeGenerator\Naming\CannotCreatePropertyName */
final class CannotCreatePropertyNameTest extends TestCase
diff --git a/test/unit/CodeGenerator/PhpParserGenerators/FileBuilderTest.php b/test/unit/CodeGenerator/PhpParserGenerators/FileBuilderTest.php
index dd67499..14a1948 100644
--- a/test/unit/CodeGenerator/PhpParserGenerators/FileBuilderTest.php
+++ b/test/unit/CodeGenerator/PhpParserGenerators/FileBuilderTest.php
@@ -13,6 +13,7 @@
use PhpParser\Node\Stmt\UseUse;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
+use ReflectionClass;
/** @covers \OnMoon\OpenApiServerBundle\CodeGenerator\PhpParserGenerators\FileBuilder */
class FileBuilderTest extends TestCase
@@ -32,7 +33,11 @@ public function testAddStmt(): void
/** @var \PhpParser\Node\Stmt\Use_ $statementToCheck */
$statementToCheck = $this->fileBuilder->getNamespace()->getNode()->stmts[0];
- Assert::assertEquals('test', $statementToCheck->uses[0]->name->parts[0]);
+ if ((new ReflectionClass(Name::class))->hasProperty('name')) {
+ Assert::assertEquals('test', $statementToCheck->uses[0]->name->name);
+ } else {
+ Assert::assertEquals('test', $statementToCheck->uses[0]->name->parts[0]);
+ }
}
public function testReferenceWithNotMatching(): void
@@ -63,8 +68,12 @@ public function testReferenceWithSameDefinition(): void
/** @var Name $nodeName */
$nodeName = $namespace->getNode()->name;
- Assert::assertEquals('NamespaceOne', $nodeName->parts[0]);
- Assert::assertEquals('NamespaceTwo', $nodeName->parts[1]);
+ if ((new ReflectionClass(Name::class))->hasProperty('name')) {
+ Assert::assertEquals('NamespaceOne\NamespaceTwo', $nodeName->name);
+ } else {
+ Assert::assertEquals('NamespaceOne', $nodeName->parts[0]);
+ Assert::assertEquals('NamespaceTwo', $nodeName->parts[1]);
+ }
Assert::assertEquals('ClassDefinition', $reference);
}
diff --git a/test/unit/CodeGenerator/PhpParserGenerators/InterfaceCodeGeneratorTest.php b/test/unit/CodeGenerator/PhpParserGenerators/InterfaceCodeGeneratorTest.php
index 6523fdd..bc3f255 100644
--- a/test/unit/CodeGenerator/PhpParserGenerators/InterfaceCodeGeneratorTest.php
+++ b/test/unit/CodeGenerator/PhpParserGenerators/InterfaceCodeGeneratorTest.php
@@ -14,6 +14,8 @@
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
+use function str_replace;
+
/** @covers \OnMoon\OpenApiServerBundle\CodeGenerator\PhpParserGenerators\InterfaceCodeGenerator */
class InterfaceCodeGeneratorTest extends TestCase
{
@@ -62,7 +64,7 @@ public function testGenerateWithRequestHandlerInterfaceDefinition(): void
*/
interface TestClass extends RequestHandler
{
- public function test() : void;
+ public function test(): void;
}
EOD;
$expectedGeneratedFileDefinition = new GeneratedFileDefinition(
@@ -71,7 +73,15 @@ public function test() : void;
);
$generatedFileDefinition = $this->interfaceCodeGenerator->generate($generatedInterfaceDefinition);
- Assert::assertEquals($expectedGeneratedFileDefinition, $generatedFileDefinition);
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getClass(),
+ $generatedFileDefinition->getClass()
+ );
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getFileContents(),
+ // to support both versions of nikic/php-parser:"^4.19|^v5.0"
+ str_replace(') : void', '): void', $generatedFileDefinition->getFileContents())
+ );
}
public function testGenerateWithRequestHandlerInterfaceDefinitionAndRequestedType(): void
@@ -102,7 +112,7 @@ public function testGenerateWithRequestHandlerInterfaceDefinitionAndRequestedTyp
interface TestClass extends RequestHandler
{
/** @param TestClass_ $request */
- public function test(TestClass_ $request) : void;
+ public function test(TestClass_ $request): void;
}
EOD;
$expectedGeneratedFileDefinition = new GeneratedFileDefinition(
@@ -111,7 +121,15 @@ public function test(TestClass_ $request) : void;
);
$generatedFileDefinition = $this->interfaceCodeGenerator->generate($generatedInterfaceDefinition);
- Assert::assertEquals($expectedGeneratedFileDefinition, $generatedFileDefinition);
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getClass(),
+ $generatedFileDefinition->getClass()
+ );
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getFileContents(),
+ // to support both versions of nikic/php-parser:"^4.19|^v5.0"
+ str_replace(') : void', '): void', $generatedFileDefinition->getFileContents())
+ );
}
public function testGenerateWithRequestHandlerInterfaceDefinitionAndResponseType(): void
@@ -139,7 +157,7 @@ public function testGenerateWithRequestHandlerInterfaceDefinitionAndResponseType
interface TestClass extends RequestHandler
{
/** @return TestClass_ */
- public function test() : TestClass_;
+ public function test(): TestClass_;
}
EOD;
$expectedGeneratedFileDefinition = new GeneratedFileDefinition(
@@ -148,7 +166,15 @@ public function test() : TestClass_;
);
$generatedFileDefinition = $this->interfaceCodeGenerator->generate($generatedInterfaceDefinition);
- Assert::assertEquals($expectedGeneratedFileDefinition, $generatedFileDefinition);
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getClass(),
+ $generatedFileDefinition->getClass()
+ );
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getFileContents(),
+ // to support both versions of nikic/php-parser:"^4.19|^v5.0"
+ str_replace(') : TestClass_', '): TestClass_', $generatedFileDefinition->getFileContents())
+ );
}
public function testGenerateWithRequestHandlerInterfaceDefinitionAndDescription(): void
@@ -175,7 +201,7 @@ public function testGenerateWithRequestHandlerInterfaceDefinitionAndDescription(
interface TestClass extends RequestHandler
{
/** method description */
- public function test() : void;
+ public function test(): void;
}
EOD;
$expectedGeneratedFileDefinition = new GeneratedFileDefinition(
@@ -184,6 +210,14 @@ public function test() : void;
);
$generatedFileDefinition = $this->interfaceCodeGenerator->generate($generatedInterfaceDefinition);
- Assert::assertEquals($expectedGeneratedFileDefinition, $generatedFileDefinition);
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getClass(),
+ $generatedFileDefinition->getClass()
+ );
+ Assert::assertEquals(
+ $expectedGeneratedFileDefinition->getFileContents(),
+ // to support both versions of nikic/php-parser:"^4.19|^v5.0"
+ str_replace(') : void', '): void', $generatedFileDefinition->getFileContents())
+ );
}
}
diff --git a/test/unit/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGeneratorTest.php b/test/unit/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGeneratorTest.php
index 7f418ec..932f893 100644
--- a/test/unit/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGeneratorTest.php
+++ b/test/unit/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGeneratorTest.php
@@ -21,6 +21,8 @@
use PhpParser\BuilderFactory;
use PHPUnit\Framework\TestCase;
+use function str_replace;
+
/** @covers \OnMoon\OpenApiServerBundle\CodeGenerator\PhpParserGenerators\ServiceSubscriberCodeGenerator */
final class ServiceSubscriberCodeGeneratorTest extends TestCase
{
@@ -122,11 +124,11 @@ public function __construct(ContainerInterface $locator)
/**
* @inheritDoc
*/
- public static function getSubscribedServices() : array
+ public static function getSubscribedServices(): array
{
return ['test' => '?' . ClassName::class];
}
- public function get(string $interface) : ?RequestHandler
+ public function get(string $interface): ?RequestHandler
{
if (!$this->locator->has($interface)) {
return null;
@@ -134,13 +136,21 @@ public function get(string $interface) : ?RequestHandler
return $this->locator->get($interface);
}
/** @return string[] */
- public function getAllowedCodes(string $apiClass, string $dtoClass) : array
+ public function getAllowedCodes(string $apiClass, string $dtoClass): array
{
return self::HTTP_CODES[$apiClass][$dtoClass];
}
}
EOD;
- self::assertEquals($expectedFileContent, $result->getFileContents());
+ self::assertEquals(
+ $expectedFileContent,
+ // to support both versions of nikic/php-parser:"^4.19|^v5.0"
+ str_replace(
+ [') : array', ') : ?RequestHandler'],
+ ['): array', '): ?RequestHandler'],
+ $result->getFileContents()
+ )
+ );
}
}
diff --git a/test/unit/Exception/ApiCallFailedTest.php b/test/unit/Exception/ApiCallFailedTest.php
index 761fcd3..061dd33 100644
--- a/test/unit/Exception/ApiCallFailedTest.php
+++ b/test/unit/Exception/ApiCallFailedTest.php
@@ -7,7 +7,7 @@
use OnMoon\OpenApiServerBundle\Exception\ApiCallFailed;
use PHPUnit\Framework\TestCase;
-use function Safe\sprintf;
+use function sprintf;
/** @covers \OnMoon\OpenApiServerBundle\Exception\ApiCallFailed */
final class ApiCallFailedTest extends TestCase
diff --git a/test/unit/Exception/CannotParseOpenApiTest.php b/test/unit/Exception/CannotParseOpenApiTest.php
index 8ffa902..b82eaf4 100644
--- a/test/unit/Exception/CannotParseOpenApiTest.php
+++ b/test/unit/Exception/CannotParseOpenApiTest.php
@@ -7,7 +7,7 @@
use OnMoon\OpenApiServerBundle\Exception\CannotParseOpenApi;
use PHPUnit\Framework\TestCase;
-use function Safe\sprintf;
+use function sprintf;
/** @covers \OnMoon\OpenApiServerBundle\Exception\CannotParseOpenApi */
final class CannotParseOpenApiTest extends TestCase