Skip to content

Commit 10cbca7

Browse files
TD-076: Command normalizer accepts non-string result payloads (#591)
1 parent 13402e2 commit 10cbca7

2 files changed

Lines changed: 65 additions & 4 deletions

File tree

src/V2/Support/WorkflowCommandNormalizer.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ private static function resolveCommandArgumentsWithCodec(array $command, int $in
565565
/**
566566
* @param array<string, mixed> $command
567567
* @param array<string, list<string>> $errors
568-
* @return array{payload: mixed, codec: string|null}
568+
* @return array{payload: string|null, codec: string|null}
569569
*/
570570
private static function resolveCommandPayloadWithCodec(
571571
array $command,
@@ -589,10 +589,31 @@ private static function resolveCommandPayloadWithCodec(
589589

590590
if (is_array($command[$field])) {
591591
try {
592-
return PayloadEnvelopeResolver::resolveCommandPayloadWithCodec(
592+
$resolved = PayloadEnvelopeResolver::resolveCommandPayloadWithCodec(
593593
$command[$field],
594594
"commands.{$index}.{$field}",
595595
);
596+
597+
$payload = $resolved['payload'];
598+
599+
if ($payload === null || is_string($payload)) {
600+
return [
601+
'payload' => $payload,
602+
'codec' => $resolved['codec'],
603+
];
604+
}
605+
606+
$errors["commands.{$index}.{$field}"] = [
607+
sprintf(
608+
'Workflow task command field [%s] must be a string or a payload envelope when provided.',
609+
$field,
610+
),
611+
];
612+
613+
return [
614+
'payload' => null,
615+
'codec' => null,
616+
];
596617
} catch (ValidationException $e) {
597618
foreach ($e->errors() as $errorField => $messages) {
598619
$errors[$errorField] = $messages;
@@ -605,15 +626,22 @@ private static function resolveCommandPayloadWithCodec(
605626
}
606627
}
607628

629+
$errors["commands.{$index}.{$field}"] = [
630+
sprintf(
631+
'Workflow task command field [%s] must be a string or a payload envelope when provided.',
632+
$field,
633+
),
634+
];
635+
608636
return [
609-
'payload' => $command[$field],
637+
'payload' => null,
610638
'codec' => null,
611639
];
612640
}
613641

614642
/**
615643
* @param array<string, mixed> $command
616-
* @param array{payload: mixed, codec: string|null} $resolved
644+
* @param array{payload: string|null, codec: string|null} $resolved
617645
* @param array<string, list<string>> $errors
618646
*/
619647
private static function payloadCodecForResolvedPayload(

tests/Unit/V2/WorkflowCommandNormalizerTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ public function testCompleteWorkflowAcceptsRawStringResult(): void
4343
]], $out);
4444
}
4545

46+
public function testCompleteWorkflowRejectsNonStringResultPayload(): void
47+
{
48+
$errors = $this->normalizeAndCaptureErrors([
49+
[
50+
'type' => 'complete_workflow',
51+
'result' => ['ok' => true],
52+
],
53+
]);
54+
55+
$this->assertArrayHasKey('commands.0.result', $errors);
56+
$this->assertStringContainsString(
57+
'must be a string or a payload envelope',
58+
$errors['commands.0.result'][0],
59+
);
60+
}
61+
4662
public function testCompleteWorkflowUnwrapsEnvelope(): void
4763
{
4864
$out = WorkflowCommandNormalizer::normalize([
@@ -452,6 +468,23 @@ public function testCompleteUpdateRequiresUpdateId(): void
452468
]);
453469
}
454470

471+
public function testCompleteUpdateRejectsNonStringResultPayload(): void
472+
{
473+
$errors = $this->normalizeAndCaptureErrors([
474+
[
475+
'type' => 'complete_update',
476+
'update_id' => '01UPDATE000000000000000001',
477+
'result' => 42,
478+
],
479+
]);
480+
481+
$this->assertArrayHasKey('commands.0.result', $errors);
482+
$this->assertStringContainsString(
483+
'must be a string or a payload envelope',
484+
$errors['commands.0.result'][0],
485+
);
486+
}
487+
455488
public function testFailUpdatePreservesOptionalFields(): void
456489
{
457490
$out = WorkflowCommandNormalizer::normalize([

0 commit comments

Comments
 (0)