Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Analysers/AnnotationFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface AnnotationFactoryInterface extends GeneratorAwareInterface
public function isSupported(): bool;

/**
* @return array<OA\AbstractAnnotation> top level annotations
* @return list<OA\AbstractAnnotation> top level annotations
*/
public function build(\Reflector $reflector, Context $context): array;
}
4 changes: 2 additions & 2 deletions src/Analysers/ComposerAutoloaderScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class ComposerAutoloaderScanner
/**
* Collect all classes/interfaces/traits known by composer.
*
* @param array<string> $namespaces
* @param list<string> $namespaces
*
* @return array<string>
* @return list<string>
*/
public function scan(array $namespaces): array
{
Expand Down
2 changes: 1 addition & 1 deletion src/Analysers/DocBlockParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function setAliases(array $aliases): void
*
* @param string $comment a T_DOC_COMMENT
*
* @return array<OA\AbstractAnnotation|object>
* @return list<OA\AbstractAnnotation|object>
*/
public function fromComment(string $comment, Context $context): array
{
Expand Down
7 changes: 3 additions & 4 deletions src/Analysers/ReflectionAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,17 @@
*
* Can read either PHP <code>DocBlock</code>s or <code>Attribute</code>s.
*
* Due to the nature of reflection this requires all related classes
* to be auto-loadable.
* Due to the nature of reflection, this requires all related classes to be auto-loadable.
*/
class ReflectionAnalyser implements AnalyserInterface
{
use GeneratorAwareTrait;

/** @var AnnotationFactoryInterface[] */
/** @var list<AnnotationFactoryInterface> */
protected array $annotationFactories = [];

/**
* @param array<AnnotationFactoryInterface> $annotationFactories
* @param list<AnnotationFactoryInterface> $annotationFactories
*/
public function __construct(array $annotationFactories = [])
{
Expand Down
63 changes: 27 additions & 36 deletions src/Analysis.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
/**
* Result of the analyser.
*
* Pretends to be an array of annotations, but also contains detected classes
* and helper functions for the processors.
* Pretends to be an array of annotations but also contains detected classes and helper functions for the processors.
*/
class Analysis
{
/** @var \SplObjectStorage<OA\AbstractAnnotation, Context> */
public \SplObjectStorage $annotations;

/**
Expand Down Expand Up @@ -45,6 +45,9 @@ class Analysis

public ?Context $context = null;

/**
* @param list<OA\AbstractAnnotation> $annotations
*/
public function __construct(array $annotations = [], ?Context $context = null)
{
$this->annotations = new \SplObjectStorage();
Expand All @@ -53,7 +56,7 @@ public function __construct(array $annotations = [], ?Context $context = null)
$this->addAnnotations($annotations, $context);
}

public function addAnnotation(object $annotation, Context $context): void
public function addAnnotation(OA\AbstractAnnotation $annotation, Context $context): void
{
if ($this->annotations->offsetExists($annotation)) {
return;
Expand All @@ -72,10 +75,11 @@ public function addAnnotation(object $annotation, Context $context): void
$context->annotations[] = $annotation;
}
}

$this->annotations->offsetSet($annotation, $context);
$blacklist = property_exists($annotation, '_blacklist') ? $annotation::$_blacklist : [];
foreach ($annotation as $property => $value) {
if (in_array($property, $blacklist)) {

foreach (get_object_vars($annotation) as $property => $value) {
if (in_array($property, $annotation::$_blacklist)) {
if ($property === '_unmerged') {
foreach ($value as $item) {
$this->addAnnotation($item, $context);
Expand All @@ -93,6 +97,9 @@ public function addAnnotation(object $annotation, Context $context): void
}
}

/**
* @param list<OA\AbstractAnnotation> $annotations
*/
public function addAnnotations(array $annotations, Context $context): void
{
foreach ($annotations as $annotation) {
Expand Down Expand Up @@ -141,7 +148,7 @@ public function addAnalysis(Analysis $analysis): void
/**
* Get all subclasses of the given parent class.
*
* @param string $parent the parent class
* @param class-string $parent the parent class
*
* @return array map of class => definition pairs of sub-classes
*/
Expand All @@ -161,14 +168,14 @@ public function getSubClasses(string $parent): array
/**
* Get a list of all super classes for the given class.
*
* @param string $class the class name
* @param bool $direct flag to find only the actual class parents
* @param class-string|null $class the class name
* @param bool $direct flag to find only the actual class parents
*
* @return array map of class => definition pairs of parent classes
*/
public function getSuperClasses(string $class, bool $direct = false): array
public function getSuperClasses(?string $class, bool $direct = false): array
{
$classDefinition = $this->classes[$class] ?? null;
$classDefinition = $this->classes[$class ?? ''] ?? null;
if (!$classDefinition || empty($classDefinition['extends'])) {
// unknown class, or no inheritance
return [];
Expand All @@ -192,12 +199,12 @@ public function getSuperClasses(string $class, bool $direct = false): array
/**
* Get the list of interfaces used by the given class or by classes which it extends.
*
* @param string $class the class name
* @param bool $direct flag to find only the actual class interfaces
* @param class-string|null $class the class name
* @param bool $direct flag to find only the actual class interfaces
*
* @return array map of class => definition pairs of interfaces
*/
public function getInterfacesOfClass(string $class, bool $direct = false): array
public function getInterfacesOfClass(?string $class, bool $direct = false): array
{
$classes = $direct ? [] : array_keys($this->getSuperClasses($class));
// add self
Expand Down Expand Up @@ -238,12 +245,12 @@ public function getInterfacesOfClass(string $class, bool $direct = false): array
/**
* Get the list of traits used by the given class/trait or by classes which it extends.
*
* @param string $source the source name
* @param bool $direct flag to find only the actual class traits
* @param string|null $source the source name
* @param bool $direct flag to find only the actual class traits
*
* @return array map of class => definition pairs of traits
*/
public function getTraitsOfClass(string $source, bool $direct = false): array
public function getTraitsOfClass(?string $source, bool $direct = false): array
{
$sources = $direct ? [] : array_keys($this->getSuperClasses($source));
// add self
Expand Down Expand Up @@ -284,10 +291,10 @@ public function getTraitsOfClass(string $source, bool $direct = false): array
/**
* @template T extends OA\AbstractAnnotation
*
* @param class-string<T>|array<class-string<T>> $classes one or more class names
* @param bool $strict in non-strict mode child classes are also detected
* @param class-string<T>|list<class-string<T>> $classes one or more class names
* @param bool $strict in non-strict mode child classes are also detected
*
* @return array<T>
* @return list<T>
*/
public function getAnnotationsOfType($classes, bool $strict = false): array
{
Expand Down Expand Up @@ -335,22 +342,6 @@ public function getAnnotationForSource(string $fqdn, string $sourceClass = OA\Sc
return null;
}

public function getContext(object $annotation): ?Context
{
if ($annotation instanceof OA\AbstractAnnotation) {
return $annotation->_context;
}
if ($this->annotations->offsetExists($annotation) === false) {
throw new OpenApiException('Annotation not found');
}
$context = $this->annotations[$annotation];
if ($context instanceof Context) {
return $context;
}

throw new OpenApiException('Annotation has no context - did you use addAnnotation()/addAnnotations()');
}

/**
* Build an analysis with only the annotations that are merged into the OpenAPI annotation.
*/
Expand Down
19 changes: 8 additions & 11 deletions src/Annotations/AbstractAnnotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ abstract class AbstractAnnotation implements \JsonSerializable
*/
public $attachables = Generator::UNDEFINED;

/**
* @var Context|null
*/
public $_context;
public ?Context $_context;

/**
* Annotations that couldn't be merged by mapping or postprocessing.
Expand All @@ -57,9 +54,9 @@ abstract class AbstractAnnotation implements \JsonSerializable
* Specify the type of the property.
*
* Examples:
* 'name' => 'string' // a string
* 'required' => 'boolean', // true or false
* 'tags' => '[string]', // array containing strings
* 'name' => 'string' // a string
* 'required' => 'boolean', // true or false
* 'tags' => '[string]', // string array
* 'in' => ["query", "header", "path", "formData", "body"] // must be one on these
* 'oneOf' => [Schema::class] // array of schema objects.
*
Expand All @@ -71,9 +68,9 @@ abstract class AbstractAnnotation implements \JsonSerializable
* Declarative mapping of Annotation types to properties.
*
* Examples:
* Info::clas => 'info', // Set @OA\Info annotation as the info property.
* Parameter::clas => ['parameters'], // Append @OA\Parameter annotations the parameters array.
* PathItem::clas => ['paths', 'path'], // Append @OA\PathItem annotations the paths array and use path as key.
* Info::class => 'info', // Set @OA\Info annotation as the info property.
* Parameter::class => ['parameters'], // Append @OA\Parameter annotations the parameters list.
* PathItem::class => ['paths', 'path'], // Add @OA\PathItem annotation to the `paths` map and use `path` as key.
*
* @var array<class-string<AbstractAnnotation>,string|array<string>>
*/
Expand All @@ -87,7 +84,7 @@ abstract class AbstractAnnotation implements \JsonSerializable
public static $_parents = [];

/**
* List of properties are blacklisted from the JSON output.
* Properties that are blacklisted from the JSON output.
*
* @var array<string>
*/
Expand Down
8 changes: 5 additions & 3 deletions src/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,14 @@ public function __debugInfo()
}

/**
* Resolve the fully qualified name.
* Resolve the given `source` to a fully qualified name.
*
* @return class-string|null
*/
public function fullyQualifiedName(?string $source): string
public function fullyQualifiedName(?string $source): ?string
{
if ($source === null) {
return '';
return null;
}

$namespace = $this->namespace ? str_replace('\\\\', '\\', '\\' . $this->namespace . '\\') : '\\';
Expand Down
6 changes: 3 additions & 3 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Generator
/** @var array<string,string> */
public const DEFAULT_ALIASES = ['oa' => 'OpenApi\\Annotations'];

/** @var array<string> */
/** @var list<string> */
public const DEFAULT_NAMESPACES = ['OpenApi\\Annotations\\'];

/** @var array<string,string> Map of namespace aliases to be supported by doctrine. */
Expand Down Expand Up @@ -83,7 +83,7 @@ public static function isDefault(...$value): bool
}

/**
* @return array<string>
* @return array<string, string>
*/
public function getAliases(): array
{
Expand All @@ -105,7 +105,7 @@ public function setAliases(array $aliases): Generator
}

/**
* @return array<string>|null
* @return list<string>|null
*/
public function getNamespaces(): ?array
{
Expand Down
3 changes: 1 addition & 2 deletions src/Loggers/ConsoleLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ class ConsoleLogger extends AbstractLogger implements LoggerInterface
LogLevel::NOTICE,
];

/** @var bool */
protected $loggedMessageAboveNotice = false;
protected bool $loggedMessageAboveNotice = false;

protected bool $debug;

Expand Down
2 changes: 1 addition & 1 deletion src/Processors/Concerns/RefTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait RefTrait
{
protected function toRefKey(Context $context, ?string $name): string
{
$fqn = strtolower($context->fullyQualifiedName($name));
$fqn = strtolower($context->fullyQualifiedName($name) ?? '');

return ltrim($fqn, '\\');
}
Expand Down
2 changes: 1 addition & 1 deletion src/Processors/ExpandEnums.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ protected function expandContextEnum(Analysis $analysis): void

foreach ($schemas as $schema) {
if ($schema->_context->is('enum')) {
$re = new \ReflectionEnum($schema->_context->fullyQualifiedName($schema->_context->enum));
$re = new \ReflectionEnum($schema->_context->fullyQualifiedName($schema->_context->enum) ?? '');
$schema->schema = Generator::isDefault($schema->schema) ? $re->getShortName() : $schema->schema;

$schemaType = $schema->type;
Expand Down
13 changes: 11 additions & 2 deletions src/Serializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,18 @@ class Serializer
OA\XmlContent::class,
];

/**
* @param class-string<OA\AbstractAnnotation> $className
*/
protected static function isValidAnnotationClass(string $className): bool
{
return in_array($className, self::$VALID_ANNOTATIONS);
}

/**
* Deserialize a string.
*
* @param class-string<OA\AbstractAnnotation> $className
*/
public function deserialize(string $jsonString, string $className): OA\AbstractAnnotation
{
Expand All @@ -80,6 +85,8 @@ public function deserialize(string $jsonString, string $className): OA\AbstractA

/**
* Deserialize a file.
*
* @param class-string<OA\AbstractAnnotation> $className
*/
public function deserializeFile(string $filename, string $format = 'json', string $className = OA\OpenApi::class): OA\AbstractAnnotation
{
Expand All @@ -99,10 +106,12 @@ public function deserializeFile(string $filename, string $format = 'json', strin

/**
* Do deserialization.
*
* @param class-string<OA\AbstractAnnotation> $className
*/
protected function doDeserialize(\stdClass $c, string $class, Context $context): OA\AbstractAnnotation
protected function doDeserialize(\stdClass $c, string $className, Context $context): OA\AbstractAnnotation
{
$annotation = new $class(['_context' => $context]);
$annotation = new $className(['_context' => $context]);
foreach ((array) $c as $property => $value) {
if ($property === '$ref') {
$property = 'ref';
Expand Down