From 489305aac920ee843072f9b8723185b370111695 Mon Sep 17 00:00:00 2001 From: Martin Rademacher Date: Wed, 5 Jun 2024 15:52:28 +1200 Subject: [PATCH] Replace current processor array with a pipeline class (#1585) Deprecates all processor related methods on `Generator` and provides simpler, more powerful alternatives in the new `Pipeline` class that now internally wraps processors. Also deprecates the unused `ProcessorInterface`. --- .../scan.php | 24 ++-- .../schema-query-parameter/scan.php | 24 ++-- bin/openapi | 2 +- docs/reference/generator.md | 6 +- src/Generator.php | 108 +++++++++++------ src/Pipeline.php | 113 ++++++++++++++++++ src/Processors/ProcessorInterface.php | 3 + tests/Analysers/ReflectionAnalyserTest.php | 6 +- tests/Analysers/TokenAnalyserTest.php | 4 +- tests/Annotations/AbstractAnnotationTest.php | 4 +- tests/Annotations/AttachableTest.php | 3 +- tests/GeneratorTest.php | 12 +- tests/OpenApiTestCase.php | 17 ++- tests/PipelineTest.php | 103 ++++++++++++++++ tests/RefTest.php | 2 +- tools/src/Docs/ProcGenerator.php | 26 ++-- 16 files changed, 352 insertions(+), 105 deletions(-) create mode 100644 src/Pipeline.php create mode 100644 tests/PipelineTest.php diff --git a/Examples/processors/schema-query-parameter-attributes/scan.php b/Examples/processors/schema-query-parameter-attributes/scan.php index 081396be8..83575d45c 100644 --- a/Examples/processors/schema-query-parameter-attributes/scan.php +++ b/Examples/processors/schema-query-parameter-attributes/scan.php @@ -1,6 +1,7 @@ addPsr4('SchemaQueryParameterProcessor\\', __DIR__); -$openapiGenerator = new Generator(); -$processors = []; -foreach ($openapiGenerator->getProcessors() as $processor) { - $processors[] = $processor; - if ($processor instanceof BuildPaths) { - $processors[] = new SchemaQueryParameter(); +$insertMatch = function (array $pipes) { + foreach ($pipes as $ii => $pipe) { + if ($pipe instanceof BuildPaths) { + return $ii; + } } -} -$openapi = $openapiGenerator - ->setProcessors($processors) - ->generate([__DIR__ . '/app']); - -file_put_contents(__DIR__ . '/schema-query-parameter.yaml', $openapi->toYaml()); + return null; +}; +$openapi = (new Generator()) + ->withProcessor(function (Pipeline $pipeline) use ($insertMatch) { $pipeline->insert(new SchemaQueryParameter(), $insertMatch); }) + ->generate([__DIR__ . '/app']); +// file_put_contents(__DIR__ . '/schema-query-parameter.yaml', $openapi->toYaml()); echo $openapi->toYaml(); diff --git a/Examples/processors/schema-query-parameter/scan.php b/Examples/processors/schema-query-parameter/scan.php index 7311e6ce9..83575d45c 100644 --- a/Examples/processors/schema-query-parameter/scan.php +++ b/Examples/processors/schema-query-parameter/scan.php @@ -1,6 +1,7 @@ addPsr4('SchemaQueryParameterProcessor\\', __DIR__); -$generator = new Generator(); - -// merge our custom processor -$processors = []; -foreach ($generator->getProcessors() as $processor) { - $processors[] = $processor; - if ($processor instanceof BuildPaths) { - $processors[] = new SchemaQueryParameter(); +$insertMatch = function (array $pipes) { + foreach ($pipes as $ii => $pipe) { + if ($pipe instanceof BuildPaths) { + return $ii; + } } -} -$options = [ - 'processors' => $processors, -]; + return null; +}; -$openapi = $generator - ->setProcessors($processors) +$openapi = (new Generator()) + ->withProcessor(function (Pipeline $pipeline) use ($insertMatch) { $pipeline->insert(new SchemaQueryParameter(), $insertMatch); }) ->generate([__DIR__ . '/app']); // file_put_contents(__DIR__ . '/schema-query-parameter.yaml', $openapi->toYaml()); echo $openapi->toYaml(); diff --git a/bin/openapi b/bin/openapi index b37d4535d..a41fa0d75 100755 --- a/bin/openapi +++ b/bin/openapi @@ -219,7 +219,7 @@ foreach ($options["processor"] as $processor) { } elseif (class_exists($processor)) { $processor = new $processor(); } - $generator->addProcessor($processor); + $generator->getProcessorPipeline()->add($processor); } $analyser = $options['legacy'] diff --git a/docs/reference/generator.md b/docs/reference/generator.md index f70e6f054..48c997df7 100644 --- a/docs/reference/generator.md +++ b/docs/reference/generator.md @@ -32,9 +32,9 @@ $openapi = \OpenApi\scan(__DIR__, ['exclude' => ['tests'], 'pattern' => '*.php'] ``` The two configuration options for the underlying Doctrine doc-block parser `aliases` and `namespaces` -are not part of this function and need to be set separately. +are not part of this function and need to be set separately. -Being static this means setting them back is the callers responsibility and there is also the fact that +Being static this means setting them back is the callers responsibility and there is also the fact that some Doctrine configuration currently can not be reverted easily. Therefore, having a single side effect free way of using swagger-php seemed like a good idea... @@ -57,7 +57,7 @@ $processors = [/* my processors */]; $finder = \Symfony\Component\Finder\Finder::create()->files()->name('*.php')->in(__DIR__); $openapi = (new \OpenApi\Generator($logger)) - ->setProcessors($processors) + ->setProcessorPipeline(new \OpenApi\Pipeline($processors)) ->setAliases(['MY' => 'My\Annotations']) ->setNamespaces(['My\\Annotations\\']) ->setAnalyser(new \OpenApi\Analysers\TokenAnalyser()) diff --git a/src/Generator.php b/src/Generator.php index fb6ae3623..ff9c1f757 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -48,13 +48,13 @@ class Generator protected $namespaces; /** @var AnalyserInterface|null The configured analyzer. */ - protected $analyser; + protected $analyser = null; /** @var array */ protected $config = []; - /** @var array|null List of configured processors. */ - protected $processors = null; + /** @var Pipeline|null */ + protected $processorPipeline = null; /** @var LoggerInterface|null PSR logger. */ protected $logger = null; @@ -243,13 +243,10 @@ public function setConfig(array $config): Generator return $this; } - /** - * @return array - */ - public function getProcessors(): array + public function getProcessorPipeline(): Pipeline { - if (null === $this->processors) { - $this->processors = [ + if (null === $this->processorPipeline) { + $this->processorPipeline = new Pipeline([ new Processors\DocBlockDescriptions(), new Processors\MergeIntoOpenApi(), new Processors\MergeIntoComponents(), @@ -267,34 +264,65 @@ public function getProcessors(): array new Processors\MergeXmlContent(), new Processors\OperationId(), new Processors\CleanUnmerged(), - ]; + ]); } $config = $this->getConfig(); - foreach ($this->processors as $processor) { - $rc = new \ReflectionClass($processor); + $walker = function (callable $pipe) use ($config) { + $rc = new \ReflectionClass($pipe); // 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); + if (method_exists($pipe, $setter)) { + $pipe->{$setter}($value); } } } - } + }; + + return $this->processorPipeline->walk($walker); + } + + public function setProcessorPipeline(Pipeline $processor): Generator + { + $this->processorPipeline = $processor; + + return $this; + } + + /** + * Chainable method that allows to modify the processor pipeline. + * + * @param callable $with callable with the current processor pipeline passed in + */ + public function withProcessor(callable $with): Generator + { + $with($this->getProcessorPipeline()); - return $this->processors; + return $this; + } + + /** + * @return array + * + * @deprecated + */ + public function getProcessors(): array + { + return $this->getProcessorPipeline()->pipes(); } /** * @param array|null $processors + * + * @deprecated */ public function setProcessors(?array $processors): Generator { - $this->processors = $processors; + $this->processorPipeline = null !== $processors ? new Pipeline($processors) : null; return $this; } @@ -302,42 +330,42 @@ public function setProcessors(?array $processors): Generator /** * @param callable|ProcessorInterface $processor * @param class-string|null $before + * + * @deprecated */ public function addProcessor($processor, ?string $before = null): Generator { - $processors = $this->getProcessors(); + $processors = $this->processorPipeline ?: $this->getProcessorPipeline(); if (!$before) { - $processors[] = $processor; + $processors->add($processor); } else { - $tmp = []; - foreach ($processors as $current) { - if ($current instanceof $before) { - $tmp[] = $processor; + $matcher = function (array $pipes) use ($before) { + foreach ($pipes as $ii => $current) { + if ($current instanceof $before) { + return $ii; + } } - $tmp[] = $current; - } - $processors = $tmp; + + return null; + }; + $processors->insert($processor, $matcher); } - $this->setProcessors($processors); + $this->processorPipeline = $processors; return $this; } /** * @param callable|ProcessorInterface $processor + * + * @deprecated */ public function removeProcessor($processor, bool $silent = false): Generator { - $processors = $this->getProcessors(); - if (false === ($key = array_search($processor, $processors, true))) { - if ($silent) { - return $this; - } - throw new \InvalidArgumentException('Processor not found'); - } - unset($processors[$key]); - $this->setProcessors($processors); + $processors = $this->processorPipeline ?: $this->getProcessorPipeline(); + $processors->remove($processor); + $this->processorPipeline = $processors; return $this; } @@ -348,6 +376,8 @@ public function removeProcessor($processor, bool $silent = false): Generator * @param ProcessorInterface|callable $processor the new processor * @param null|callable $matcher Optional matcher callable to identify the processor to replace. * If none given, matching is based on the processors class. + * + * @deprecated */ public function updateProcessor($processor, ?callable $matcher = null): Generator { @@ -390,6 +420,7 @@ public static function scan(iterable $sources, array $options = []): ?OA\OpenApi 'namespaces' => self::DEFAULT_NAMESPACES, 'analyser' => null, 'analysis' => null, + 'processor' => null, 'processors' => null, 'logger' => null, 'validate' => true, @@ -401,7 +432,8 @@ public static function scan(iterable $sources, array $options = []): ?OA\OpenApi ->setAliases($config['aliases']) ->setNamespaces($config['namespaces']) ->setAnalyser($config['analyser']) - ->setProcessors($config['processors']) + ->setProcessorPipeline($config['processor']) + ->setProcessorPipeline(new Pipeline($config['processors'])) ->generate($sources, $config['analysis'], $config['validate']); } @@ -455,7 +487,7 @@ public function generate(iterable $sources, ?Analysis $analysis = null, bool $va $this->scanSources($sources, $analysis, $rootContext); // post-processing - $analysis->process($this->getProcessors()); + $this->getProcessorPipeline()->process($analysis); if ($analysis->openapi) { // overwrite default/annotated version diff --git a/src/Pipeline.php b/src/Pipeline.php new file mode 100644 index 000000000..d54ab2716 --- /dev/null +++ b/src/Pipeline.php @@ -0,0 +1,113 @@ + + */ + protected $pipes = []; + + public function __construct(array $pipes = []) + { + $this->pipes = $pipes; + } + + /** + * @deprecated This will be removed in 5.0 + */ + public function pipes(): array + { + return $this->pipes; + } + + public function add(callable $pipe): Pipeline + { + $this->pipes[] = $pipe; + + return $this; + } + + /** + * @param callable|class-string|null $pipe + */ + public function remove($pipe = null, ?callable $matcher = null): Pipeline + { + if (!$pipe && !$matcher) { + throw new \InvalidArgumentException('pipe or callable must not be empty'); + } + + // allow matching on class name in $pipe in a string + if (is_string($pipe) && !$matcher) { + $pipeClass = $pipe; + $matcher = function ($pipe) use ($pipeClass) { + return !$pipe instanceof $pipeClass; + }; + } + + if ($matcher) { + $tmp = []; + foreach ($this->pipes as $pipe) { + if ($matcher($pipe)) { + $tmp[] = $pipe; + } + } + + $this->pipes = $tmp; + } else { + if (false === ($key = array_search($pipe, $this->pipes, true))) { + return $this; + } + + unset($this->pipes[$key]); + + $this->pipes = array_values($this->pipes); + } + + return $this; + } + + /** + * @param callable $matcher Callable to determine the position to insert (returned as `int`) + */ + public function insert(callable $pipe, callable $matcher): Pipeline + { + $index = $matcher($this->pipes); + if (null === $index || $index < 0 || $index > count($this->pipes)) { + throw new \InvalidArgumentException('Matcher result out of range'); + } + + array_splice($this->pipes, $index, 0, [$pipe]); + + return $this; + } + + public function walk(callable $walker): Pipeline + { + foreach ($this->pipes as $pipe) { + $walker($pipe); + } + + return $this; + } + + /** + * @param mixed $payload + * + * @return mixed + */ + public function process($payload) + { + foreach ($this->pipes as $pipe) { + /** @deprecated null payload returned from pipe */ + $payload = $pipe($payload) ?: $payload; + } + + return $payload; + } +} diff --git a/src/Processors/ProcessorInterface.php b/src/Processors/ProcessorInterface.php index e8e96ee88..67e8e820c 100644 --- a/src/Processors/ProcessorInterface.php +++ b/src/Processors/ProcessorInterface.php @@ -6,6 +6,9 @@ namespace OpenApi\Processors; +/** + * @deprecated + */ interface ProcessorInterface { } diff --git a/tests/Analysers/ReflectionAnalyserTest.php b/tests/Analysers/ReflectionAnalyserTest.php index bb5b3b2bd..b8fd6d3d9 100644 --- a/tests/Analysers/ReflectionAnalyserTest.php +++ b/tests/Analysers/ReflectionAnalyserTest.php @@ -94,7 +94,7 @@ public function testApiDocBlockBasic(AnalyserInterface $analyser): void ->withContext(function (Generator $generator) use ($analyser) { $analyser->setGenerator($generator); $analysis = $analyser->fromFile($this->fixture('Apis/DocBlocks/basic.php'), $this->getContext([], $generator->getVersion())); - $analysis->process($generator->getProcessors()); + $generator->getProcessorPipeline()->process($analysis); return $analysis; }); @@ -125,7 +125,7 @@ public function testApiAttributesBasic(AnalyserInterface $analyser): void ->withContext(function (Generator $generator) use ($analyser) { $analyser->setGenerator($generator); $analysis = $analyser->fromFile($this->fixture('Apis/Attributes/basic.php'), $this->getContext([], $generator->getVersion())); - $analysis->process(($generator)->getProcessors()); + $generator->getProcessorPipeline()->process($analysis); return $analysis; }); @@ -166,7 +166,7 @@ public function testApiMixedBasic(AnalyserInterface $analyser): void ->withContext(function (Generator $generator) use ($analyser) { $analyser->setGenerator($generator); $analysis = $analyser->fromFile($this->fixture('Apis/Mixed/basic.php'), $this->getContext([], $generator->getVersion())); - $analysis->process(($generator)->getProcessors()); + $generator->getProcessorPipeline()->process($analysis); return $analysis; }); diff --git a/tests/Analysers/TokenAnalyserTest.php b/tests/Analysers/TokenAnalyserTest.php index 00cf3951d..dac65837a 100644 --- a/tests/Analysers/TokenAnalyserTest.php +++ b/tests/Analysers/TokenAnalyserTest.php @@ -280,7 +280,7 @@ public function testPhp8PromotedProperties(): void public function testAnonymousFunctions(): void { $analysis = $this->analysisFromFixtures(['PHP/AnonymousFunctions.php'], [], new TokenAnalyser()); - $analysis->process((new Generator())->getProcessors()); + (new Generator())->getProcessorPipeline()->process($analysis); $infos = $analysis->getAnnotationsOfType(OA\Info::class, true); $this->assertCount(1, $infos); @@ -295,6 +295,6 @@ public function testPhp8NamedArguments(): void $schemas = $analysis->getAnnotationsOfType(OA\Schema::class, true); $this->assertCount(1, $schemas); - $analysis->process((new Generator())->getProcessors()); + (new Generator())->getProcessorPipeline()->process($analysis); } } diff --git a/tests/Annotations/AbstractAnnotationTest.php b/tests/Annotations/AbstractAnnotationTest.php index 7a0527138..7dbc837f6 100644 --- a/tests/Annotations/AbstractAnnotationTest.php +++ b/tests/Annotations/AbstractAnnotationTest.php @@ -130,7 +130,7 @@ public function testMatchNested(string $class, $expected): void public function testDuplicateOperationIdValidation(): void { $analysis = $this->analysisFromFixtures(['DuplicateOperationId.php']); - $analysis->process((new Generator())->getProcessors()); + (new Generator())->getProcessorPipeline()->process($analysis); $this->assertOpenApiLogEntryContains('operationId must be unique. Duplicate value found: "getItem"'); $this->assertFalse($analysis->validate()); @@ -151,7 +151,7 @@ public function testValidateExamples(): void $this->skipLegacy(); $analysis = $this->analysisFromFixtures(['BadExampleParameter.php']); - $analysis->process((new Generator())->getProcessors()); + (new Generator())->getProcessorPipeline()->process($analysis); $this->assertOpenApiLogEntryContains('Required @OA\PathItem() not found'); $this->assertOpenApiLogEntryContains('Required @OA\Info() not found'); diff --git a/tests/Annotations/AttachableTest.php b/tests/Annotations/AttachableTest.php index 70e6f30cd..b3b6d549a 100644 --- a/tests/Annotations/AttachableTest.php +++ b/tests/Annotations/AttachableTest.php @@ -9,6 +9,7 @@ use OpenApi\Analysis; use OpenApi\Annotations as OA; use OpenApi\Generator; +use OpenApi\Pipeline; use OpenApi\Processors\CleanUnusedComponents; use OpenApi\Tests\Fixtures\Annotations\CustomAttachable; use OpenApi\Tests\OpenApiTestCase; @@ -31,7 +32,7 @@ public function testCustomAttachableImplementationsAreAttached(): void (new Generator()) ->addAlias('oaf', 'OpenApi\Tests\Fixtures\Annotations') ->addNamespace('OpenApi\Tests\Fixtures\Annotations\\') - ->setProcessors($this->processors([CleanUnusedComponents::class])) + ->withProcessor(function (Pipeline $processor) { $processor->remove(null, function ($pipe) { return !$pipe instanceof CleanUnusedComponents; }); }) ->generate($this->fixtures(['UsingCustomAttachables.php']), $analysis); $schemas = $analysis->getAnnotationsOfType(OA\Schema::class, true); diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index 4683b5498..09d1b97fa 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -107,21 +107,13 @@ public function testRemoveProcessor(): void $this->assertEquals($processors, $generator->getProcessors()); } - public function testRemoveProcessorNotFound(): void - { - $this->expectException(\InvalidArgumentException::class); - - (new Generator())->removeProcessor(function () { - }); - } - protected function assertOperationIdHash(Generator $generator, bool $expected): void { - foreach ($generator->getProcessors() as $processor) { + $generator->getProcessorPipeline()->walk(function ($processor) use ($expected) { if ($processor instanceof OperationId) { $this->assertEquals($expected, $processor->isHash()); } - } + }); } public static function configCases(): iterable diff --git a/tests/OpenApiTestCase.php b/tests/OpenApiTestCase.php index cfcc0d505..7b75819da 100644 --- a/tests/OpenApiTestCase.php +++ b/tests/OpenApiTestCase.php @@ -16,6 +16,7 @@ use OpenApi\Context; use OpenApi\Analysers\TokenAnalyser; use OpenApi\Generator; +use OpenApi\Pipeline; use PHPUnit\Framework\TestCase; use Psr\Log\AbstractLogger; use Psr\Log\LoggerInterface; @@ -225,13 +226,17 @@ public static function fixtures(array $files): array }, $files); } - public static function processors(array $strip = [], array $add = []): array + public static function processors(array $strip = []): array { - $processors = (new Generator())->getProcessors(); + $processors = []; - $processors = array_filter($processors, function ($processor) use ($strip) { - return !is_object($processor) || !in_array(get_class($processor), $strip); - }); + (new Generator()) + ->getProcessorPipeline() + ->walk(function ($processor) use (&$processors, $strip) { + if (!is_object($processor) || !in_array(get_class($processor), $strip)) { + $processors[] = $processor; + } + }); return $processors; } @@ -242,7 +247,7 @@ public function analysisFromFixtures(array $files, array $processors = [], ?Anal (new Generator($this->getTrackingLogger())) ->setAnalyser($analyzer ?: $this->getAnalyzer()) - ->setProcessors($processors) + ->setProcessorPipeline(new Pipeline($processors)) ->generate($this->fixtures($files), $analysis, false); return $analysis; diff --git a/tests/PipelineTest.php b/tests/PipelineTest.php new file mode 100644 index 000000000..0e14cbc1d --- /dev/null +++ b/tests/PipelineTest.php @@ -0,0 +1,103 @@ +add = $add; + } + + // ------------------------------------------------------------------------ + + public function __invoke($payload) + { + return $payload . $this->add; + } + }; + } + + public function testProcess() + { + $pipeline = new Pipeline([$this->pipe('x')]); + $result = $pipeline->process(''); + + $this->assertEquals('x', $result); + } + + public function testAdd() + { + $pipeline = new Pipeline(); + + $pipeline->add($this->pipe('a')); + $this->assertEquals('a', $pipeline->process('')); + + $pipeline->add($this->pipe('b')); + $this->assertEquals('ab', $pipeline->process('')); + } + + public function testRemoveStrict() + { + $pipeline = new Pipeline(); + + $pipeline->add($pipec = $this->pipe('c')); + $pipeline->add($this->pipe('d')); + $this->assertEquals('cd', $pipeline->process('')); + + $pipeline->remove($pipec); + $this->assertEquals('d', $pipeline->process('')); + } + + public function testRemoveMatcher() + { + $pipeline = new Pipeline(); + + $pipeline->add($pipec = $this->pipe('c')); + $pipeline->add($this->pipe('d')); + $this->assertEquals('cd', $pipeline->process('')); + + $pipeline->remove(null, function ($pipe) use ($pipec) { return $pipe !== $pipec; }); + $this->assertEquals('d', $pipeline->process('')); + } + + public function testRemoveClassString() + { + $pipeline = new Pipeline(); + + $pipeline->add($this->pipe('c')); + $pipeline->add($this); + $this->assertEquals('cx', $pipeline->process('')); + + $pipeline->remove(__CLASS__); + $this->assertEquals('c', $pipeline->process('')); + } + + public function testInsert() + { + $pipeline = new Pipeline(); + + $pipeline->add($this->pipe('x')); + $pipeline->add($this->pipe('z')); + $this->assertEquals('xz', $pipeline->process('')); + + $pipeline->insert($this->pipe('y'), function ($pipes) { return 1; }); + $this->assertEquals('xyz', $pipeline->process('')); + } +} diff --git a/tests/RefTest.php b/tests/RefTest.php index d860cfdbd..b852341c8 100644 --- a/tests/RefTest.php +++ b/tests/RefTest.php @@ -27,7 +27,7 @@ public function testRef(): void $openapi->merge($this->annotationsFromDocBlockParser($comment)); $analysis = new Analysis([], $this->getContext()); $analysis->addAnnotation($openapi, $this->getContext()); - $analysis->process((new Generator())->getProcessors()); + (new Generator())->getProcessorPipeline()->process($analysis); $analysis->validate(); // escape / as ~1 diff --git a/tools/src/Docs/ProcGenerator.php b/tools/src/Docs/ProcGenerator.php index 702ccac9f..b35e38498 100644 --- a/tools/src/Docs/ProcGenerator.php +++ b/tools/src/Docs/ProcGenerator.php @@ -51,19 +51,21 @@ public function getProcessorsDetails(): array $processors = []; $defaultProcessors = []; - foreach ((new Generator())->getProcessors() as $processor) { - $rc = new \ReflectionClass($processor); - $class = $rc->getName(); + (new Generator()) + ->getProcessorPipeline() + ->walk(function ($processor) use (&$processors, &$defaultProcessors) { + $rc = new \ReflectionClass($processor); + $class = $rc->getName(); - $defaultProcessors[] = $class; - $processors[] = [ - 'class' => $class, - 'name' => $rc->getShortName(), - 'default' => true, - 'options' => $this->getOptionsDetails($rc), - 'phpdoc' => $this->extractDocumentation($rc->getDocComment()), - ]; - } + $defaultProcessors[] = $class; + $processors[] = [ + 'class' => $class, + 'name' => $rc->getShortName(), + 'default' => true, + 'options' => $this->getOptionsDetails($rc), + 'phpdoc' => $this->extractDocumentation($rc->getDocComment()), + ]; + }); $proccesorsDir = dirname((new \ReflectionClass(MergeIntoOpenApi::class))->getFileName()); foreach (glob("$proccesorsDir/*.php") as $processor) {