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
14 changes: 14 additions & 0 deletions generate-spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,20 @@

$parameters[] = $parameter;
}

foreach ($route->controllerMethod->requestHeaders as $requestHeader) {
$parameters[] = [
'name' => $requestHeader,
'in' => 'header',
// Not required, because getHeader() will return an empty string by default.
// It might still mean that a header is always required, but the controller method has to check the
// value manually anyway.
'schema' => [
'type' => 'string',
],
];
}

if ($route->isOCS || !$route->isNoCSRFRequired) {
$parameters[] = [
'name' => 'OCS-APIRequest',
Expand Down
18 changes: 17 additions & 1 deletion src/ControllerMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

namespace OpenAPIExtractor;

use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode;
Expand All @@ -23,13 +26,15 @@ class ControllerMethod {

/**
* @param ControllerMethodParameter[] $parameters
* @param list<string> $requestHeaders
* @param list<ControllerMethodResponse|null> $responses
* @param OpenApiType[] $returns
* @param array<int, string> $responseDescription
* @param string[] $description
*/
public function __construct(
public array $parameters,
public array $requestHeaders,
public array $responses,
public array $responseDescription,
public array $description,
Expand Down Expand Up @@ -274,7 +279,18 @@ public static function parse(string $context,
Logger::warning($context, 'Summary ends with a punctuation mark');
}

return new ControllerMethod($parameters, $responses, $responseDescriptions, $methodDescription, $methodSummary, $isDeprecated);
$headers = [];
foreach ($nodeFinder->findInstanceOf($method->getStmts(), MethodCall::class) as $methodCall) {
if ($methodCall->var instanceof PropertyFetch &&
$methodCall->var->var instanceof Variable &&
$methodCall->var->var->name === 'this' &&
$methodCall->var->name->name === 'request' &&
$methodCall->name->name === 'getHeader') {
$headers[] = Helpers::exprToValue($context . ': getHeader', $methodCall->args[0]->value);
}
}

return new ControllerMethod($parameters, array_unique($headers), $responses, $responseDescriptions, $methodDescription, $methodSummary, $isDeprecated);
}

}
1 change: 1 addition & 0 deletions tests/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
['name' => 'Settings#deprecatedRouteAndParameterGet', 'url' => '/api/{apiVersion}/deprecated-route-parameter-get', 'verb' => 'GET', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#samePathGet', 'url' => '/api/{apiVersion}/same-path', 'verb' => 'GET', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#samePathPost', 'url' => '/api/{apiVersion}/same-path', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#requestHeader', 'url' => '/api/{apiVersion}/request-header', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'V1\SubDir#subDirRoute', 'url' => '/sub-dir', 'verb' => 'GET'],
],
];
13 changes: 13 additions & 0 deletions tests/lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -739,4 +739,17 @@ public function samePathGet(): DataResponse {
public function samePathPost(): DataResponse {
return new DataResponse();
}

/**
* A method with a request header.
*
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
*
* 200: Admin settings updated
*/
public function requestHeader(): DataResponse {
$value = $this->request->getHeader('X-Custom-Header');

return new DataResponse();
}
}
79 changes: 79 additions & 0 deletions tests/openapi-administration.json
Original file line number Diff line number Diff line change
Expand Up @@ -5352,6 +5352,85 @@
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/request-header": {
"post": {
"operationId": "settings-request-header",
"summary": "A method with a request header.",
"description": "This endpoint requires admin access",
"tags": [
"settings"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v2"
],
"default": "v2"
}
},
{
"name": "X-Custom-Header",
"in": "header",
"schema": {
"type": "string"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Admin settings updated",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/tests/attribute-ocs/{param}": {
"get": {
"operationId": "routing-attributeocs-route",
Expand Down
79 changes: 79 additions & 0 deletions tests/openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -5509,6 +5509,85 @@
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/request-header": {
"post": {
"operationId": "settings-request-header",
"summary": "A method with a request header.",
"description": "This endpoint requires admin access",
"tags": [
"settings"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v2"
],
"default": "v2"
}
},
{
"name": "X-Custom-Header",
"in": "header",
"schema": {
"type": "string"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Admin settings updated",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/tests/attribute-ocs/{param}": {
"get": {
"operationId": "routing-attributeocs-route",
Expand Down
Loading