Skip to content

Commit 62a2e75

Browse files
committed
Introduce InputFieldBuilder and InputObjectBuilder
1 parent 55beae0 commit 62a2e75

File tree

6 files changed

+217
-3
lines changed

6 files changed

+217
-3
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ composer require simpod/graphql-utils
3232

3333
### Schema Builders
3434

35-
Instead of defining your schema as an array, use can use more objective-oriented approach. This library provides set of strictly typed builders that help you build your schema.
35+
Instead of defining your schema as an array, use can use more objective-oriented approach. This library provides set of strictly typed builders that help you build your schema:
36+
37+
- EnumBuilder
38+
- FieldBuilder
39+
- InputFieldBuilder
40+
- InputObjectBuilder
41+
- InterfaceBuilder
42+
- ObjectBuilder
43+
- TypeBuilder
44+
- UnionBuilder
3645

3746
#### ObjectBuilder and FieldBuilder
3847

src/Builder/InputFieldBuilder.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimPod\GraphQLUtils\Builder;
6+
7+
use ReflectionProperty;
8+
9+
class InputFieldBuilder
10+
{
11+
private string $name;
12+
13+
private mixed $type;
14+
15+
private string|null $description = null;
16+
17+
private mixed $defaultValue;
18+
19+
final private function __construct(string $name, mixed $type)
20+
{
21+
$this->name = $name;
22+
$this->type = $type;
23+
}
24+
25+
/**
26+
* @return static
27+
*/
28+
public static function create(string $name, mixed $type): self
29+
{
30+
return new static($name, $type);
31+
}
32+
33+
/**
34+
* @return $this
35+
*/
36+
public function setDefaultValue(mixed $defaultValue): self
37+
{
38+
$this->defaultValue = $defaultValue;
39+
40+
return $this;
41+
}
42+
43+
/**
44+
* @return $this
45+
*/
46+
public function setDescription(string $description): self
47+
{
48+
$this->description = $description;
49+
50+
return $this;
51+
}
52+
53+
/**
54+
* @psalm-return array<string, mixed>
55+
*/
56+
public function build(): array
57+
{
58+
$config = [
59+
'name' => $this->name,
60+
'description' => $this->description,
61+
'type' => $this->type,
62+
];
63+
64+
$property = new ReflectionProperty($this, 'defaultValue');
65+
$property->setAccessible(true);
66+
if ($property->isInitialized($this)) {
67+
/** @psalm-suppress MixedAssignment */
68+
$config['defaultValue'] = $this->defaultValue;
69+
}
70+
71+
return $config;
72+
}
73+
}

src/Builder/InputObjectBuilder.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimPod\GraphQLUtils\Builder;
6+
7+
use GraphQL\Type\Definition\InputObjectField;
8+
9+
class InputObjectBuilder extends TypeBuilder
10+
{
11+
/** @var callable():array<string, mixed>|array<string, mixed>|InputObjectField */
12+
private $fields = [];
13+
14+
/**
15+
* @return static
16+
*/
17+
public static function create(string $name): self
18+
{
19+
return new static($name);
20+
}
21+
22+
/**
23+
* @param callable():array<string, mixed>|array<string, mixed>|InputObjectField $fields
24+
*
25+
* @return $this
26+
*/
27+
public function setFields(callable|array $fields): self
28+
{
29+
$this->fields = $fields;
30+
31+
return $this;
32+
}
33+
34+
/**
35+
* @psalm-return array<string, mixed>
36+
*/
37+
public function build(): array
38+
{
39+
return [
40+
'name' => $this->name,
41+
'description' => $this->description,
42+
'fields' => $this->fields,
43+
];
44+
}
45+
}

src/Builder/TypeBuilder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ abstract class TypeBuilder
1212
{
1313
public const VALID_NAME_PATTERN = '~^[_a-zA-Z][_a-zA-Z0-9]*$~';
1414

15-
private string $name;
15+
protected string $name;
1616

17-
private ?string $description = null;
17+
protected ?string $description = null;
1818

1919
final protected function __construct(string $name)
2020
{
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimPod\GraphQLUtils\Tests\Builder;
6+
7+
use GraphQL\Type\Definition\Type;
8+
use PHPUnit\Framework\TestCase;
9+
use SimPod\GraphQLUtils\Builder\InputFieldBuilder;
10+
11+
final class InputFieldBuilderTest extends TestCase
12+
{
13+
public function testCreate(): void
14+
{
15+
$field = InputFieldBuilder::create('SomeField', Type::string())
16+
->setDefaultValue(null)
17+
->setDeprecationReason('Deprecated')
18+
->setDescription('SomeDescription')
19+
->build();
20+
21+
self::assertSame('SomeField', $field['name']);
22+
self::assertArrayHasKey('deprecationReason', $field);
23+
self::assertSame('Deprecated', $field['deprecationReason']);
24+
self::assertArrayHasKey('defaultValue', $field);
25+
self::assertNull($field['defaultValue']);
26+
self::assertArrayHasKey('description', $field);
27+
self::assertSame('SomeDescription', $field['description']);
28+
}
29+
30+
public function testCreateWithoutDefaultValue(): void
31+
{
32+
$field = InputFieldBuilder::create('SomeField', Type::string())
33+
->build();
34+
35+
self::assertArrayNotHasKey('defaultValue', $field);
36+
}
37+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimPod\GraphQLUtils\Tests\Builder;
6+
7+
use GraphQL\Type\Definition\InputObjectField;
8+
use GraphQL\Type\Definition\InterfaceType;
9+
use GraphQL\Type\Definition\Type;
10+
use PHPUnit\Framework\TestCase;
11+
use SimPod\GraphQLUtils\Builder\InputFieldBuilder;
12+
use SimPod\GraphQLUtils\Builder\InputObjectBuilder;
13+
use SimPod\GraphQLUtils\Builder\InterfaceBuilder;
14+
15+
final class InputObjectBuilderTest extends TestCase
16+
{
17+
public function testCreate(): void
18+
{
19+
$description = 'To the sichuan-style nachos add ghee, noodles, buttermilk and heated herring.';
20+
$name = 'SomeType';
21+
$interface = new class () extends InterfaceType {
22+
public function __construct()
23+
{
24+
$builder = InterfaceBuilder::create('InterfaceA');
25+
parent::__construct($builder->build());
26+
}
27+
};
28+
29+
$fieldResolver = static function (): void {
30+
};
31+
32+
$builder = InputObjectBuilder::create($name);
33+
$object = $builder
34+
->setDescription($description)
35+
->setFields(
36+
[
37+
InputFieldBuilder::create('SomeField', Type::string())->build(),
38+
new InputObjectField(InputFieldBuilder::create('Another', Type::string())->build()),
39+
]
40+
)
41+
->build();
42+
43+
self::assertArrayHasKey('name', $object);
44+
self::assertSame($name, $object['name']);
45+
self::assertArrayHasKey('description', $object);
46+
self::assertSame($description, $object['description']);
47+
self::assertIsArray($object['fields']);
48+
self::assertCount(2, $object['fields']);
49+
}
50+
}

0 commit comments

Comments
 (0)