Skip to content

Commit

Permalink
Do not inject InvalidArgument class when not needed (#1608)
Browse files Browse the repository at this point in the history
  • Loading branch information
jderusse authored Nov 23, 2023
1 parent 299375f commit d0aa3b9
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 47 deletions.
35 changes: 23 additions & 12 deletions src/Generator/InputGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ public function generate(Operation $operation): ClassName
$classBuilder->addUse(StreamFactory::class);
$this->inputClassRequestGetters($shape, $classBuilder, $operation);

$classBuilder->addUse(InvalidArgument::class);
$this->addUse($shape, $classBuilder);

$classBuilder->addExtend(Input::class);
Expand All @@ -305,12 +304,14 @@ public function generate(Operation $operation): ClassName
return $className;
}

private function inputClassRequestPartGettersEnumGenerator(Member $member, string $requestPart, string $input): string
private function inputClassRequestPartGettersEnumGenerator(Member $member, ClassBuilder $classBuilder, string $requestPart, string $input): string
{
$memberShape = $member->getShape();
$validateEnum = '';
if (!empty($memberShape->getEnum())) {
$enumClassName = $this->namespaceRegistry->getEnum($memberShape);
$classBuilder->addUse(InvalidArgument::class);

$validateEnum = strtr('if (!ENUM_CLASS::exists(VALUE)) {
throw new InvalidArgument(sprintf(\'Invalid parameter "MEMBER_NAME" for "%s". The value "%s" is not a valid "ENUM_CLASS".\', __CLASS__, INPUT));
}', [
Expand Down Expand Up @@ -343,7 +344,7 @@ private function inputClassRequestPartGettersHookGenerator(StructureMember $memb
]);
}

private function inputClassRequestPartGetters(StructureMember $member, Operation $operation, string $requestPart, string $input, string $output): string
private function inputClassRequestPartGetters(StructureMember $member, ClassBuilder $classBuilder, Operation $operation, string $requestPart, string $input, string $output): string
{
$memberShape = $member->getShape();
if ($memberShape instanceof ListShape) {
Expand All @@ -365,7 +366,7 @@ private function inputClassRequestPartGetters(StructureMember $member, Operation
'INPUT' => $input,
'OUTPUT' => $output,
'VALUE' => $this->stringify('$value', $memberShape->getMember(), $requestPart),
'VALIDATE_ENUM' => $this->inputClassRequestPartGettersEnumGenerator($memberShape->getMember(), $requestPart, '$value'),
'VALIDATE_ENUM' => $this->inputClassRequestPartGettersEnumGenerator($memberShape->getMember(), $classBuilder, $requestPart, '$value'),
'APPLY_HOOK' => $this->inputClassRequestPartGettersHookGenerator($member, $operation, $requestPart, $input),
]);
}
Expand All @@ -376,7 +377,7 @@ private function inputClassRequestPartGetters(StructureMember $member, Operation
OUTPUT = VALUE;';

return strtr($bodyCode, [
'VALIDATE_ENUM' => $this->inputClassRequestPartGettersEnumGenerator($member, $requestPart, $input),
'VALIDATE_ENUM' => $this->inputClassRequestPartGettersEnumGenerator($member, $classBuilder, $requestPart, $input),
'APPLY_HOOK' => $this->inputClassRequestPartGettersHookGenerator($member, $operation, $requestPart, $input),
'OUTPUT' => $output,
'VALUE' => $this->stringify($input, $member, $requestPart),
Expand Down Expand Up @@ -414,6 +415,7 @@ private function inputClassRequestGetters(StructureShape $inputShape, ClassBuild
}

if ($member->isRequired()) {
$classBuilder->addUse(InvalidArgument::class);
$bodyCode = 'if (null === $v = $this->PROPERTY) {
throw new InvalidArgument(sprintf(\'Missing parameter "MEMBER_NAME" for "%s". The value cannot be null.\', __CLASS__));
}
Expand All @@ -429,7 +431,7 @@ private function inputClassRequestGetters(StructureShape $inputShape, ClassBuild
}

$bodyCode = strtr(strtr($bodyCode, [
'GETTER_CODE' => $this->inputClassRequestPartGetters($member, $operation, $requestPart, $input, $output),
'GETTER_CODE' => $this->inputClassRequestPartGetters($member, $classBuilder, $operation, $requestPart, $input, $output),
]), [
'MEMBER_NAME' => $member->getName(),
'VAR_NAME' => $varName,
Expand Down Expand Up @@ -478,14 +480,23 @@ private function inputClassRequestGetters(StructureShape $inputShape, ClassBuild
}

if ($operation->hasBody()) {
[$body['body'], $hasRequestBody, $overrideArgs] = $serializer->generateRequestBody($operation, $inputShape) + [null, null, []];
if ($hasRequestBody) {
[$returnType, $requestBody, $args] = $serializer->generateRequestBuilder($inputShape, true) + [null, null, []];
if ('' === trim($requestBody)) {
$serializerBodyResult = $serializer->generateRequestBody($operation, $inputShape);
$body['body'] = $serializerBodyResult->getBody();
foreach ($serializerBodyResult->getUsedClasses() as $classNameFqdn) {
$classBuilder->addUse($classNameFqdn);
}

if ($serializerBodyResult->hasRequestBody()) {
$serializerBuilderResult = $serializer->generateRequestBuilder($inputShape, true);
foreach ($serializerBuilderResult->getUsedClasses() as $classNameFqdn) {
$classBuilder->addUse($classNameFqdn);
}

if ('' === trim($serializerBuilderResult->getBody())) {
$body['body'] = '$body = "";';
} else {
$method = $classBuilder->addMethod('requestBody')->setReturnType($returnType)->setBody($requestBody)->setPrivate();
foreach ($overrideArgs + $args as $arg => $type) {
$method = $classBuilder->addMethod('requestBody')->setReturnType($serializerBuilderResult->getReturnType())->setBody($serializerBuilderResult->getBody())->setPrivate();
foreach ($serializerBodyResult->getExtraMethodArgs() + $serializerBuilderResult->getExtraMethodArgs() as $arg => $type) {
$method->addParameter($arg)->setType($type);
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/Generator/ObjectGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,17 @@ public function generate(StructureShape $shape, bool $forEndpoint = false): Clas

$serializer = $this->serializer->get($shape->getService());
if ($this->isShapeUsedInput($shape)) {
[$returnType, $requestBody, $args] = $serializer->generateRequestBuilder($shape, false) + [null, null, []];
$method = $classBuilder->addMethod('requestBody')->setReturnType($returnType)->setBody($requestBody)->setPublic()->setComment('@internal');
foreach ($args as $arg => $type) {
$serializerBuilderResult = $serializer->generateRequestBuilder($shape, false);
foreach ($serializerBuilderResult->getUsedClasses() as $classNameFqdn) {
$classBuilder->addUse($classNameFqdn);
}

$method = $classBuilder->addMethod('requestBody')->setReturnType($serializerBuilderResult->getReturnType())->setBody($serializerBuilderResult->getBody())->setPublic()->setComment('@internal');
foreach ($serializerBuilderResult->getExtraMethodArgs() as $arg => $type) {
$method->addParameter($arg)->setType($type);
}
}

$classBuilder->addUse(InvalidArgument::class);

return $className;
}

Expand Down
29 changes: 19 additions & 10 deletions src/Generator/RequestSerializer/QuerySerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use AsyncAws\CodeGenerator\Generator\Composer\RequirementsRegistry;
use AsyncAws\CodeGenerator\Generator\GeneratorHelper;
use AsyncAws\CodeGenerator\Generator\Naming\NamespaceRegistry;
use AsyncAws\Core\Exception\InvalidArgument;

/**
* Serialize a request body to a flattened array with "." as separator.
Expand All @@ -24,6 +25,8 @@
*/
class QuerySerializer implements Serializer
{
use UseClassesTrait;

/**
* @var NamespaceRegistry
*/
Expand All @@ -45,10 +48,12 @@ public function getHeaders(Operation $operation): string
return '["content-type" => "application/x-www-form-urlencoded"]';
}

public function generateRequestBody(Operation $operation, StructureShape $shape): array
public function generateRequestBody(Operation $operation, StructureShape $shape): SerializerResultBody
{
$this->usedClassesInit();
if (null !== $payloadProperty = $shape->getPayload()) {
if ($shape->getMember($payloadProperty)->isRequired()) {
$this->usedClassesAdd(InvalidArgument::class);
$body = 'if (null === $v = $this->PROPERTY) {
throw new InvalidArgument(sprintf(\'Missing parameter "NAME" for "%s". The value cannot be null.\', __CLASS__));
}
Expand All @@ -57,20 +62,21 @@ public function generateRequestBody(Operation $operation, StructureShape $shape)
$body = '$body = $this->PROPERTY ?? "";';
}

return [strtr($body, [
return new SerializerResultBody(strtr($body, [
'PROPERTY' => GeneratorHelper::normalizeName($payloadProperty),
'NAME' => $payloadProperty,
]), false];
]), false, $this->usedClassesFlush());
}

return [strtr('$body = http_build_query([\'Action\' => OPERATION_NAME, \'Version\' => API_VERSION] + $this->requestBody(), \'\', \'&\', \PHP_QUERY_RFC1738);', [
return new SerializerResultBody(strtr('$body = http_build_query([\'Action\' => OPERATION_NAME, \'Version\' => API_VERSION] + $this->requestBody(), \'\', \'&\', \PHP_QUERY_RFC1738);', [
'OPERATION_NAME' => var_export($operation->getName(), true),
'API_VERSION' => var_export($operation->getApiVersion(), true),
]), true];
]), true, $this->usedClassesFlush());
}

public function generateRequestBuilder(StructureShape $shape, bool $needsChecks): array
public function generateRequestBuilder(StructureShape $shape, bool $needsChecks): SerializerResultBuilder
{
$this->usedClassesInit();
$body = implode("\n", array_map(function (StructureMember $member) use ($needsChecks) {
if (null !== $member->getLocation()) {
return '';
Expand All @@ -85,6 +91,7 @@ public function generateRequestBuilder(StructureShape $shape, bool $needsChecks)
$inputElement = '$v';
} elseif ($member->isRequired()) {
if ($needsChecks) {
$this->usedClassesAdd(InvalidArgument::class);
$body = 'if (null === $v = $this->PROPERTY) {
throw new InvalidArgument(sprintf(\'Missing parameter "NAME" for "%s". The value cannot be null.\', __CLASS__));
}
Expand Down Expand Up @@ -113,14 +120,14 @@ public function generateRequestBuilder(StructureShape $shape, bool $needsChecks)
]);
}, $shape->getMembers()));

return ['array', strtr('
return new SerializerResultBuilder('array', strtr('
$payload = [];
CHILDREN_CODE
return $payload;
', [
'CHILDREN_CODE' => $body,
])];
]), $this->usedClassesFlush());
}

private function getQueryName(Member $member, string $default): string
Expand Down Expand Up @@ -206,6 +213,7 @@ private function dumpArrayMap(string $output, string $input, string $contextProp
$mapKeyShape = $shape->getKey()->getShape();
if (!empty($mapKeyShape->getEnum())) {
$enumClassName = $this->namespaceRegistry->getEnum($mapKeyShape);
$this->usedClassesAdd(InvalidArgument::class);
$validateEnum = strtr('if (!ENUM_CLASS::exists($mapKey)) {
throw new InvalidArgument(sprintf(\'Invalid key for "%s". The value "%s" is not a valid "ENUM_CLASS".\', __CLASS__, $mapKey));
}', [
Expand All @@ -228,7 +236,7 @@ private function dumpArrayMap(string $output, string $input, string $contextProp
'INPUT' => $input,
'VALIDATE_ENUM' => $validateEnum,
'OUTPUT_KEY' => sprintf('%s.$index.%s', $output, $this->getQueryName($shape->getKey(), 'key')),
'MEMBER_CODE' => $memberCode = $this->dumpArrayElement(sprintf('%s.$index.%s', $output, $this->getQueryName($shape->getValue(), 'value')), '$mapValue', $contextProperty, $shape->getValue()->getShape()),
'MEMBER_CODE' => $this->dumpArrayElement(sprintf('%s.$index.%s', $output, $this->getQueryName($shape->getValue(), 'value')), '$mapValue', $contextProperty, $shape->getValue()->getShape()),
]);
}

Expand All @@ -245,7 +253,7 @@ private function dumpArrayList(string $output, string $input, string $contextPro
',
[
'INPUT' => $input,
'MEMBER_CODE' => $memberCode = $this->dumpArrayElement(sprintf('%s.$index', $output), '$mapValue', $contextProperty, $memberShape),
'MEMBER_CODE' => $this->dumpArrayElement(sprintf('%s.$index', $output), '$mapValue', $contextProperty, $memberShape),
]);
}

Expand All @@ -258,6 +266,7 @@ private function dumpArrayScalar(string $output, string $input, string $contextP
];
if (!empty($shape->getEnum())) {
$enumClassName = $this->namespaceRegistry->getEnum($shape);
$this->usedClassesAdd(InvalidArgument::class);
$body = 'if (!ENUM_CLASS::exists(INPUT)) {
throw new InvalidArgument(sprintf(\'Invalid parameter "PROPERTY" for "%s". The value "%s" is not a valid "ENUM_CLASS".\', __CLASS__, INPUT));
}
Expand Down
23 changes: 16 additions & 7 deletions src/Generator/RequestSerializer/RestJsonSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use AsyncAws\CodeGenerator\Generator\Composer\RequirementsRegistry;
use AsyncAws\CodeGenerator\Generator\GeneratorHelper;
use AsyncAws\CodeGenerator\Generator\Naming\NamespaceRegistry;
use AsyncAws\Core\Exception\InvalidArgument;

/**
* Serialize a request body to a nice nested array.
Expand All @@ -24,6 +25,8 @@
*/
class RestJsonSerializer implements Serializer
{
use UseClassesTrait;

/**
* @var NamespaceRegistry
*/
Expand All @@ -45,10 +48,12 @@ public function getHeaders(Operation $operation): string
return '["content-type" => "application/json"]';
}

public function generateRequestBody(Operation $operation, StructureShape $shape): array
public function generateRequestBody(Operation $operation, StructureShape $shape): SerializerResultBody
{
$this->usedClassesInit();
if (null !== $payloadProperty = $shape->getPayload()) {
if ($shape->getMember($payloadProperty)->isRequired()) {
$this->usedClassesAdd(InvalidArgument::class);
$body = 'if (null === $v = $this->PROPERTY) {
throw new InvalidArgument(sprintf(\'Missing parameter "NAME" for "%s". The value cannot be null.\', __CLASS__));
}
Expand All @@ -57,19 +62,20 @@ public function generateRequestBody(Operation $operation, StructureShape $shape)
$body = '$body = $this->PROPERTY ?? "";';
}

return [strtr($body, [
return new SerializerResultBody(strtr($body, [
'PROPERTY' => GeneratorHelper::normalizeName($payloadProperty),
'NAME' => $payloadProperty,
]), false];
]), false, $this->usedClassesFlush());
}

$this->requirementsRegistry->addRequirement('ext-json');

return ['$bodyPayload = $this->requestBody(); $body = empty($bodyPayload) ? "{}" : \json_encode($bodyPayload, ' . \JSON_THROW_ON_ERROR . ');', true];
return new SerializerResultBody('$bodyPayload = $this->requestBody(); $body = empty($bodyPayload) ? "{}" : \json_encode($bodyPayload, ' . \JSON_THROW_ON_ERROR . ');', true, $this->usedClassesFlush());
}

public function generateRequestBuilder(StructureShape $shape, bool $needsChecks): array
public function generateRequestBuilder(StructureShape $shape, bool $needsChecks): SerializerResultBuilder
{
$this->usedClassesInit();
$body = implode("\n", array_map(function (StructureMember $member) use ($needsChecks) {
if (null !== $member->getLocation()) {
return '';
Expand All @@ -84,6 +90,7 @@ public function generateRequestBuilder(StructureShape $shape, bool $needsChecks)
$inputElement = '$v';
} elseif ($member->isRequired()) {
if ($needsChecks) {
$this->usedClassesAdd(InvalidArgument::class);
$body = 'if (null === $v = $this->PROPERTY) {
throw new InvalidArgument(sprintf(\'Missing parameter "NAME" for "%s". The value cannot be null.\', __CLASS__));
}
Expand Down Expand Up @@ -112,14 +119,14 @@ public function generateRequestBuilder(StructureShape $shape, bool $needsChecks)
]);
}, $shape->getMembers()));

return ['array', strtr('
return new SerializerResultBuilder('array', strtr('
$payload = [];
CHILDREN_CODE
return $payload;
', [
'CHILDREN_CODE' => $body,
])];
]), $this->usedClassesFlush());
}

protected function dumpArrayBoolean(string $output, string $input, Shape $shape): string
Expand Down Expand Up @@ -227,6 +234,7 @@ private function dumpArrayMap(string $output, string $input, string $contextProp
$mapKeyShape = $shape->getKey()->getShape();
if (!empty($mapKeyShape->getEnum())) {
$enumClassName = $this->namespaceRegistry->getEnum($mapKeyShape);
$this->usedClassesAdd(InvalidArgument::class);
$validateEnum = strtr('if (!ENUM_CLASS::exists($name)) {
throw new InvalidArgument(sprintf(\'Invalid key for "%s". The value "%s" is not a valid "ENUM_CLASS".\', __CLASS__, $name));
}', [
Expand Down Expand Up @@ -265,6 +273,7 @@ private function dumpArrayScalar(string $output, string $input, string $contextP
];
if (!empty($shape->getEnum())) {
$enumClassName = $this->namespaceRegistry->getEnum($shape);
$this->usedClassesAdd(InvalidArgument::class);
$body = 'if (!ENUM_CLASS::exists(INPUT)) {
throw new InvalidArgument(sprintf(\'Invalid parameter "PROPERTY" for "%s". The value "%s" is not a valid "ENUM_CLASS".\', __CLASS__, INPUT));
}
Expand Down
Loading

0 comments on commit d0aa3b9

Please sign in to comment.