Skip to content

Commit 165524f

Browse files
committed
CLI-1745: fix: resolve pointers in requestBody and property schemas for API commands.
1 parent 064b748 commit 165524f

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

src/Command/Api/ApiBaseCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ private function castParamType(array $paramSpec, array|string|bool|int $value):
245245
if (in_array('integer', $types, true) && ctype_digit($value)) {
246246
return $this->doCastParamType('integer', $value);
247247
}
248-
} elseif ($paramSpec['type'] === 'array') {
248+
} elseif ($this->getParamType($paramSpec) === 'array') {
249249
if (is_array($value) && count($value) === 1) {
250250
return $this->castParamToArray($paramSpec, $value[0]);
251251
}

src/Command/Api/ApiCommandHelper.php

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,20 @@ private function addApiCommandParameters(array $schema, array $acquiaCloudSpec,
8686

8787
// Parameters to be used in the request body.
8888
if (array_key_exists('requestBody', $schema)) {
89+
// Resolve $ref in requestBody if present.
90+
if (array_key_exists('$ref', $schema['requestBody'])) {
91+
$parts = explode('/', $schema['requestBody']['$ref']);
92+
$paramKey = end($parts);
93+
$schema['requestBody'] = $acquiaCloudSpec['components']['requestBodies'][$paramKey];
94+
}
8995
[
9096
$bodyInputDefinition,
9197
$requestBodyParamUsageSuffix,
9298
] = $this->addApiCommandParametersForRequestBody($schema, $acquiaCloudSpec);
9399
$requestBodySchema = $this->getRequestBodyFromParameterSchema($schema, $acquiaCloudSpec);
94100
/** @var \Symfony\Component\Console\Input\InputOption|InputArgument $parameterDefinition */
95101
foreach ($bodyInputDefinition as $parameterDefinition) {
96-
$parameterSpecification = $this->getPropertySpecFromRequestBodyParam($requestBodySchema, $parameterDefinition);
102+
$parameterSpecification = $this->getPropertySpecFromRequestBodyParam($requestBodySchema, $parameterDefinition, $acquiaCloudSpec);
97103
$command->addPostParameter($parameterDefinition->getName(), $parameterSpecification);
98104
}
99105
$usage .= $requestBodyParamUsageSuffix;
@@ -125,6 +131,12 @@ private function addApiCommandParametersForRequestBody(array $schema, array $acq
125131
$requestBodySchema['properties'] = [];
126132
}
127133
foreach ($requestBodySchema['properties'] as $propKey => $paramDefinition) {
134+
// Resolve $ref inside individual property definitions.
135+
if (array_key_exists('$ref', $paramDefinition)) {
136+
$parts = explode('/', $paramDefinition['$ref']);
137+
$paramKey = end($parts);
138+
$paramDefinition = $this->getParameterSchemaFromSpec($paramKey, $acquiaCloudSpec);
139+
}
128140
$isRequired = array_key_exists('required', $requestBodySchema) && in_array($propKey, $requestBodySchema['required'], true);
129141
$propKey = self::renameParameter($propKey);
130142

@@ -168,9 +180,17 @@ private function addApiCommandParametersForRequestBody(array $schema, array $acq
168180
private function addPostArgumentUsageToExample(mixed $requestBody, mixed $propKey, mixed $paramDefinition, string $type, string $usage, array $acquiaCloudSpec): string
169181
{
170182
$requestBodyContent = $this->getRequestBodyContent($requestBody, $acquiaCloudSpec);
171-
183+
// Example may live directly on the content-type object (inline requestBody),
184+
// or nested inside schema (e.g. $ref-resolved requestBodies).
172185
if (array_key_exists('example', $requestBodyContent)) {
173186
$example = $requestBodyContent['example'];
187+
} elseif (array_key_exists('schema', $requestBodyContent) && array_key_exists('example', $requestBodyContent['schema'])) {
188+
$example = $requestBodyContent['schema']['example'];
189+
} else {
190+
return $usage;
191+
}
192+
193+
if ($example) {
174194
$prefix = $type === 'argument' ? '' : "--$propKey=";
175195
if (array_key_exists($propKey, $example)) {
176196
if (!array_key_exists('type', $paramDefinition)) {
@@ -482,10 +502,20 @@ private function getRequestBodyFromParameterSchema(array $schema, array $acquiaC
482502
return $requestBodySchema;
483503
}
484504

485-
private function getPropertySpecFromRequestBodyParam(array $requestBodySchema, mixed $parameterDefinition): mixed
505+
private function getPropertySpecFromRequestBodyParam(array $requestBodySchema, mixed $parameterDefinition, array $acquiaCloudSpec = []): mixed
486506
{
487507
$name = self::restoreRenamedParameter($parameterDefinition->getName());
488-
return $requestBodySchema['properties'][$name] ?? null;
508+
$spec = $requestBodySchema['properties'][$name] ?? [];
509+
510+
// Resolve $ref in the property spec so downstream code (e.g. castParamType) always
511+
// receives a fully resolved spec with a 'type' key rather than a bare $ref object.
512+
if (array_key_exists('$ref', $spec)) {
513+
$parts = explode('/', $spec['$ref']);
514+
$paramKey = end($parts);
515+
$spec = $this->getParameterSchemaFromSpec($paramKey, $acquiaCloudSpec);
516+
}
517+
518+
return $spec;
489519
}
490520

491521
/**

tests/phpunit/src/Commands/Api/ApiCommandTest.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,11 @@ public static function providerTestApiCommandDefinitionRequestBody(): array
550550
'post',
551551
'12-d314739e-296f-11e9-b210-d663bd873d93 --source="14-0c7e79ab-1c4a-424e-8446-76ae8be7e851"',
552552
],
553+
[
554+
'api:private-networks:create',
555+
'post',
556+
'api:private-networks:create "123e4567-e89b-12d3-a456-426614174000" "us-east-1" "customer-private-network" --description="Private network for customer" --label="anyLabel" --isolation="{"dedicated_compute":false,"dedicated_network":false}"" --ingress="{"drupal_ssh":{"ingress_acls":["test-acls"]}}"" "{"cidr":"114.7.55.1\/16","private_egress_access":{"drupal":true},"vpns":[{"name":"vpn1","gateway_ip":"10.10.10.10","routes":["127.0.0.1\/32","127.0.0.2\/32"],"tunnel1":{"shared_key":"sharedKey1","internal_cidr":"192.1.1.0\/24","ike_versions":"1","startup_action":"start","dpd_timeout_action":"stop"},"tunnel2":{"shared_key":"sharedKey2","internal_cidr":"192.1.1.0\/14","ike_versions":"1","startup_action":"start","dpd_timeout_action":"stop"}}],"vpc_peers":[{"name":"vpcPeer1","aws_account":"123456789012","vpc_id":"vpc-1234567890abcdef0","vpc_cidr":"120.24.16.1\/24"}]}""',
557+
],
553558
];
554559
}
555560

@@ -563,7 +568,15 @@ public function testApiCommandDefinitionRequestBody(string $commandName, string
563568
{
564569
$this->command = $this->getApiCommandByName($commandName);
565570
$resource = self::getResourceFromSpec($this->command->getPath(), $method);
566-
foreach ($resource['requestBody']['content']['application/hal+json']['example'] as $propKey => $value) {
571+
if (array_key_exists('$ref', $resource['requestBody'])) {
572+
$cloudApiSpec = self::getCloudApiSpec();
573+
$parts = explode('/', $resource['requestBody']['$ref']);
574+
$paramKey = end($parts);
575+
$resource['requestBody'] = $cloudApiSpec['components']['requestBodies'][$paramKey];
576+
}
577+
$example = $resource['requestBody']['content']['application/hal+json']['example'] ?? $resource['requestBody']['content']['application/json']['schema']['example'] ?? null;
578+
self::assertNotEmpty($example);
579+
foreach ($example as $propKey => $value) {
567580
$this->assertTrue(
568581
$this->command->getDefinition()
569582
->hasArgument($propKey) || $this->command->getDefinition()

0 commit comments

Comments
 (0)