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
26 changes: 13 additions & 13 deletions generate-spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@
/** @var AttributeGroup $attrGroup */
foreach ($classMethod->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
if ($attr->name->getLast() !== 'Route' && $attr->name->getLast() !== 'ApiRoute' && $attr->name->getLast() !== 'FrontpageRoute') {
if (!in_array($attr->name->getLast(), ['Route', 'ApiRoute', 'FrontpageRoute'], true)) {
continue;
}

Expand Down Expand Up @@ -397,7 +397,7 @@
// This is very ugly, but since we do not parse the entire source code we can not say with certainty which controller type is used.
// To still allow apps to use custom controllers that extend OCSController, we only check the suffix and have the warning if the controller type can not be detected.
$isOCS = str_ends_with($parentControllerClass, 'OCSController');
if ($parentControllerClass !== 'Controller' && $parentControllerClass !== 'ApiController' && $parentControllerClass !== 'OCSController' && !$isOCS) {
if (!in_array($parentControllerClass, ['Controller', 'ApiController', 'OCSController'], true) && !$isOCS) {
Logger::warning($routeName, 'You are extending a custom controller class. Make sure that it ends with "OCSController" if it extends "OCSController" itself.');
} elseif ($isOCS !== ($pathPrefix === '/ocs/v2.php')) {
Logger::warning($routeName, 'Do not mix OCS/non-OCS routes and non-OCS/OCS controllers!');
Expand All @@ -422,9 +422,9 @@
Logger::panic($routeName, "Controller '" . $controllerName . "' is marked as ignore but also has other scopes");
}

$tagName = implode('_', array_map(fn (string $s) => strtolower($s), Helpers::splitOnUppercaseFollowedByNonUppercase(str_replace('\\', '', $controllerName))));
$tagName = implode('_', array_map(strtolower(...), Helpers::splitOnUppercaseFollowedByNonUppercase(str_replace('\\', '', $controllerName))));
$doc = $controllerClass->getDocComment()?->getText();
if ($doc != null && count(array_filter($tags, fn (array $tag): bool => $tag['name'] === $tagName)) == 0) {
if ($doc != null && count(array_filter($tags, fn (array $tag): bool => $tag['name'] === $tagName)) === 0) {
$classDescription = [];

$docNodes = $phpDocParser->parse(new TokenIterator($lexer->tokenize($doc)))->children;
Expand Down Expand Up @@ -520,7 +520,7 @@
}

$classMethodInfo = ControllerMethod::parse($routeName, $definitions, $methodFunction, $isPublic, $isAdmin, $isDeprecated, $isPasswordConfirmation, $isCORS, $isOCS);
if (count($classMethodInfo->responses) == 0) {
if (count($classMethodInfo->responses) === 0) {
Logger::error($routeName, 'Returns no responses');
continue;
}
Expand Down Expand Up @@ -612,7 +612,7 @@
foreach ($urlParameters as $urlParameter) {
$matchingParameters = array_filter($route->controllerMethod->parameters, fn (ControllerMethodParameter $param): bool => $param->name == $urlParameter);
$requirement = $route->requirements[$urlParameter] ?? null;
if (count($matchingParameters) == 1) {
if (count($matchingParameters) === 1) {
$parameter = $matchingParameters[array_keys($matchingParameters)[0]];

$schema = $parameter->type->toArray(true);
Expand Down Expand Up @@ -640,7 +640,7 @@
continue;
}
preg_match("/^\^\(([v0-9-.|]*)\)\\$$/m", (string)$requirement, $matches);
if (count($matches) == 2) {
if (count($matches) === 2) {
$enum = explode('|', $matches[1]);
} else {
Logger::error($route->name, 'Invalid requirement for apiVersion');
Expand Down Expand Up @@ -714,7 +714,7 @@

$hasEmpty = array_filter($contentTypeResponses, fn (ControllerMethodResponse $response): bool => $response->type == null) !== [];
$uniqueResponses = array_values(array_intersect_key($contentTypeResponses, array_unique(array_map(fn (ControllerMethodResponse $response): array|\stdClass => $response->type->toArray(), array_filter($contentTypeResponses, fn (ControllerMethodResponse $response): bool => $response->type != null)), SORT_REGULAR)));
if (count($uniqueResponses) == 1) {
if (count($uniqueResponses) === 1) {
if ($hasEmpty) {
$mergedContentTypeResponses[$contentType] = [];
} else {
Expand Down Expand Up @@ -946,7 +946,7 @@
];
}

if (count($schemas) == 0 && count($routes) == 0) {
if (count($schemas) === 0 && count($routes) === 0) {
Logger::error('app', 'No spec generated');
}

Expand All @@ -972,7 +972,7 @@

$usedSchemas = ['Capabilities', 'PublicCapabilities'];

foreach (glob(dirname($out) . '/openapi*.json') as $path) {
foreach (glob(dirname((string)$out) . '/openapi*.json') as $path) {
unlink($path);
}

Expand Down Expand Up @@ -1060,12 +1060,12 @@
$openapiScope['paths'] = new stdClass();
}

$startExtension = strrpos($out, '.');
$startExtension = strrpos((string)$out, '.');
if ($startExtension !== false) {
// Path + filename (without extension)
$path = substr($out, 0, $startExtension);
$path = substr((string)$out, 0, $startExtension);
// Extension
$extension = substr($out, $startExtension);
$extension = substr((string)$out, $startExtension);
$scopeOut = $path . $scopeSuffix . $extension;
} else {
$scopeOut = $out . $scopeSuffix;
Expand Down
1 change: 0 additions & 1 deletion rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@
deadCode: true,
codeQuality: true,
typeDeclarations: true,
strictBooleans: true,
);
8 changes: 4 additions & 4 deletions src/ControllerMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,9 @@ public static function parse(string $context,
}

if (str_starts_with($type->name, 'OCS') && str_ends_with($type->name, 'Exception')) {
$responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, 'application/json', new OpenApiType(context: $context, type: 'array', maxItems: 0), null);
$responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, 'application/json', new OpenApiType(context: $context, type: 'array', maxItems: 0));
} else {
$responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, 'text/plain', new OpenApiType(context: $context, type: 'string'), null);
$responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, 'text/plain', new OpenApiType(context: $context, type: 'string'));
}
}
}
Expand Down Expand Up @@ -566,7 +566,7 @@ public static function parse(string $context,
$parameters[] = $param;
}

if (!$allowMissingDocs && count($methodDescription) == 0) {
if (!$allowMissingDocs && count($methodDescription) === 0) {
Logger::error($context, 'Missing method description');
}

Expand All @@ -582,7 +582,7 @@ public static function parse(string $context,
$methodDescription[] = 'This endpoint allows CORS requests';
}

if (count($methodDescription) == 1) {
if (count($methodDescription) === 1) {
$methodSummary = $methodDescription[0];
$methodDescription = [];
} elseif (count($methodDescription) > 1) {
Expand Down
6 changes: 3 additions & 3 deletions src/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Helpers {
public const OPENAPI_ATTRIBUTE_CLASSNAME = 'OpenAPI';

public static function generateReadableAppID(string $appID): string {
return implode('', array_map(fn (string $s): string => ucfirst($s), explode('_', $appID)));
return implode('', array_map(ucfirst(...), explode('_', $appID)));
}

public static function securitySchemes(): array {
Expand Down Expand Up @@ -75,7 +75,7 @@ public static function splitOnUppercaseFollowedByNonUppercase(string $str): arra
}

public static function mergeSchemas(array $schemas): mixed {
if (!in_array(true, array_map(fn ($schema): bool => is_array($schema), $schemas))) {
if (!in_array(true, array_map(is_array(...), $schemas))) {
$results = array_values(array_unique($schemas));
if (count($results) > 1) {
throw new Exception('Incompatibles types: ' . implode(', ', $results));
Expand Down Expand Up @@ -271,7 +271,7 @@ public static function getOpenAPIAttributeTagsByScope(ClassMethod|Class_|Node $n
}

if ($foundTags !== []) {
$tags[$foundScopeName !== null && $foundScopeName !== '' && $foundScopeName !== '0' ? $foundScopeName : $defaultScope] = $foundTags;
$tags[in_array($foundScopeName, [null, '', '0'], true) ? $defaultScope : $foundScopeName] = $foundTags;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this one is better 🙈

}
}
}
Expand Down
25 changes: 11 additions & 14 deletions src/OpenApiType.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,14 @@ public function __construct(
}

public function toArray(bool $isParameter = false): array|stdClass {
if ($isParameter) {
if ($this->type === 'object' || $this->ref !== null || $this->anyOf !== null || $this->allOf !== null) {
Logger::warning($this->context, 'Complex types can not be part of query or URL parameters. Falling back to string due to undefined serialization!');

return (new OpenApiType(
context: $this->context,
type: 'string',
nullable: $this->nullable,
description: $this->description,
))->toArray($isParameter);
}
if ($isParameter && ($this->type === 'object' || $this->ref !== null || $this->anyOf !== null || $this->allOf !== null)) {
Logger::warning($this->context, 'Complex types can not be part of query or URL parameters. Falling back to string due to undefined serialization!');
return (new OpenApiType(
context: $this->context,
type: 'string',
nullable: $this->nullable,
description: $this->description,
))->toArray($isParameter);
}

$values = [];
Expand Down Expand Up @@ -173,7 +170,7 @@ public static function resolve(string $context, array $definitions, ParamTagValu
items: self::resolve($context . ': items', $definitions, $node->type),
);
}
if ($node instanceof GenericTypeNode && ($node->type->name === 'array' || $node->type->name === 'list' || $node->type->name === 'non-empty-list') && count($node->genericTypes) === 1) {
if ($node instanceof GenericTypeNode && (in_array($node->type->name, ['array', 'list', 'non-empty-list'], true)) && count($node->genericTypes) === 1) {
if ($node->type->name === 'array') {
Logger::error($context, "The 'array<TYPE>' syntax for arrays is forbidden due to ambiguities. Use 'list<TYPE>' for JSON arrays or 'array<string, TYPE>' for JSON objects instead.");
}
Expand Down Expand Up @@ -235,7 +232,7 @@ public static function resolve(string $context, array $definitions, ParamTagValu
Logger::panic($context, "JSON objects can only be indexed by '" . implode("', '", $allowedTypes) . "' but got '" . $node->genericTypes[0]->name . "'");
}

if ($node instanceof GenericTypeNode && $node->type->name === 'int' && count($node->genericTypes) == 2) {
if ($node instanceof GenericTypeNode && $node->type->name === 'int' && count($node->genericTypes) === 2) {
$min = null;
$max = null;
if ($node->genericTypes[0] instanceof ConstTypeNode) {
Expand Down Expand Up @@ -331,7 +328,7 @@ enum: $values,
$items = array_unique($items, SORT_REGULAR);
$items = self::mergeEnums($context, $items);

if (count($items) == 1) {
if (count($items) === 1) {
$type = $items[0];
if ($type->ref !== null) {
// https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-354037150
Expand Down
8 changes: 4 additions & 4 deletions src/ResponseType.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ public static function resolve(string $context, TypeNode $obj): array {
if ($className == 'void') {
$responses[] = null;
} else {
if (count(array_filter($responseTypes, fn ($responseType): bool => $responseType->className == $className)) == 0) {
if (count(array_filter($responseTypes, fn (\OpenAPIExtractor\ResponseType $responseType): bool => $responseType->className == $className)) === 0) {
Logger::error($context, "Invalid return type '" . $obj . "'");
return [];
}
foreach ($responseTypes as $responseType) {
if ($responseType->className == $className) {
// +2 for status code and headers which are always present
$expectedArgs = count(array_filter([$responseType->hasContentTypeTemplate, $responseType->hasTypeTemplate], fn ($value): bool => $value)) + 2;
if (count($args) != $expectedArgs) {
$expectedArgs = count(array_filter([$responseType->hasContentTypeTemplate, $responseType->hasTypeTemplate], fn (bool $value): bool => $value)) + 2;
if (count($args) !== $expectedArgs) {
Logger::error($context, "'" . $className . "' needs " . $expectedArgs . ' parameters');
continue;
}
Expand All @@ -223,7 +223,7 @@ public static function resolve(string $context, TypeNode $obj): array {
} elseif ($args[$i] instanceof IdentifierTypeNode && $args[$i]->name === 'string') {
$contentTypes = ['*/*'];
} elseif ($args[$i] instanceof UnionTypeNode) {
$contentTypes = array_map(fn ($arg) => $arg->constExpr->value, $args[$i]->types);
$contentTypes = array_map(fn (\PHPStan\PhpDocParser\Ast\Type\TypeNode $arg) => $arg->constExpr->value, $args[$i]->types);
} else {
Logger::panic($context, 'Unable to parse content type from ' . $args[$i]::class);
}
Expand Down