Skip to content

Commit 7a346ac

Browse files
committed
feat(ControllerMethod): Parse request headers
Signed-off-by: provokateurin <kate@provokateurin.de>
1 parent bfb1ee2 commit 7a346ac

File tree

6 files changed

+203
-1
lines changed

6 files changed

+203
-1
lines changed

generate-spec.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,20 @@
838838

839839
$parameters[] = $parameter;
840840
}
841+
842+
foreach ($route->controllerMethod->requestHeaders as $requestHeader) {
843+
$parameters[] = [
844+
'name' => $requestHeader,
845+
'in' => 'header',
846+
// Not required, because getHeader() will return an empty string by default.
847+
// It might still mean that a header is always required, but the controller method has to check the
848+
// value manually anyway.
849+
'schema' => [
850+
'type' => 'string',
851+
],
852+
];
853+
}
854+
841855
if ($route->isOCS || !$route->isNoCSRFRequired) {
842856
$parameters[] = [
843857
'name' => 'OCS-APIRequest',

src/ControllerMethod.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
namespace OpenAPIExtractor;
99

10+
use PhpParser\Node\Expr\MethodCall;
11+
use PhpParser\Node\Expr\PropertyFetch;
12+
use PhpParser\Node\Expr\Variable;
1013
use PhpParser\Node\Stmt\ClassMethod;
1114
use PhpParser\Node\Stmt\Return_;
1215
use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode;
@@ -23,13 +26,15 @@ class ControllerMethod {
2326

2427
/**
2528
* @param ControllerMethodParameter[] $parameters
29+
* @param list<string> $requestHeaders
2630
* @param list<ControllerMethodResponse|null> $responses
2731
* @param OpenApiType[] $returns
2832
* @param array<int, string> $responseDescription
2933
* @param string[] $description
3034
*/
3135
public function __construct(
3236
public array $parameters,
37+
public array $requestHeaders,
3338
public array $responses,
3439
public array $responseDescription,
3540
public array $description,
@@ -274,7 +279,18 @@ public static function parse(string $context,
274279
Logger::warning($context, 'Summary ends with a punctuation mark');
275280
}
276281

277-
return new ControllerMethod($parameters, $responses, $responseDescriptions, $methodDescription, $methodSummary, $isDeprecated);
282+
$headers = [];
283+
foreach ($nodeFinder->findInstanceOf($method->getStmts(), MethodCall::class) as $methodCall) {
284+
if ($methodCall->var instanceof PropertyFetch &&
285+
$methodCall->var->var instanceof Variable &&
286+
$methodCall->var->var->name === 'this' &&
287+
$methodCall->var->name->name === 'request' &&
288+
$methodCall->name->name === 'getHeader') {
289+
$headers[] = Helpers::exprToValue($context . ': getHeader', $methodCall->args[0]->value);
290+
}
291+
}
292+
293+
return new ControllerMethod($parameters, array_unique($headers), $responses, $responseDescriptions, $methodDescription, $methodSummary, $isDeprecated);
278294
}
279295

280296
}

tests/appinfo/routes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
['name' => 'Settings#deprecatedRouteAndParameterGet', 'url' => '/api/{apiVersion}/deprecated-route-parameter-get', 'verb' => 'GET', 'requirements' => ['apiVersion' => '(v2)']],
8686
['name' => 'Settings#samePathGet', 'url' => '/api/{apiVersion}/same-path', 'verb' => 'GET', 'requirements' => ['apiVersion' => '(v2)']],
8787
['name' => 'Settings#samePathPost', 'url' => '/api/{apiVersion}/same-path', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
88+
['name' => 'Settings#requestHeader', 'url' => '/api/{apiVersion}/request-header', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
8889
['name' => 'V1\SubDir#subDirRoute', 'url' => '/sub-dir', 'verb' => 'GET'],
8990
],
9091
];

tests/lib/Controller/SettingsController.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,4 +739,17 @@ public function samePathGet(): DataResponse {
739739
public function samePathPost(): DataResponse {
740740
return new DataResponse();
741741
}
742+
743+
/**
744+
* A method with a request header.
745+
*
746+
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
747+
*
748+
* 200: Admin settings updated
749+
*/
750+
public function requestHeader(): DataResponse {
751+
$value = $this->request->getHeader('X-Custom-Header');
752+
753+
return new DataResponse();
754+
}
742755
}

tests/openapi-administration.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5352,6 +5352,85 @@
53525352
}
53535353
}
53545354
},
5355+
"/ocs/v2.php/apps/notifications/api/{apiVersion}/request-header": {
5356+
"post": {
5357+
"operationId": "settings-request-header",
5358+
"summary": "A method with a request header.",
5359+
"description": "This endpoint requires admin access",
5360+
"tags": [
5361+
"settings"
5362+
],
5363+
"security": [
5364+
{
5365+
"bearer_auth": []
5366+
},
5367+
{
5368+
"basic_auth": []
5369+
}
5370+
],
5371+
"parameters": [
5372+
{
5373+
"name": "apiVersion",
5374+
"in": "path",
5375+
"required": true,
5376+
"schema": {
5377+
"type": "string",
5378+
"enum": [
5379+
"v2"
5380+
],
5381+
"default": "v2"
5382+
}
5383+
},
5384+
{
5385+
"name": "X-Custom-Header",
5386+
"in": "header",
5387+
"schema": {
5388+
"type": "string"
5389+
}
5390+
},
5391+
{
5392+
"name": "OCS-APIRequest",
5393+
"in": "header",
5394+
"description": "Required to be true for the API request to pass",
5395+
"required": true,
5396+
"schema": {
5397+
"type": "boolean",
5398+
"default": true
5399+
}
5400+
}
5401+
],
5402+
"responses": {
5403+
"200": {
5404+
"description": "Admin settings updated",
5405+
"content": {
5406+
"application/json": {
5407+
"schema": {
5408+
"type": "object",
5409+
"required": [
5410+
"ocs"
5411+
],
5412+
"properties": {
5413+
"ocs": {
5414+
"type": "object",
5415+
"required": [
5416+
"meta",
5417+
"data"
5418+
],
5419+
"properties": {
5420+
"meta": {
5421+
"$ref": "#/components/schemas/OCSMeta"
5422+
},
5423+
"data": {}
5424+
}
5425+
}
5426+
}
5427+
}
5428+
}
5429+
}
5430+
}
5431+
}
5432+
}
5433+
},
53555434
"/ocs/v2.php/tests/attribute-ocs/{param}": {
53565435
"get": {
53575436
"operationId": "routing-attributeocs-route",

tests/openapi-full.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5509,6 +5509,85 @@
55095509
}
55105510
}
55115511
},
5512+
"/ocs/v2.php/apps/notifications/api/{apiVersion}/request-header": {
5513+
"post": {
5514+
"operationId": "settings-request-header",
5515+
"summary": "A method with a request header.",
5516+
"description": "This endpoint requires admin access",
5517+
"tags": [
5518+
"settings"
5519+
],
5520+
"security": [
5521+
{
5522+
"bearer_auth": []
5523+
},
5524+
{
5525+
"basic_auth": []
5526+
}
5527+
],
5528+
"parameters": [
5529+
{
5530+
"name": "apiVersion",
5531+
"in": "path",
5532+
"required": true,
5533+
"schema": {
5534+
"type": "string",
5535+
"enum": [
5536+
"v2"
5537+
],
5538+
"default": "v2"
5539+
}
5540+
},
5541+
{
5542+
"name": "X-Custom-Header",
5543+
"in": "header",
5544+
"schema": {
5545+
"type": "string"
5546+
}
5547+
},
5548+
{
5549+
"name": "OCS-APIRequest",
5550+
"in": "header",
5551+
"description": "Required to be true for the API request to pass",
5552+
"required": true,
5553+
"schema": {
5554+
"type": "boolean",
5555+
"default": true
5556+
}
5557+
}
5558+
],
5559+
"responses": {
5560+
"200": {
5561+
"description": "Admin settings updated",
5562+
"content": {
5563+
"application/json": {
5564+
"schema": {
5565+
"type": "object",
5566+
"required": [
5567+
"ocs"
5568+
],
5569+
"properties": {
5570+
"ocs": {
5571+
"type": "object",
5572+
"required": [
5573+
"meta",
5574+
"data"
5575+
],
5576+
"properties": {
5577+
"meta": {
5578+
"$ref": "#/components/schemas/OCSMeta"
5579+
},
5580+
"data": {}
5581+
}
5582+
}
5583+
}
5584+
}
5585+
}
5586+
}
5587+
}
5588+
}
5589+
}
5590+
},
55125591
"/ocs/v2.php/tests/attribute-ocs/{param}": {
55135592
"get": {
55145593
"operationId": "routing-attributeocs-route",

0 commit comments

Comments
 (0)