Skip to content

Commit a350b57

Browse files
committed
feat: improves fromJson validation and documenting
1 parent 03f66ff commit a350b57

File tree

17 files changed

+93
-26
lines changed

17 files changed

+93
-26
lines changed

src/Files/DTO/File.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,16 +406,26 @@ public function jsonSerialize(): array
406406
* {@inheritDoc}
407407
*
408408
* @since n.e.x.t
409+
*
410+
* @param array{fileType: string, url?: string, mimeType?: string, base64Data?: string} $json The JSON data.
409411
*/
410412
public static function fromJson(array $json): File
411413
{
412414
$fileType = FileTypeEnum::from((string) $json['fileType']);
413415

414416
if ($fileType->isRemote()) {
417+
if (!isset($json['url']) || !isset($json['mimeType'])) {
418+
throw new \InvalidArgumentException('Remote file requires url and mimeType.');
419+
}
415420
return new self((string) $json['url'], (string) $json['mimeType']);
416421
} else {
422+
if (!isset($json['mimeType']) || !isset($json['base64Data'])) {
423+
throw new \InvalidArgumentException('Inline file requires mimeType and base64Data.');
424+
}
417425
// Create data URI from base64 data and mime type
418-
$dataUri = sprintf('data:%s;base64,%s', (string) $json['mimeType'], (string) $json['base64Data']);
426+
$mimeType = (string) $json['mimeType'];
427+
$base64Data = (string) $json['base64Data'];
428+
$dataUri = sprintf('data:%s;base64,%s', $mimeType, $base64Data);
419429
return new self($dataUri);
420430
}
421431
}

src/Messages/DTO/Message.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,13 @@ public function jsonSerialize(): array
113113
* {@inheritDoc}
114114
*
115115
* @since n.e.x.t
116+
*
117+
* @param array{role: string, parts: array<array<string, mixed>>} $json The JSON data.
116118
*/
117119
public static function fromJson(array $json): Message
118120
{
119121
$role = MessageRoleEnum::from((string) $json['role']);
120-
/** @var array<array<string, mixed>> $partsData */
122+
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
121123
$partsData = $json['parts'];
122124
$parts = array_map(function (array $partData) {
123125
return MessagePart::fromJson($partData);

src/Messages/DTO/MessagePart.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,27 +232,47 @@ public function jsonSerialize(): array
232232
* {@inheritDoc}
233233
*
234234
* @since n.e.x.t
235+
*
236+
* @param array{
237+
* type: string,
238+
* text?: string,
239+
* file?: array<string, mixed>,
240+
* functionCall?: array<string, mixed>,
241+
* functionResponse?: array<string, mixed>
242+
* } $json The JSON data.
235243
*/
236244
public static function fromJson(array $json): MessagePart
237245
{
238246
$type = MessagePartTypeEnum::from((string) $json['type']);
239247

240248
if ($type->isText()) {
249+
if (!isset($json['text'])) {
250+
throw new \InvalidArgumentException('Text message part requires text field.');
251+
}
241252
return new self((string) $json['text']);
242253
} elseif ($type->isFile()) {
243-
/** @var array<string, mixed> $fileData */
254+
if (!isset($json['file'])) {
255+
throw new \InvalidArgumentException('File message part requires file field.');
256+
}
257+
/** @var array{fileType: string, url?: string, mimeType?: string, base64Data?: string} $fileData */
244258
$fileData = $json['file'];
245259
return new self(File::fromJson($fileData));
246260
} elseif ($type->isFunctionCall()) {
247-
/** @var array<string, mixed> $functionCallData */
261+
if (!isset($json['functionCall'])) {
262+
throw new \InvalidArgumentException('Function call message part requires functionCall field.');
263+
}
264+
/** @var array{id?: string, name?: string, args?: mixed} $functionCallData */
248265
$functionCallData = $json['functionCall'];
249266
return new self(FunctionCall::fromJson($functionCallData));
250267
} elseif ($type->isFunctionResponse()) {
251-
/** @var array<string, mixed> $functionResponseData */
268+
if (!isset($json['functionResponse'])) {
269+
throw new \InvalidArgumentException('Function response message part requires functionResponse field.');
270+
}
271+
/** @var array{id: string, name: string, response: mixed} $functionResponseData */
252272
$functionResponseData = $json['functionResponse'];
253273
return new self(FunctionResponse::fromJson($functionResponseData));
254274
}
255275

256-
throw new \InvalidArgumentException(sprintf('Unknown message part type: %s', $json['type']));
276+
throw new \InvalidArgumentException(sprintf('Unknown message part type: %s', (string) $json['type']));
257277
}
258278
}

src/Messages/DTO/ModelMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function __construct(array $parts)
3535
*/
3636
public static function fromJson(array $json): ModelMessage
3737
{
38-
/** @var array<array<string, mixed>> $partsData */
38+
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
3939
$partsData = $json['parts'];
4040
$parts = array_map(function (array $partData) {
4141
return MessagePart::fromJson($partData);

src/Messages/DTO/SystemMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function __construct(array $parts)
3535
*/
3636
public static function fromJson(array $json): SystemMessage
3737
{
38-
/** @var array<array<string, mixed>> $partsData */
38+
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
3939
$partsData = $json['parts'];
4040
$parts = array_map(function (array $partData) {
4141
return MessagePart::fromJson($partData);

src/Messages/DTO/UserMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function __construct(array $parts)
3434
*/
3535
public static function fromJson(array $json): UserMessage
3636
{
37-
/** @var array<array<string, mixed>> $partsData */
37+
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
3838
$partsData = $json['parts'];
3939
$parts = array_map(function (array $partData) {
4040
return MessagePart::fromJson($partData);

src/Operations/DTO/GenerativeAiOperation.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,15 @@ public function jsonSerialize(): array
158158
* {@inheritDoc}
159159
*
160160
* @since n.e.x.t
161+
*
162+
* @param array{id: string, state: string, result?: array<string, mixed>} $json The JSON data.
161163
*/
162164
public static function fromJson(array $json): GenerativeAiOperation
163165
{
164166
$state = OperationStateEnum::from((string) $json['state']);
165167
$result = null;
166168
if (isset($json['result'])) {
167-
/** @var array<string, mixed> $resultData */
169+
/** @var array{id: string, candidates: array<array<string, mixed>>, tokenUsage: array<string, mixed>, providerMetadata?: array<string, mixed>} $resultData */
168170
$resultData = $json['result'];
169171
$result = GenerativeAiResult::fromJson($resultData);
170172
}

src/Results/DTO/Candidate.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,12 @@ public function jsonSerialize(): array
137137
* {@inheritDoc}
138138
*
139139
* @since n.e.x.t
140+
*
141+
* @param array{message: array<string, mixed>, finishReason: string, tokenCount: int|string} $json The JSON data.
140142
*/
141143
public static function fromJson(array $json): Candidate
142144
{
143-
/** @var array<string, mixed> $messageData */
145+
/** @var array{role: string, parts: array<array<string, mixed>>} $messageData */
144146
$messageData = $json['message'];
145147

146148
return new self(

src/Results/DTO/GenerativeAiResult.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,16 +402,23 @@ public function jsonSerialize(): array
402402
* {@inheritDoc}
403403
*
404404
* @since n.e.x.t
405+
*
406+
* @param array{
407+
* id: string,
408+
* candidates: array<array<string, mixed>>,
409+
* tokenUsage: array<string, mixed>,
410+
* providerMetadata?: array<string, mixed>
411+
* } $json The JSON data.
405412
*/
406413
public static function fromJson(array $json): GenerativeAiResult
407414
{
408-
/** @var array<array<string, mixed>> $candidatesData */
415+
/** @var array<array{message: array<string, mixed>, finishReason: string, tokenCount: int|string}> $candidatesData */
409416
$candidatesData = $json['candidates'];
410417
$candidates = array_map(function (array $candidateData) {
411418
return Candidate::fromJson($candidateData);
412419
}, $candidatesData);
413420

414-
/** @var array<string, mixed> $tokenUsageData */
421+
/** @var array{promptTokens: int|string, completionTokens: int|string, totalTokens: int|string} $tokenUsageData */
415422
$tokenUsageData = $json['tokenUsage'];
416423
/** @var array<string, mixed> $providerMetadata */
417424
$providerMetadata = $json['providerMetadata'] ?? [];

src/Results/DTO/TokenUsage.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ public function jsonSerialize(): array
131131
* {@inheritDoc}
132132
*
133133
* @since n.e.x.t
134+
*
135+
* @param array{
136+
* promptTokens: int|string,
137+
* completionTokens: int|string,
138+
* totalTokens: int|string
139+
* } $json The JSON data.
134140
*/
135141
public static function fromJson(array $json): TokenUsage
136142
{

0 commit comments

Comments
 (0)