Skip to content

Commit d30f53c

Browse files
authored
Merge pull request #384 from richard-myers/Resolve-Restoring-Promoted-Properties-During-Desrilization
Resolve handling of promoted properties during desrilization
2 parents 4e822d3 + af60807 commit d30f53c

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

src/StructuredOutput/Deserializer/Deserializer.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ protected function deserializeObject(array $data, string $className): object
5757
// Get all properties including private/protected
5858
$properties = $reflection->getProperties();
5959

60+
// Track values set on promoted properties
61+
$promotedArgs = [];
62+
6063
foreach ($properties as $property) {
6164
$propertyName = $property->getName();
6265

@@ -72,13 +75,18 @@ protected function deserializeObject(array $data, string $className): object
7275
}
7376

7477
$property->setValue($instance, $value);
78+
79+
// Track any promoted arguments that are being set
80+
if ($property->isPromoted()) {
81+
$promotedArgs[ $propertyName ] = $value;
82+
}
7583
}
7684
}
7785

7886
// Call constructor if it exists and is public
7987
$constructor = $reflection->getConstructor();
8088
if ($constructor && $constructor->isPublic() && $constructor->getNumberOfRequiredParameters() === 0) {
81-
$constructor->invoke($instance);
89+
$constructor->invokeArgs($instance, $promotedArgs);
8290
}
8391

8492
return $instance;

tests/DeserializerTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,43 @@ public function test_person_with_address(): void
3838
$this->assertEquals('Rome', $obj->address->city);
3939
}
4040

41+
public function test_constructor_as_new_instance(): void
42+
{
43+
// Check we can manually instantiate the class with values
44+
$greenObj = new ColorWithDefaults(0, 255, 0);
45+
46+
$this->assertInstanceOf(ColorWithDefaults::class, $greenObj);
47+
$this->assertEquals(0, $greenObj->r);
48+
$this->assertEquals(255, $greenObj->g);
49+
$this->assertEquals(0, $greenObj->b);
50+
}
51+
52+
public function test_constructor_deserialize_with_default_values(): void
53+
{
54+
// Create a new instance from json deserialization, where all properties are optional and have default values (will be black)
55+
$json = '{}';
56+
57+
$obj = Deserializer::make()->fromJson($json, ColorWithDefaults::class);
58+
59+
$this->assertInstanceOf(ColorWithDefaults::class, $obj);
60+
$this->assertEquals(0, $obj->r);
61+
$this->assertEquals(0, $obj->g);
62+
$this->assertEquals(0, $obj->b);
63+
}
64+
65+
public function test_constructor_deserialize_with_provided_values(): void
66+
{
67+
// Create a new instance, where properties are being provided for a "green" color
68+
$json = '{"r": 0, "g": 255, "b": 0}';
69+
70+
$obj = Deserializer::make()->fromJson($json, ColorWithDefaults::class);
71+
72+
$this->assertInstanceOf(ColorWithDefaults::class, $obj);
73+
$this->assertEquals(0, $obj->r);
74+
$this->assertEquals(255, $obj->g);
75+
$this->assertEquals(0, $obj->b);
76+
}
77+
4178
public function test_deserialize_array(): void
4279
{
4380
$json = '{"firstName": "John", "lastName": "Doe", "tags": [{"name": "agent"}]}';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare( strict_types=1 );
4+
5+
namespace NeuronAI\Tests\Stubs\StructuredOutput;
6+
7+
use NeuronAI\StructuredOutput\SchemaProperty;
8+
9+
class ColorWithDefaults
10+
{
11+
12+
public function __construct(
13+
#[SchemaProperty( description: "The RED", required: false )]
14+
public int $r = 0,
15+
#[SchemaProperty( description: "The GREEN", required: false )]
16+
public int $g = 0,
17+
#[SchemaProperty( description: "The BLUE", required: false )]
18+
public int $b = 0,
19+
) {}
20+
21+
}

0 commit comments

Comments
 (0)