diff --git a/README.md b/README.md
index 5c180e1..998199d 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ open_api_server:
root_path: %kernel.project_dir%/src/Generated
language_level: 7.4.0 # minimum PHP version the generated code should be compatible with
generated_dir_permissions: 0755 # permissions for the generated directories
+ full_doc_blocks: false # whether to generate DocBlocks for typed variables and params
specs:
petstore:
path: '../spec/petstore.yaml' # path to OpenApi specification
diff --git a/src/CodeGenerator/ApiServerCodeGenerator.php b/src/CodeGenerator/ApiServerCodeGenerator.php
index 867f032..570b04b 100644
--- a/src/CodeGenerator/ApiServerCodeGenerator.php
+++ b/src/CodeGenerator/ApiServerCodeGenerator.php
@@ -8,7 +8,6 @@
use OnMoon\OpenApiServerBundle\Event\CodeGenerator\ClassGraphReadyEvent;
use OnMoon\OpenApiServerBundle\Event\CodeGenerator\FilesReadyEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use function Safe\substr;
class ApiServerCodeGenerator
{
@@ -37,24 +36,6 @@ public function generate() : void
$this->interfaceGenerator->setAllInterfaces($graph);
$this->attributeGenerator->setAllAttributes($graph);
$this->nameGenerator->setAllNamesAndPaths($graph);
- //ToDo: remove this loop
- foreach ($graph->getSpecifications() as $specificationDefinition) {
- foreach ($specificationDefinition->getOperations() as $operation) {
- $request = $operation->getRequest();
- if ($request === null) {
- continue;
- }
-
- foreach ($request->getProperties() as $property) {
- $object = $property->getObjectTypeDefinition();
- if ($object === null) {
- continue;
- }
-
- $this->nameGenerator->setTreePathsAndClassNames($object, $request->getNamespace(), substr($request->getClassName(), 0, -3) . $object->getClassName(), $request->getFilePath());
- }
- }
- }
$this->eventDispatcher->dispatch(new ClassGraphReadyEvent($graph));
diff --git a/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php
index 54af9ad..8db9337 100644
--- a/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/CodeGenerator.php
@@ -31,13 +31,14 @@ abstract class CodeGenerator
protected BuilderFactory $factory;
protected ScalarTypesResolver $typeResolver;
protected string $languageLevel;
- protected bool $fullDocs = false;
+ protected bool $fullDocs;
- public function __construct(BuilderFactory $factory, ScalarTypesResolver $typeResolver, string $languageLevel)
+ public function __construct(BuilderFactory $factory, ScalarTypesResolver $typeResolver, string $languageLevel, bool $fullDocs)
{
$this->factory = $factory;
$this->typeResolver = $typeResolver;
$this->languageLevel = $languageLevel;
+ $this->fullDocs = $fullDocs;
}
public function use(Namespace_ $builder, string $parentNameSpace, ClassDefinition $class) : void
@@ -85,11 +86,10 @@ public function getDocComment(array $lines) : string
$glued = ' ' . trim($lines[0]);
} else {
$asteriskLines = array_map(
- //ToDo: add space after * anyway after tests
- static fn(string $line) : string => ' *' . (trim($line)?' ':'') . trim($line),
+ static fn(string $line) : string => ' * ' . trim($line),
$lines
);
- $glued = PHP_EOL . implode(PHP_EOL, $asteriskLines) . PHP_EOL;
+ $glued = PHP_EOL . implode(PHP_EOL, $asteriskLines) . PHP_EOL;
}
return sprintf('/**%s */', $glued);
diff --git a/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
index de20d42..da6815c 100644
--- a/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/DtoCodeGenerator.php
@@ -18,8 +18,6 @@
use PhpParser\Node\Stmt\Return_;
use function count;
use function Safe\sprintf;
-use function str_replace;
-use function strpos;
class DtoCodeGenerator extends CodeGenerator
{
@@ -51,15 +49,14 @@ public function generate(DtoDefinition $definition) : GeneratedFileDefinition
}
$classBuilder->addStmts($this->generateProperties($definition));
- //ToDo: Move below after tests
- if ($definition instanceof ResponseDtoDefinition) {
- $classBuilder->addStmt($this->generateResponseCodeStaticMethod($definition));
- }
-
$classBuilder->addStmts($this->generateConstructor($definition));
$classBuilder->addStmts($this->generateGetters($definition));
$classBuilder->addStmts($this->generateSetters($definition));
+ if ($definition instanceof ResponseDtoDefinition) {
+ $classBuilder->addStmt($this->generateResponseCodeStaticMethod($definition));
+ }
+
$fileBuilder = $fileBuilder->addStmt($classBuilder);
return new GeneratedFileDefinition(
@@ -176,13 +173,14 @@ private function generateClassProperty(PropertyDefinition $definition) : Propert
$docCommentLines[] = '';
}
- //ToDo: remove this
- if (strpos($definition->getClassPropertyName(), 'queryParameters') === false
- &&
- strpos($definition->getClassPropertyName(), 'pathParameters') === false
- &&
- strpos($definition->getClassPropertyName(), 'body') === false
- ) {
+ $supportSymfonySerializer = true;
+ /*
+ * Symfony serializer does not support property class definitions.
+ * ToDo: Remove this hack and phpstan ignores after serializer is no longer used.
+ */
+
+ /** @phpstan-ignore-next-line */
+ if ($this->fullDocs || $definition->isArray() || $supportSymfonySerializer) {
$docCommentLines[] = sprintf(
'@var %s $%s ',
$this->getTypeDocBlock($definition),
@@ -190,6 +188,7 @@ private function generateClassProperty(PropertyDefinition $definition) : Propert
);
}
+ /** @phpstan-ignore-next-line */
if (count($docCommentLines)) {
$property->setDocComment($this->getDocComment($docCommentLines));
}
@@ -199,11 +198,10 @@ private function generateClassProperty(PropertyDefinition $definition) : Propert
private function generateMethodParameter(PropertyDefinition $definition) : Param
{
-//ToDo: Remove
return $this
->factory
->param($definition->getClassPropertyName())
- ->setType(str_replace('?', '', $this->getTypePhp($definition)));
+ ->setType($this->getTypePhp($definition));
}
private function getAssignmentDefinition(string $name) : Assign
@@ -250,12 +248,12 @@ private function generateSetter(PropertyDefinition $definition) : Method
->addParam($this->generateMethodParameter($definition))
->addStmt($this->getAssignmentDefinition($definition->getClassPropertyName()))
->addStmt(new Return_(new Variable('this')));
-//ToDo: remove
+
if ($this->fullDocs || $definition->isArray()) {
$blocks = [
sprintf(
'@param %s $%s',
- str_replace('|null', '', $this->getTypeDocBlock($definition)),
+ $this->getTypeDocBlock($definition),
$definition->getClassPropertyName()
),
];
diff --git a/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php
index 6141c29..fc50e8b 100644
--- a/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/InterfaceCodeGenerator.php
@@ -7,6 +7,7 @@
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\GeneratedFileDefinition;
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\GeneratedInterfaceDefinition;
use OnMoon\OpenApiServerBundle\CodeGenerator\Definitions\ServiceInterfaceDefinition;
+use function count;
use function Safe\sprintf;
class InterfaceCodeGenerator extends CodeGenerator
@@ -31,26 +32,48 @@ public function generate(GeneratedInterfaceDefinition $definition) : GeneratedFi
if ($definition instanceof ServiceInterfaceDefinition) {
$methodBuilder = $this->factory->method($definition->getMethodName())->makePublic();
$request = $definition->getRequestType();
+ $docBlocks = [];
+
if ($request !== null) {
$this->use($fileBuilder, $definition->getNamespace(), $request);
$methodBuilder->addParam(
$this->factory->param('request')->setType($request->getClassName())
);
- //ToDo: Add full docblock support
+ if ($this->fullDocs) {
+ $docBlocks[] = sprintf(
+ '@param %s $%s',
+ $request->getClassName(),
+ 'request'
+ );
+ }
}
$response = $definition->getResponseType();
if ($response !== null) {
$this->use($fileBuilder, $definition->getNamespace(), $response);
$methodBuilder->setReturnType($response->getClassName());
+ if ($this->fullDocs) {
+ $docBlocks[] = sprintf(
+ '@return %s',
+ $response->getClassName()
+ );
+ }
} else {
$methodBuilder->setReturnType('void');
}
$description = $definition->getMethodDescription();
if ($description !== null) {
- $methodBuilder->setDocComment($this->getDocComment([$description]));
+ if (count($docBlocks)) {
+ $docBlocks = [$description, '', ...$docBlocks];
+ } else {
+ $docBlocks[] = $description;
+ }
+ }
+
+ if (count($docBlocks) > 0) {
+ $methodBuilder->setDocComment($this->getDocComment($docBlocks));
}
$interfaceBuilder->addStmt($methodBuilder);
diff --git a/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php b/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php
index 83f6e58..cad1a68 100644
--- a/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php
+++ b/src/CodeGenerator/PhpParserGenerators/ServiceSubscriberCodeGenerator.php
@@ -33,6 +33,7 @@ public function generate(GraphDefinition $graphDefinition) : GeneratedFileDefini
$fileBuilder = $this->factory->namespace($subscriberDefinition->getNamespace());
$fileBuilder->addStmt($this->factory->use(ContainerInterface::class));
+ $fileBuilder->addStmt($this->factory->use(RequestHandler::class));
$classBuilder = $this
->factory
@@ -44,9 +45,6 @@ public function generate(GraphDefinition $graphDefinition) : GeneratedFileDefini
$this->use($fileBuilder, $subscriberDefinition->getNamespace(), $implement);
}
- //ToDo: move upwards
- $fileBuilder->addStmt($this->factory->use(RequestHandler::class));
-
$services = [];
foreach ($graphDefinition->getSpecifications() as $specification) {
foreach ($specification->getOperations() as $operation) {
@@ -55,85 +53,99 @@ public function generate(GraphDefinition $graphDefinition) : GeneratedFileDefini
}
}
- //ToDo: full DocBlock support
- $classBuilder->addStmts(
- [
- $this
- ->factory
- ->property('locator')
- ->makePrivate()
- ->setType('ContainerInterface'),
- $this
- ->factory
- ->method('__construct')
- ->makePublic()
- ->addParam(
- $this->factory->param('locator')->setType('ContainerInterface')
- )
- ->addStmt(
- new Assign(new Variable('this->locator'), new Variable('locator'))
- ),
- $this
- ->factory
- ->method('getSubscribedServices')
- ->makePublic()
- ->makeStatic()
- ->setDocComment('/**
+ $property = $this
+ ->factory
+ ->property('locator')
+ ->makePrivate()
+ ->setType('ContainerInterface');
+ if ($this->fullDocs) {
+ $property->setDocComment('/** @var ContainerInterface */');
+ }
+
+ $constructor = $this
+ ->factory
+ ->method('__construct')
+ ->makePublic()
+ ->addParam(
+ $this->factory->param('locator')->setType('ContainerInterface')
+ )
+ ->addStmt(
+ new Assign(new Variable('this->locator'), new Variable('locator'))
+ );
+ if ($this->fullDocs) {
+ $constructor->setDocComment('/** @param ContainerInterface $locator */');
+ }
+
+ $getSubscribedServices = $this
+ ->factory
+ ->method('getSubscribedServices')
+ ->makePublic()
+ ->makeStatic()
+ ->setDocComment('/**
* @inheritDoc
*/')
- ->addStmt(
- new Return_(
- new Array_(
- array_map(
- static fn (string $service) : ArrayItem =>
- new ArrayItem(
- new Concat(
- new String_('?'),
- new ClassConstFetch(
- new Name($service),
- 'class'
- )
- )
- ),
- $services
+ ->addStmt(
+ new Return_(
+ new Array_(
+ array_map(
+ static fn (string $service) : ArrayItem =>
+ new ArrayItem(
+ new Concat(
+ new String_('?'),
+ new ClassConstFetch(
+ new Name($service),
+ 'class'
)
)
- )
- ),
- $this
- ->factory
- ->method('get')
- ->makePublic()
- ->setReturnType('?RequestHandler')
- ->addParam(
- $this->factory->param('interface')->setType('string')
- )
- ->addStmt(
- new If_(new BooleanNot(new MethodCall(
- new Variable('this->locator'),
- 'has',
- [
- new Arg(
- new Variable('interface')
- ),
- ]
- )), ['stmts' => [new Return_($this->factory->val(null))]])
+ ),
+ $services
)
- ->addStmt(
- new Return_(
- new MethodCall(
- new Variable('this->locator'),
- 'get',
- [
- new Arg(
- new Variable('interface')
- ),
- ]
- )
- )
+ )
+ )
+ );
+
+ $getRequestHandler = $this
+ ->factory
+ ->method('get')
+ ->makePublic()
+ ->setReturnType('?RequestHandler')
+ ->addParam(
+ $this->factory->param('interface')->setType('string')
+ )
+ ->addStmt(
+ new If_(new BooleanNot(new MethodCall(
+ new Variable('this->locator'),
+ 'has',
+ [
+ new Arg(
+ new Variable('interface')
),
- ]
- );
+ ]
+ )), ['stmts' => [new Return_($this->factory->val(null))]])
+ )
+ ->addStmt(
+ new Return_(
+ new MethodCall(
+ new Variable('this->locator'),
+ 'get',
+ [
+ new Arg(
+ new Variable('interface')
+ ),
+ ]
+ )
+ )
+ );
+
+ if ($this->fullDocs) {
+ $docs = [
+ '@param string $interface',
+ '@return RequestHandler|null',
+ ];
+ $getRequestHandler->setDocComment($this->getDocComment($docs));
+ }
+
+ $classBuilder->addStmts([$property, $constructor, $getSubscribedServices, $getRequestHandler]);
$fileBuilder->addStmt($classBuilder);
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 4a097f9..d3f2c21 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -22,6 +22,7 @@ public function getConfigTreeBuilder()
->scalarNode('root_name_space')->defaultValue('App\Generated')->cannotBeEmpty()->end()
->scalarNode('language_level')->defaultValue('7.4.0')->cannotBeEmpty()->end()
->scalarNode('generated_dir_permissions')->defaultValue('0755')->cannotBeEmpty()->end()
+ ->booleanNode('full_doc_blocks')->defaultValue(false)->end()
->arrayNode('specs')
->arrayPrototype()
->children()
diff --git a/src/DependencyInjection/OpenApiServerExtension.php b/src/DependencyInjection/OpenApiServerExtension.php
index 8cead3f..bac5822 100644
--- a/src/DependencyInjection/OpenApiServerExtension.php
+++ b/src/DependencyInjection/OpenApiServerExtension.php
@@ -32,6 +32,7 @@ public function load(array $configs, ContainerBuilder $container) : void
* root_name_space:string,
* language_level:string,
* generated_dir_permissions: string,
+ * full_doc_blocks: bool,
* specs: array{
* path: string,
* type?: string,
@@ -60,6 +61,7 @@ public function load(array $configs, ContainerBuilder $container) : void
$container->setParameter('openapi.generated.code.root.namespace', $rootNameSpace);
$container->setParameter('openapi.generated.code.language.level', $config['language_level']);
$container->setParameter('openapi.generated.code.dir.permissions', $config['generated_dir_permissions']);
+ $container->setParameter('openapi.generated.code.full.doc.blocks', $config['full_doc_blocks']);
$definition = $container->getDefinition(SpecificationLoader::class);
diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml
index 84e0d86..7fcc846 100644
--- a/src/Resources/config/services.xml
+++ b/src/Resources/config/services.xml
@@ -31,12 +31,15 @@
%openapi.generated.code.language.level%
+ %openapi.generated.code.full.doc.blocks%
%openapi.generated.code.language.level%
+ %openapi.generated.code.full.doc.blocks%
%openapi.generated.code.language.level%
+ %openapi.generated.code.full.doc.blocks%
%openapi.generated.code.dir.permissions%