Skip to content

Commit

Permalink
Fix injecting context into attribute contructor
Browse files Browse the repository at this point in the history
  • Loading branch information
DerManoMann committed Aug 26, 2021
1 parent d33a98f commit d15547d
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 30 deletions.
20 changes: 12 additions & 8 deletions src/Analysers/AttributeAnnotationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use OpenApi\Annotations\AbstractAnnotation;
use OpenApi\Context;
use OpenApi\Generator;

class AttributeAnnotationFactory implements AnnotationFactoryInterface
{
Expand All @@ -17,18 +18,21 @@ public function build(\Reflector $reflector, Context $context): array
$context->annotations = [];
}

Generator::$context = $context;
$annotations = [];
foreach ($reflector->getAttributes() as $attribute) {
$instance = $attribute->newInstance();
if ($instance instanceof AbstractAnnotation) {
$instance->_context = $context;
try {
foreach ($reflector->getAttributes() as $attribute) {
$instance = $attribute->newInstance();
if ($instance instanceof AbstractAnnotation) {
$instance->_context = $context;
}
$annotations[] = $instance;
}
$annotations[] = $instance;
} finally {
Generator::$context = null;
}

$context->annotations = $annotations;

return array_filter($annotations, function ($a) {
return $context->annotations = array_filter($annotations, function ($a) {
return $a !== null;
});
}
Expand Down
19 changes: 6 additions & 13 deletions src/Analysers/DocBlockParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\DocParser;
use OpenApi\Context;
use OpenApi\Generator;

if (class_exists(AnnotationRegistry::class, true)) {
AnnotationRegistry::registerLoader(
Expand All @@ -24,7 +25,7 @@ function (string $class): bool {
if (!$loaded && $namespace === 'OpenApi\\Annotations\\') {
if (in_array(strtolower(substr($class, 20)), ['definition', 'path'])) {
// Detected an 2.x annotation?
throw new \Exception('The annotation @SWG\\' . substr($class, 20) . '() is deprecated. Found in ' . DocBlockParser::$context . "\nFor more information read the migration guide: https://github.com/zircote/swagger-php/blob/master/docs/Migrating-to-v3.md");
throw new \Exception('The annotation @SWG\\' . substr($class, 20) . '() is deprecated. Found in ' . Generator::$context . "\nFor more information read the migration guide: https://github.com/zircote/swagger-php/blob/master/docs/Migrating-to-v3.md");
}
}

Expand Down Expand Up @@ -59,13 +60,6 @@ class DocBlockParser
*/
public static $defaultImports = ['oa' => 'OpenApi\\Annotations'];

/**
* Allows Annotation classes to know the context of the annotation that is being processed.
*
* @var null|Context
*/
public static $context;

/**
* @var DocParser
*/
Expand Down Expand Up @@ -94,16 +88,13 @@ public function fromComment(string $comment, Context $context): array
$context->comment = $comment;

try {
self::$context = $context;
Generator::$context = $context;
if ($context->is('annotations') === false) {
$context->annotations = [];
}
$annotations = $this->docParser->parse($comment);
self::$context = null;

return $annotations;
return $this->docParser->parse($comment);
} catch (\Exception $e) {
self::$context = null;
if (preg_match('/^(.+) at position ([0-9]+) in ' . preg_quote((string) $context, '/') . '\.$/', $e->getMessage(), $matches)) {
$errorMessage = $matches[1];
$errorPos = (int) $matches[2];
Expand All @@ -117,6 +108,8 @@ public function fromComment(string $comment, Context $context): array
}

return [];
} finally {
Generator::$context = null;
}
}
}
15 changes: 9 additions & 6 deletions src/Annotations/AbstractAnnotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

namespace OpenApi\Annotations;

use OpenApi\Analysers\DocBlockParser;
use OpenApi\Context;
use OpenApi\Generator;
use OpenApi\Util;
Expand Down Expand Up @@ -88,8 +87,8 @@ public function __construct(array $properties)
if (isset($properties['_context'])) {
$this->_context = $properties['_context'];
unset($properties['_context']);
} elseif (DocBlockParser::$context) {
$this->_context = DocBlockParser::$context;
} elseif (Generator::$context) {
$this->_context = Generator::$context;
} else {
$this->_context = Context::detect(1);
}
Expand All @@ -113,7 +112,7 @@ public function __construct(array $properties)
} elseif (is_array($value)) {
$annotations = [];
foreach ($value as $annotation) {
if (is_object($annotation) && $annotation instanceof AbstractAnnotation) {
if ($annotation instanceof AbstractAnnotation) {
$annotations[] = $annotation;
} else {
$this->_context->logger->warning('Unexpected field in ' . $this->identity() . ' in ' . $this->_context);
Expand All @@ -123,7 +122,7 @@ public function __construct(array $properties)
} elseif (is_object($value)) {
$this->merge([$value]);
} else {
if (!(\PHP_VERSION_ID >= 80100 && $value === Generator::UNDEFINED)) {
if ($value !== Generator::UNDEFINED) {
$this->_context->logger->warning('Unexpected parameter "' . $property . '" in ' . $this->identity());
}
}
Expand Down Expand Up @@ -654,8 +653,12 @@ private function validateArrayType($value): bool
*
* @return AbstractAnnotation
*/
private function nested($annotation, Context $nestedContext)
protected function nested($annotation, Context $nestedContext)
{
if (!$annotation) {
return $annotation;
}

if (property_exists($annotation, '_context') && $annotation->_context === $this->_context) {
$annotation->_context = $nestedContext;
}
Expand Down
30 changes: 29 additions & 1 deletion src/Annotations/JsonContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
* @Annotation
*/
class JsonContent extends Schema
abstract class JsonContentImpl extends Schema
{

/**
Expand Down Expand Up @@ -45,3 +45,31 @@ class JsonContent extends Schema
Examples::class => ['examples', 'example'],
];
}

if (\PHP_VERSION_ID >= 80100) {
/**
* @Annotation
*/
class JsonContent extends JsonContentImpl
{
public function __construct(
array $properties = [],
string $ref = Generator::UNDEFINED
) {
parent::__construct($properties + [
'ref' => $ref,
]);
}
}
} else {
/**
* @Annotation
*/
class JsonContent extends JsonContentImpl
{
public function __construct(array $properties)
{
parent::__construct($properties);
}
}
}
4 changes: 3 additions & 1 deletion src/Annotations/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ class Response extends ResponeImpl
public function __construct(
array $properties = [],
$response = Generator::UNDEFINED,
string $description = Generator::UNDEFINED
string $description = Generator::UNDEFINED,
$content = Generator::UNDEFINED
) {
parent::__construct($properties + [
'response' => $response,
'description' => $description,
'value' => $content !== Generator::UNDEFINED ? [$content] : Generator::UNDEFINED,
]);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
*/
class Generator
{
/**
* Allows Annotation classes to know the context of the annotation that is being processed.
*
* @var null|Context
*/
public static $context;

/** @var string Magic value to differentiate between null and undefined. */
public const UNDEFINED = '@OA\Generator::UNDEFINED🙈';

Expand Down
2 changes: 1 addition & 1 deletion tests/Fixtures/Apis/Attributes/basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class ProductController
path: '/products/{product_id}',
tags: ['Products'],
responses: [
new OA\Response(response: 200, description: 'successful operation'),
new OA\Response(response: 200, description: 'successful operation', content: new OA\JsonContent(ref: '#/components/schemas/Product')),
new OA\Response(response: 401, description: 'oops'),
]
)]
Expand Down

0 comments on commit d15547d

Please sign in to comment.