Skip to content

Commit 5cb08bf

Browse files
Merge branch 'dto-serlialization' into extender-dtos
2 parents e1c9e5d + 59e586c commit 5cb08bf

29 files changed

+523
-476
lines changed

src/Common/Contracts/WithArrayTransformationInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function toArray(): array;
2828
* @since 1.0.0
2929
*
3030
* @param TArrayShape $array The array data.
31-
* @return static The created instance.
31+
* @return self<TArrayShape> The created instance.
3232
*/
33-
public static function fromArray(array $array);
33+
public static function fromArray(array $array): self;
3434
}

src/Files/DTO/File.php

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
*
2828
* @extends AbstractDataValueObject<FileArrayShape>
2929
*/
30-
final class File extends AbstractDataValueObject
30+
class File extends AbstractDataValueObject
3131
{
32+
public const KEY_FILE_TYPE = 'fileType';
33+
public const KEY_MIME_TYPE = 'mimeType';
34+
public const KEY_URL = 'url';
35+
public const KEY_BASE64_DATA = 'base64Data';
3236
/**
3337
* @var MimeType The MIME type of the file.
3438
*/
@@ -346,44 +350,44 @@ public static function getJsonSchema(): array
346350
'oneOf' => [
347351
[
348352
'properties' => [
349-
'fileType' => [
353+
self::KEY_FILE_TYPE => [
350354
'type' => 'string',
351355
'const' => FileTypeEnum::REMOTE,
352356
'description' => 'The file type.',
353357
],
354-
'mimeType' => [
358+
self::KEY_MIME_TYPE => [
355359
'type' => 'string',
356360
'description' => 'The MIME type of the file.',
357361
'pattern' => '^[a-zA-Z0-9][a-zA-Z0-9!#$&\\-\\^_+.]*\\/[a-zA-Z0-9]'
358362
. '[a-zA-Z0-9!#$&\\-\\^_+.]*$',
359363
],
360-
'url' => [
364+
self::KEY_URL => [
361365
'type' => 'string',
362366
'format' => 'uri',
363367
'description' => 'The URL to the remote file.',
364368
],
365369
],
366-
'required' => ['fileType', 'mimeType', 'url'],
370+
'required' => [self::KEY_FILE_TYPE, self::KEY_MIME_TYPE, self::KEY_URL],
367371
],
368372
[
369373
'properties' => [
370-
'fileType' => [
374+
self::KEY_FILE_TYPE => [
371375
'type' => 'string',
372376
'const' => FileTypeEnum::INLINE,
373377
'description' => 'The file type.',
374378
],
375-
'mimeType' => [
379+
self::KEY_MIME_TYPE => [
376380
'type' => 'string',
377381
'description' => 'The MIME type of the file.',
378382
'pattern' => '^[a-zA-Z0-9][a-zA-Z0-9!#$&\\-\\^_+.]*\\/[a-zA-Z0-9]'
379383
. '[a-zA-Z0-9!#$&\\-\\^_+.]*$',
380384
],
381-
'base64Data' => [
385+
self::KEY_BASE64_DATA => [
382386
'type' => 'string',
383387
'description' => 'The base64-encoded file data.',
384388
],
385389
],
386-
'required' => ['fileType', 'mimeType', 'base64Data'],
390+
'required' => [self::KEY_FILE_TYPE, self::KEY_MIME_TYPE, self::KEY_BASE64_DATA],
387391
],
388392
],
389393
];
@@ -399,14 +403,14 @@ public static function getJsonSchema(): array
399403
public function toArray(): array
400404
{
401405
$data = [
402-
'fileType' => $this->fileType->value,
403-
'mimeType' => $this->getMimeType(),
406+
self::KEY_FILE_TYPE => $this->fileType->value,
407+
self::KEY_MIME_TYPE => $this->getMimeType(),
404408
];
405409

406410
if ($this->url !== null) {
407-
$data['url'] = $this->url;
408-
} elseif ($this->base64Data !== null) {
409-
$data['base64Data'] = $this->base64Data;
411+
$data[self::KEY_URL] = $this->url;
412+
} elseif (!$this->fileType->isRemote() && $this->base64Data !== null) {
413+
$data[self::KEY_BASE64_DATA] = $this->base64Data;
410414
} else {
411415
throw new RuntimeException(
412416
'File requires either url or base64Data. This should not be a possible condition.'
@@ -421,17 +425,17 @@ public function toArray(): array
421425
*
422426
* @since n.e.x.t
423427
*/
424-
public static function fromArray(array $array): File
428+
public static function fromArray(array $array): self
425429
{
426-
static::validateFromArrayData($array, ['fileType']);
430+
static::validateFromArrayData($array, [self::KEY_FILE_TYPE]);
427431

428432
// Check which properties are set to determine how to construct the File
429-
$mimeType = $array['mimeType'] ?? null;
433+
$mimeType = $array[self::KEY_MIME_TYPE] ?? null;
430434

431-
if (isset($array['url'])) {
432-
return new self($array['url'], $mimeType);
433-
} elseif (isset($array['base64Data'])) {
434-
return new self($array['base64Data'], $mimeType);
435+
if (isset($array[self::KEY_URL])) {
436+
return new self($array[self::KEY_URL], $mimeType);
437+
} elseif (isset($array[self::KEY_BASE64_DATA])) {
438+
return new self($array[self::KEY_BASE64_DATA], $mimeType);
435439
} else {
436440
throw new InvalidArgumentException('File requires either url or base64Data.');
437441
}

src/Messages/DTO/Message.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
*/
2828
class Message extends AbstractDataValueObject
2929
{
30+
public const KEY_ROLE = 'role';
31+
public const KEY_PARTS = 'parts';
3032
/**
3133
* @var MessageRoleEnum The role of the message sender.
3234
*/
@@ -85,19 +87,19 @@ public static function getJsonSchema(): array
8587
return [
8688
'type' => 'object',
8789
'properties' => [
88-
'role' => [
90+
self::KEY_ROLE => [
8991
'type' => 'string',
9092
'enum' => MessageRoleEnum::getValues(),
9193
'description' => 'The role of the message sender.',
9294
],
93-
'parts' => [
95+
self::KEY_PARTS => [
9496
'type' => 'array',
9597
'items' => MessagePart::getJsonSchema(),
9698
'minItems' => 1,
9799
'description' => 'The parts that make up this message.',
98100
],
99101
],
100-
'required' => ['role', 'parts'],
102+
'required' => [self::KEY_ROLE, self::KEY_PARTS],
101103
];
102104
}
103105

@@ -111,8 +113,8 @@ public static function getJsonSchema(): array
111113
public function toArray(): array
112114
{
113115
return [
114-
'role' => $this->role->value,
115-
'parts' => array_map(function (MessagePart $part) {
116+
self::KEY_ROLE => $this->role->value,
117+
self::KEY_PARTS => array_map(function (MessagePart $part) {
116118
return $part->toArray();
117119
}, $this->parts),
118120
];
@@ -123,14 +125,14 @@ public function toArray(): array
123125
*
124126
* @since n.e.x.t
125127
*
126-
* @return Message The specific message class based on the role.
128+
* @return self The specific message class based on the role.
127129
*/
128-
final public static function fromArray(array $array): Message
130+
final public static function fromArray(array $array): self
129131
{
130-
static::validateFromArrayData($array, ['role', 'parts']);
132+
static::validateFromArrayData($array, [self::KEY_ROLE, self::KEY_PARTS]);
131133

132-
$role = MessageRoleEnum::from($array['role']);
133-
$partsData = $array['parts'];
134+
$role = MessageRoleEnum::from($array[self::KEY_ROLE]);
135+
$partsData = $array[self::KEY_PARTS];
134136
$parts = array_map(function (array $partData) {
135137
return MessagePart::fromArray($partData);
136138
}, $partsData);

src/Messages/DTO/MessagePart.php

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@
3434
*
3535
* @extends AbstractDataValueObject<MessagePartArrayShape>
3636
*/
37-
final class MessagePart extends AbstractDataValueObject
37+
class MessagePart extends AbstractDataValueObject
3838
{
39+
public const KEY_TYPE = 'type';
40+
public const KEY_TEXT = 'text';
41+
public const KEY_FILE = 'file';
42+
public const KEY_FUNCTION_CALL = 'functionCall';
43+
public const KEY_FUNCTION_RESPONSE = 'functionResponse';
3944
/**
4045
* @var MessagePartTypeEnum The type of this message part.
4146
*/
@@ -167,52 +172,52 @@ public static function getJsonSchema(): array
167172
[
168173
'type' => 'object',
169174
'properties' => [
170-
'type' => [
175+
self::KEY_TYPE => [
171176
'type' => 'string',
172177
'const' => MessagePartTypeEnum::text()->value,
173178
],
174-
'text' => [
179+
self::KEY_TEXT => [
175180
'type' => 'string',
176181
'description' => 'Text content.',
177182
],
178183
],
179-
'required' => ['type', 'text'],
184+
'required' => [self::KEY_TYPE, self::KEY_TEXT],
180185
'additionalProperties' => false,
181186
],
182187
[
183188
'type' => 'object',
184189
'properties' => [
185-
'type' => [
190+
self::KEY_TYPE => [
186191
'type' => 'string',
187192
'const' => MessagePartTypeEnum::file()->value,
188193
],
189-
'file' => File::getJsonSchema(),
194+
self::KEY_FILE => File::getJsonSchema(),
190195
],
191-
'required' => ['type', 'file'],
196+
'required' => [self::KEY_TYPE, self::KEY_FILE],
192197
'additionalProperties' => false,
193198
],
194199
[
195200
'type' => 'object',
196201
'properties' => [
197-
'type' => [
202+
self::KEY_TYPE => [
198203
'type' => 'string',
199204
'const' => MessagePartTypeEnum::functionCall()->value,
200205
],
201-
'functionCall' => FunctionCall::getJsonSchema(),
206+
self::KEY_FUNCTION_CALL => FunctionCall::getJsonSchema(),
202207
],
203-
'required' => ['type', 'functionCall'],
208+
'required' => [self::KEY_TYPE, self::KEY_FUNCTION_CALL],
204209
'additionalProperties' => false,
205210
],
206211
[
207212
'type' => 'object',
208213
'properties' => [
209-
'type' => [
214+
self::KEY_TYPE => [
210215
'type' => 'string',
211216
'const' => MessagePartTypeEnum::functionResponse()->value,
212217
],
213-
'functionResponse' => FunctionResponse::getJsonSchema(),
218+
self::KEY_FUNCTION_RESPONSE => FunctionResponse::getJsonSchema(),
214219
],
215-
'required' => ['type', 'functionResponse'],
220+
'required' => [self::KEY_TYPE, self::KEY_FUNCTION_RESPONSE],
216221
'additionalProperties' => false,
217222
],
218223
],
@@ -228,16 +233,16 @@ public static function getJsonSchema(): array
228233
*/
229234
public function toArray(): array
230235
{
231-
$data = ['type' => $this->type->value];
236+
$data = [self::KEY_TYPE => $this->type->value];
232237

233238
if ($this->text !== null) {
234-
$data['text'] = $this->text;
239+
$data[self::KEY_TEXT] = $this->text;
235240
} elseif ($this->file !== null) {
236-
$data['file'] = $this->file->toArray();
241+
$data[self::KEY_FILE] = $this->file->toArray();
237242
} elseif ($this->functionCall !== null) {
238-
$data['functionCall'] = $this->functionCall->toArray();
243+
$data[self::KEY_FUNCTION_CALL] = $this->functionCall->toArray();
239244
} elseif ($this->functionResponse !== null) {
240-
$data['functionResponse'] = $this->functionResponse->toArray();
245+
$data[self::KEY_FUNCTION_RESPONSE] = $this->functionResponse->toArray();
241246
} else {
242247
throw new RuntimeException(
243248
'MessagePart requires one of: text, file, functionCall, or functionResponse. '
@@ -253,19 +258,19 @@ public function toArray(): array
253258
*
254259
* @since n.e.x.t
255260
*/
256-
public static function fromArray(array $array): MessagePart
261+
public static function fromArray(array $array): self
257262
{
258-
static::validateFromArrayData($array, ['type']);
263+
static::validateFromArrayData($array, [self::KEY_TYPE]);
259264

260265
// Check which properties are set to determine how to construct the MessagePart
261-
if (isset($array['text'])) {
262-
return new self($array['text']);
263-
} elseif (isset($array['file'])) {
264-
return new self(File::fromArray($array['file']));
265-
} elseif (isset($array['functionCall'])) {
266-
return new self(FunctionCall::fromArray($array['functionCall']));
267-
} elseif (isset($array['functionResponse'])) {
268-
return new self(FunctionResponse::fromArray($array['functionResponse']));
266+
if (isset($array[self::KEY_TEXT])) {
267+
return new self($array[self::KEY_TEXT]);
268+
} elseif (isset($array[self::KEY_FILE])) {
269+
return new self(File::fromArray($array[self::KEY_FILE]));
270+
} elseif (isset($array[self::KEY_FUNCTION_CALL])) {
271+
return new self(FunctionCall::fromArray($array[self::KEY_FUNCTION_CALL]));
272+
} elseif (isset($array[self::KEY_FUNCTION_RESPONSE])) {
273+
return new self(FunctionResponse::fromArray($array[self::KEY_FUNCTION_RESPONSE]));
269274
} else {
270275
throw new InvalidArgumentException(
271276
'MessagePart requires one of: text, file, functionCall, or functionResponse.'

src/Messages/DTO/ModelMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
* @since n.e.x.t
1717
*/
18-
final class ModelMessage extends Message
18+
class ModelMessage extends Message
1919
{
2020
/**
2121
* Constructor.

src/Messages/DTO/SystemMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
* @since n.e.x.t
1717
*/
18-
final class SystemMessage extends Message
18+
class SystemMessage extends Message
1919
{
2020
/**
2121
* Constructor.

src/Messages/DTO/UserMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
* @since n.e.x.t
1616
*/
17-
final class UserMessage extends Message
17+
class UserMessage extends Message
1818
{
1919
/**
2020
* Constructor.

0 commit comments

Comments
 (0)