From 22cec77fe1cfebe5ca0575767ef01da0e529cd04 Mon Sep 17 00:00:00 2001 From: Martin Rademacher Date: Wed, 4 May 2022 11:34:31 +1200 Subject: [PATCH] Add support for generator / processor configuration (#1211) --- src/Generator.php | 53 ++++++++++++++++++++++++++--- src/Processors/ExpandClasses.php | 26 +++++++------- src/Processors/ExpandInterfaces.php | 2 +- tests/GeneratorTest.php | 34 ++++++++++++++++-- 4 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/Generator.php b/src/Generator.php index f8c24d032..e82d565c1 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -35,20 +35,23 @@ class Generator /** @var string Magic value to differentiate between null and undefined. */ public const UNDEFINED = '@OA\Generator::UNDEFINED🙈'; - /** @var string[] */ + /** @var array */ public const DEFAULT_ALIASES = ['oa' => 'OpenApi\\Annotations']; - /** @var string[] */ + /** @var array */ public const DEFAULT_NAMESPACES = ['OpenApi\\Annotations\\']; - /** @var array Map of namespace aliases to be supported by doctrine. */ + /** @var array Map of namespace aliases to be supported by doctrine. */ protected $aliases; - /** @var array|null List of annotation namespaces to be autoloaded by doctrine. */ + /** @var array|null List of annotation namespaces to be autoloaded by doctrine. */ protected $namespaces; /** @var AnalyserInterface|null The configured analyzer. */ protected $analyser; + /** @var array */ + protected $config = []; + /** @var callable[]|null List of configured processors. */ protected $processors = null; @@ -177,6 +180,32 @@ public function setAnalyser(?AnalyserInterface $analyser): Generator return $this; } + public function getDefaultConfig(): array + { + return [ + 'operationId' => [ + 'hash' => true, + ], + ]; + } + + public function getConfig(): array + { + return $this->config + $this->getDefaultConfig(); + } + + /** + * Set generator and/or processor config. + * + * @param array $config + */ + public function setConfig(array $config): Generator + { + $this->config = $config + $this->config; + + return $this; + } + /** * @return callable[] */ @@ -203,6 +232,22 @@ public function getProcessors(): array ]; } + $config = $this->getConfig(); + foreach ($this->processors as $processor) { + $rc = new \ReflectionClass($processor); + + // apply config + $processorKey = lcfirst($rc->getShortName()); + if (array_key_exists($processorKey, $config)) { + foreach ($config[$processorKey] as $name => $value) { + $setter = 'set' . ucfirst($name); + if (method_exists($processor, $setter)) { + $processor->{$setter}($value); + } + } + } + } + return $this->processors; } diff --git a/src/Processors/ExpandClasses.php b/src/Processors/ExpandClasses.php index 5fb653948..7e729decd 100644 --- a/src/Processors/ExpandClasses.php +++ b/src/Processors/ExpandClasses.php @@ -12,9 +12,9 @@ use OpenApi\Generator; /** - * Iterate over the chain of anchestors of a schema and: - * - merge anchestor annotations/methods/properties into the schema if the anchestor doesn't have a schema itself - * - inherit from the anchestor if it has a schema (allOf) and stop. + * Iterate over the chain of ancestors of a schema and: + * - merge ancestor annotations/methods/properties into the schema if the ancestor doesn't have a schema itself + * - inherit from the ancestor if it has a schema (allOf) and stop. */ class ExpandClasses { @@ -27,20 +27,20 @@ public function __invoke(Analysis $analysis) foreach ($schemas as $schema) { if ($schema->_context->is('class')) { - $anchestors = $analysis->getSuperClasses($schema->_context->fullyQualifiedName($schema->_context->class)); + $ancestors = $analysis->getSuperClasses($schema->_context->fullyQualifiedName($schema->_context->class)); $existing = []; - foreach ($anchestors as $anchestor) { - $anchestorSchema = $analysis->getSchemaForSource($anchestor['context']->fullyQualifiedName($anchestor['class'])); - if ($anchestorSchema) { - $refPath = !Generator::isDefault($anchestorSchema->schema) ? $anchestorSchema->schema : $anchestor['class']; - $this->inheritFrom($analysis, $schema, $anchestorSchema, $refPath, $anchestor['context']); + foreach ($ancestors as $ancestor) { + $ancestorSchema = $analysis->getSchemaForSource($ancestor['context']->fullyQualifiedName($ancestor['class'])); + if ($ancestorSchema) { + $refPath = !Generator::isDefault($ancestorSchema->schema) ? $ancestorSchema->schema : $ancestor['class']; + $this->inheritFrom($analysis, $schema, $ancestorSchema, $refPath, $ancestor['context']); - // one anchestor is enough + // one ancestor is enough break; } else { - $this->mergeAnnotations($schema, $anchestor, $existing); - $this->mergeMethods($schema, $anchestor, $existing); - $this->mergeProperties($schema, $anchestor, $existing); + $this->mergeAnnotations($schema, $ancestor, $existing); + $this->mergeMethods($schema, $ancestor, $existing); + $this->mergeProperties($schema, $ancestor, $existing); } } } diff --git a/src/Processors/ExpandInterfaces.php b/src/Processors/ExpandInterfaces.php index ac977621c..0c78f8d8b 100644 --- a/src/Processors/ExpandInterfaces.php +++ b/src/Processors/ExpandInterfaces.php @@ -31,7 +31,7 @@ public function __invoke(Analysis $analysis) $interfaces = $analysis->getInterfacesOfClass($className, true); if (class_exists($className) && ($parent = get_parent_class($className)) && ($inherited = array_keys(class_implements($parent)))) { - // strip interfaces we inherit from anchestor + // strip interfaces we inherit from ancestor foreach (array_keys($interfaces) as $interface) { if (in_array(ltrim($interface, '\\'), $inherited)) { unset($interfaces[$interface]); diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index e15d43a91..1b718a1c6 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -50,8 +50,7 @@ public function testScanInvalidSource(): void public function processorCases(): iterable { return [ - [new OperationId(false), false], - [new OperationId(true), true], + [new OperationId(), true], [new class(false) extends OperationId { }, false], ]; @@ -116,4 +115,35 @@ public function testRemoveProcessorNotFound(): void (new Generator())->removeProcessor(function () { }); } + + protected function assertOperationIdHash(Generator $generator, bool $expected) + { + foreach ($generator->getProcessors() as $processor) { + if ($processor instanceof OperationId) { + $this->assertEquals($expected, $processor->isHash()); + } + } + } + + public function testConfig() + { + $generator = new Generator(); + $this->assertOperationIdHash($generator, true); + + $generator->setConfig(['operationId' => ['hash' => false]]); + $this->assertOperationIdHash($generator, false); + } + + public function testCallableProcessor() + { + $generator = new Generator(); + // not the default + $operationId = new OperationId(false); + $generator->addProcessor(function (Analysis $analysis) use ($operationId) { + $operationId($analysis); + }); + + $this->assertOperationIdHash($generator, true); + $this->assertFalse($operationId->isHash()); + } }