diff --git a/generate-spec.php b/generate-spec.php index 6136148..1408b8c 100755 --- a/generate-spec.php +++ b/generate-spec.php @@ -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; } @@ -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!'); @@ -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; @@ -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; } @@ -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); @@ -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'); @@ -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 { @@ -946,7 +946,7 @@ ]; } -if (count($schemas) == 0 && count($routes) == 0) { +if (count($schemas) === 0 && count($routes) === 0) { Logger::error('app', 'No spec generated'); } @@ -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); } @@ -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; diff --git a/rector.php b/rector.php index e590488..304c23f 100644 --- a/rector.php +++ b/rector.php @@ -17,5 +17,4 @@ deadCode: true, codeQuality: true, typeDeclarations: true, - strictBooleans: true, ); diff --git a/src/ControllerMethod.php b/src/ControllerMethod.php index c9c45e3..8a7789f 100644 --- a/src/ControllerMethod.php +++ b/src/ControllerMethod.php @@ -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')); } } } @@ -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'); } @@ -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) { diff --git a/src/Helpers.php b/src/Helpers.php index 4782d11..2b09fc7 100644 --- a/src/Helpers.php +++ b/src/Helpers.php @@ -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 { @@ -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)); @@ -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; } } } diff --git a/src/OpenApiType.php b/src/OpenApiType.php index 6de07d9..6caeda1 100644 --- a/src/OpenApiType.php +++ b/src/OpenApiType.php @@ -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 = []; @@ -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' syntax for arrays is forbidden due to ambiguities. Use 'list' for JSON arrays or 'array' for JSON objects instead."); } @@ -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) { @@ -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 diff --git a/src/ResponseType.php b/src/ResponseType.php index fbe6793..da9da47 100644 --- a/src/ResponseType.php +++ b/src/ResponseType.php @@ -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; } @@ -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); }