Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ public function literal(bool|float|int|string $literal): LiteralSchema
* @param array<string, SchemaInterface> $fieldNameToSchema
* @param class-string $classname
*/
public function object(array $fieldNameToSchema, string $classname = \stdClass::class): ObjectSchema
public function object(array $fieldNameToSchema, string $classname = \stdClass::class, bool $construct = false): ObjectSchema
{
return new ObjectSchema($fieldNameToSchema, $classname);
return new ObjectSchema($fieldNameToSchema, $classname, $construct);
}

public function record(SchemaInterface $fieldSchema): RecordSchema
Expand Down
19 changes: 14 additions & 5 deletions src/Schema/ObjectSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class ObjectSchema extends AbstractObjectSchema implements ObjectSchemaInt
* @param array<mixed, mixed> $fieldToSchema
* @param class-string $classname
*/
public function __construct(array $fieldToSchema, private string $classname = \stdClass::class)
public function __construct(array $fieldToSchema, private string $classname = \stdClass::class, private bool $construct = false)
{
parent::__construct($fieldToSchema);
}
Expand All @@ -26,20 +26,29 @@ public function __construct(array $fieldToSchema, private string $classname = \s
*/
protected function parseFields(array $input, Errors $childrenErrors): object
{
$object = new ($this->classname);

$fields = [];
foreach ($this->getFieldToSchema() as $fieldName => $fieldSchema) {
try {
if ($this->skip($input, $fieldName)) {
continue;
}

$object->{$fieldName} = $fieldSchema->parse($input[$fieldName] ?? null);
$fields[$fieldName] = $fieldSchema->parse($input[$fieldName] ?? null);
} catch (ErrorsException $e) {
$childrenErrors->add($e->errors, $fieldName);
}
}

return $object;
if (!$this->construct) {
$object = new ($this->classname);

foreach ($fields as $fieldName => $fieldValue) {
$object->{$fieldName} = $fieldValue;
}

return $object;
}

return new ($this->classname)(...$fields);
}
}
64 changes: 63 additions & 1 deletion tests/Unit/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ enum BackedSuit: string
case Spades = 'S';
}

final class ObjectDemo implements \JsonSerializable
{
public string $field1;

public function jsonSerialize(): array
{
return [
'field1' => $this->field1,
];
}
}

final class ObjectConstructDemo implements \JsonSerializable
{
public function __construct(public string $field1) {}

public function jsonSerialize(): array
{
return [
'field1' => $this->field1,
];
}
}

/**
* @covers \Chubbyphp\Parsing\Parser
*
Expand Down Expand Up @@ -159,7 +183,7 @@ public function testLiteral(): void
self::assertInstanceOf(LiteralSchema::class, $literalSchema);
}

public function testObject(): void
public function testObjectStdClass(): void
{
$p = new Parser();

Expand All @@ -170,6 +194,44 @@ public function testObject(): void
self::assertInstanceOf(ObjectSchema::class, $objectSchema);
}

public function testObjectWithObject(): void
{
$p = new Parser();

$objectSchema = $p->object([
'field' => $p->string(),
], ObjectDemo::class, );

$classnameReflection = new \ReflectionProperty(ObjectSchema::class, 'classname');

self::assertSame(ObjectDemo::class, $classnameReflection->getValue($objectSchema));

$constructReflection = new \ReflectionProperty(ObjectSchema::class, 'construct');

self::assertFalse($constructReflection->getValue($objectSchema));

self::assertInstanceOf(ObjectSchema::class, $objectSchema);
}

public function testObjectWithObjectConstruct(): void
{
$p = new Parser();

$objectSchema = $p->object([
'field' => $p->string(),
], ObjectConstructDemo::class, true);

$classnameReflection = new \ReflectionProperty(ObjectSchema::class, 'classname');

self::assertSame(ObjectConstructDemo::class, $classnameReflection->getValue($objectSchema));

$constructReflection = new \ReflectionProperty(ObjectSchema::class, 'construct');

self::assertTrue($constructReflection->getValue($objectSchema));

self::assertInstanceOf(ObjectSchema::class, $objectSchema);
}

public function testRecord(): void
{
$p = new Parser();
Expand Down
79 changes: 69 additions & 10 deletions tests/Unit/Schema/ObjectSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,28 @@ final class ObjectDemo implements \JsonSerializable
{
public string $field1;
public int $field2;
public ?float $field3;

public function jsonSerialize(): array
{
return [
'field1' => $this->field1,
'field2' => $this->field2,
'field3' => $this->field3,
];
}
}

final class ObjectConstructDemo implements \JsonSerializable
{
public function __construct(public string $field1, public int $field2, public ?float $field3) {}

public function jsonSerialize(): array
{
return [
'field1' => $this->field1,
'field2' => $this->field2,
'field3' => $this->field3,
];
}
}
Expand All @@ -35,7 +51,11 @@ final class ObjectSchemaTest extends TestCase
{
public function testImmutability(): void
{
$schema = new ObjectSchema(['field1' => new StringSchema(), 'field2' => new IntSchema()]);
$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
]);

self::assertNotSame($schema, $schema->nullable());
self::assertNotSame($schema, $schema->nullable(false));
Expand Down Expand Up @@ -78,11 +98,15 @@ public function testConstructWithoutFieldSchema(): void

public function testParseSuccess(): void
{
$input = ['field1' => 'test', 'field2' => 1];
$input = ['field1' => 'test', 'field2' => 1, 'field3' => 3.14159];

$schema = new ObjectSchema(['field1' => new StringSchema(), 'field2' => new IntSchema()]);
$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
]);

$output = $schema->parse([...$input, 'field3' => 1.5]);
$output = $schema->parse($input);

self::assertInstanceOf(\stdClass::class, $output);

Expand All @@ -91,9 +115,13 @@ public function testParseSuccess(): void

public function testParseSuccessWithClass(): void
{
$input = ['field1' => 'test', 'field2' => 1];
$input = ['field1' => 'test', 'field2' => 1, 'field3' => 3.14159];

$schema = new ObjectSchema(['field1' => new StringSchema(), 'field2' => new IntSchema()], ObjectDemo::class);
$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
], ObjectDemo::class);

$output = $schema->parse($input);

Expand All @@ -102,13 +130,35 @@ public function testParseSuccessWithClass(): void
self::assertSame($input, (array) $output);
}

public function testParseSuccessWithConstructClass(): void
{
$input = ['field1' => 'test', 'field2' => 1, 'field3' => 3.14159];

$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
], ObjectConstructDemo::class, true);

$output = $schema->parse($input);

self::assertInstanceOf(ObjectConstructDemo::class, $output);

self::assertSame($input, (array) $output);
}

public function testParseSuccessWithStdClassInput(): void
{
$input = new \stdClass();
$input->field1 = 'test';
$input->field2 = 1;
$input->field3 = 3.14159;

$schema = new ObjectSchema(['field1' => new StringSchema(), 'field2' => new IntSchema()]);
$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
]);

$output = $schema->parse($input);

Expand All @@ -119,9 +169,13 @@ public function testParseSuccessWithStdClassInput(): void

public function testParseSuccessWithIteratorInput(): void
{
$input = new \ArrayIterator(['field1' => 'test', 'field2' => 1]);
$input = new \ArrayIterator(['field1' => 'test', 'field2' => 1, 'field3' => 3.14159]);

$schema = new ObjectSchema(['field1' => new StringSchema(), 'field2' => new IntSchema()]);
$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
]);

$output = $schema->parse($input);

Expand All @@ -135,8 +189,13 @@ public function testParseSuccessWithJsonSerialzableObject(): void
$input = new ObjectDemo();
$input->field1 = 'test';
$input->field2 = 1;
$input->field3 = 3.14159;

$schema = new ObjectSchema(['field1' => new StringSchema(), 'field2' => new IntSchema()]);
$schema = new ObjectSchema([
'field1' => new StringSchema(),
'field2' => new IntSchema(),
'field3' => new FloatSchema(),
]);

$output = $schema->parse($input);

Expand Down