Skip to content

Commit 1a3665e

Browse files
committed
Split TypeBuilder for more flexibility & extensibility
1 parent 38b706e commit 1a3665e

23 files changed

+1408
-894
lines changed

src/ExpressionLanguage/ExpressionFunction.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
class ExpressionFunction extends BaseExpressionFunction
1212
{
13+
/**
14+
* TODO: use single source for all usages (create a provider).
15+
*/
1316
protected string $gqlServices = '$'.TypeGenerator::GRAPHQL_SERVICES;
1417

1518
public function __construct(string $name, callable $compiler, ?callable $evaluator = null)

src/Generator/ConfigBuilder.php

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator;
6+
7+
use Murtukov\PHPCodeGenerator\PhpFile;
8+
use Overblog\GraphQLBundle\Generator\ConfigBuilder\ConfigBuilderInterface;
9+
use Overblog\GraphQLBundle\Generator\Model\TypeConfig;
10+
11+
class ConfigBuilder
12+
{
13+
/**
14+
* @var iterable<ConfigBuilderInterface>
15+
*/
16+
protected iterable $builders;
17+
18+
/**
19+
* @param iterable<ConfigBuilderInterface> $builders
20+
*/
21+
public function __construct(iterable $builders)
22+
{
23+
$this->builders = $builders;
24+
}
25+
26+
/**
27+
* Builds a config array compatible with webonyx/graphql-php type system. The content
28+
* of the array depends on the GraphQL type that is currently being generated.
29+
*
30+
* Render example (object):
31+
*
32+
* [
33+
* 'name' => self::NAME,
34+
* 'description' => 'Root query type',
35+
* 'fields' => fn() => [
36+
* 'posts' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\FieldsBuilder::buildField()},
37+
* 'users' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\FieldsBuilder::buildField()},
38+
* ...
39+
* ],
40+
* 'interfaces' => fn() => [
41+
* $services->getType('PostInterface'),
42+
* ...
43+
* ],
44+
* 'resolveField' => {@see \Overblog\GraphQLBundle\Generator\ResolveInstructionBuilder::build()},
45+
* ]
46+
*
47+
* Render example (input-object):
48+
*
49+
* [
50+
* 'name' => self::NAME,
51+
* 'description' => 'Some description.',
52+
* 'validation' => {@see \Overblog\GraphQLBundle\Generator\ValidationRulesBuilder::build()}
53+
* 'fields' => fn() => [
54+
* {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\FieldsBuilder::buildField()},
55+
* ...
56+
* ],
57+
* ]
58+
*
59+
* Render example (interface)
60+
*
61+
* [
62+
* 'name' => self::NAME,
63+
* 'description' => 'Some description.',
64+
* 'fields' => fn() => [
65+
* {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\FieldsBuilder::buildField()},
66+
* ...
67+
* ],
68+
* 'resolveType' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\ResolveTypeBuilder::buildResolveType()},
69+
* ]
70+
*
71+
* Render example (union):
72+
*
73+
* [
74+
* 'name' => self::NAME,
75+
* 'description' => 'Some description.',
76+
* 'types' => fn() => [
77+
* $services->getType('Photo'),
78+
* ...
79+
* ],
80+
* 'resolveType' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\ResolveTypeBuilder::buildResolveType()},
81+
* ]
82+
*
83+
* Render example (custom-scalar):
84+
*
85+
* [
86+
* 'name' => self::NAME,
87+
* 'description' => 'Some description'
88+
* 'serialize' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\CustomScalarTypeFieldsBuilder::buildScalarCallback()},
89+
* 'parseValue' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\CustomScalarTypeFieldsBuilder::buildScalarCallback()},
90+
* 'parseLiteral' => {@see \Overblog\GraphQLBundle\Generator\ConfigBuilder\CustomScalarTypeFieldsBuilder::buildScalarCallback()},
91+
* ]
92+
*
93+
* Render example (enum):
94+
*
95+
* [
96+
* 'name' => self::NAME,
97+
* 'values' => [
98+
* 'PUBLISHED' => ['value' => 1],
99+
* 'DRAFT' => ['value' => 2],
100+
* 'STANDBY' => [
101+
* 'value' => 3,
102+
* 'description' => 'Waiting for validation',
103+
* ],
104+
* ...
105+
* ],
106+
* ]
107+
*/
108+
public function build(TypeConfig $typeConfig, PhpFile $phpFile): Collection
109+
{
110+
$configLoader = Collection::assoc();
111+
foreach ($this->builders as $builder) {
112+
$builder->build($typeConfig, $configLoader, $phpFile);
113+
}
114+
115+
return $configLoader;
116+
}
117+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator\ConfigBuilder;
6+
7+
use Murtukov\PHPCodeGenerator\PhpFile;
8+
use Overblog\GraphQLBundle\Generator\Collection;
9+
use Overblog\GraphQLBundle\Generator\Model\TypeConfig;
10+
11+
interface ConfigBuilderInterface
12+
{
13+
public function build(TypeConfig $typeConfig, Collection $builder, PhpFile $phpFile): void;
14+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator\ConfigBuilder;
6+
7+
use Murtukov\PHPCodeGenerator\ArrowFunction;
8+
use Murtukov\PHPCodeGenerator\Literal;
9+
use Murtukov\PHPCodeGenerator\PhpFile;
10+
use Murtukov\PHPCodeGenerator\Utils;
11+
use Overblog\GraphQLBundle\Generator\Collection;
12+
use Overblog\GraphQLBundle\Generator\Exception\GeneratorException;
13+
use Overblog\GraphQLBundle\Generator\Model\TypeConfig;
14+
15+
class CustomScalarTypeFieldsBuilder implements ConfigBuilderInterface
16+
{
17+
public function build(TypeConfig $typeConfig, Collection $builder, PhpFile $phpFile): void
18+
{
19+
// only by custom-scalar types
20+
if ($typeConfig->isCustomScalar()) {
21+
if (isset($typeConfig->scalarType)) {
22+
$builder->addItem('scalarType', $typeConfig->scalarType);
23+
}
24+
25+
if (isset($typeConfig->serialize)) {
26+
$builder->addItem('serialize', $this->buildScalarCallback($typeConfig->serialize, 'serialize', $typeConfig, $phpFile));
27+
}
28+
29+
if (isset($typeConfig->parseValue)) {
30+
$builder->addItem('parseValue', $this->buildScalarCallback($typeConfig->parseValue, 'parseValue', $typeConfig, $phpFile));
31+
}
32+
33+
if (isset($typeConfig->parseLiteral)) {
34+
$builder->addItem('parseLiteral', $this->buildScalarCallback($typeConfig->parseLiteral, 'parseLiteral', $typeConfig, $phpFile));
35+
}
36+
}
37+
}
38+
39+
/**
40+
* Builds an arrow function that calls a static method.
41+
*
42+
* Render example:
43+
*
44+
* fn() => MyClassName::myMethodName(...\func_get_args())
45+
*
46+
* @param callable|mixed $callback - a callable string or a callable array
47+
*
48+
* @throws GeneratorException
49+
*/
50+
protected function buildScalarCallback($callback, string $fieldName, TypeConfig $typeConfig, PhpFile $phpFile): ArrowFunction
51+
{
52+
if (!is_callable($callback)) {
53+
throw new GeneratorException("Value of '$fieldName' is not callable.");
54+
}
55+
56+
$closure = new ArrowFunction();
57+
58+
if (!is_string($callback)) {
59+
[$class, $method] = $callback;
60+
} else {
61+
[$class, $method] = explode('::', $callback);
62+
}
63+
64+
$className = Utils::resolveQualifier($class);
65+
66+
if ($className === $typeConfig->class_name) {
67+
// Create an alias if name of serializer is same as type name
68+
$className = 'Base' . $className;
69+
$phpFile->addUse($class, $className);
70+
} else {
71+
$phpFile->addUse($class);
72+
}
73+
74+
$closure->setExpression(Literal::new("$className::$method(...\\func_get_args())"));
75+
76+
return $closure;
77+
}
78+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator\ConfigBuilder;
6+
7+
use Murtukov\PHPCodeGenerator\PhpFile;
8+
use Overblog\GraphQLBundle\Generator\Collection;
9+
use Overblog\GraphQLBundle\Generator\Model\TypeConfig;
10+
11+
class DescriptionBuilder implements ConfigBuilderInterface
12+
{
13+
public function build(TypeConfig $typeConfig, Collection $builder, PhpFile $phpFile): void
14+
{
15+
if (isset($typeConfig->description)) {
16+
$builder->addItem('description', $typeConfig->description);
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)