Skip to content

Commit 05729d0

Browse files
author
Jeremiah VALERIE
committed
wip
1 parent 941238c commit 05729d0

14 files changed

+446
-195
lines changed

src/Config/InterfaceTypeDefinition.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ public function getDefinition(): ArrayNodeDefinition
1212
{
1313
/** @var ArrayNodeDefinition $node */
1414
$node = self::createNode('_interface_config');
15+
$this->resolverNormalization($node, 'typeResolver', 'resolveType');
1516

1617
/** @phpstan-ignore-next-line */
1718
$node
1819
->children()
1920
->append($this->nameSection())
2021
->append($this->outputFieldsSection())
21-
->append($this->resolveTypeSection())
22+
->append($this->resolverSection('typeResolver', 'GraphQL type resolver'))
2223
->append($this->descriptionSection())
2324
->arrayNode('interfaces')
2425
->prototype('scalar')->info('One of internal or custom interface types.')->end()

src/Config/ObjectTypeDefinition.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function getDefinition(): ArrayNodeDefinition
1616

1717
/** @var ArrayNodeDefinition $node */
1818
$node = $builder->getRootNode();
19+
$this->resolverNormalization($node, 'fieldResolver', 'resolveField');
1920

2021
/** @phpstan-ignore-next-line */
2122
$node
@@ -29,7 +30,7 @@ public function getDefinition(): ArrayNodeDefinition
2930
->prototype('scalar')->info('One of internal or custom interface types.')->end()
3031
->end()
3132
->variableNode('isTypeOf')->end()
32-
->variableNode('resolveField')->end()
33+
->append($this->resolverSection('fieldResolver', 'GraphQL field value resolver'))
3334
->variableNode('fieldsDefaultAccess')
3435
->info('Default access control to fields (expression language can be use here)')
3536
->end()

src/Config/TypeDefinition.php

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
namespace Overblog\GraphQLBundle\Config;
66

7+
use Overblog\GraphQLBundle\ExpressionLanguage\ExpressionLanguage;
78
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
9+
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
810
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
911
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
1012
use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition;
@@ -32,11 +34,6 @@ public static function create(): self
3234
return new static();
3335
}
3436

35-
protected function resolveTypeSection(): VariableNodeDefinition
36-
{
37-
return self::createNode('resolveType', 'variable');
38-
}
39-
4037
protected function nameSection(): ScalarNodeDefinition
4138
{
4239
/** @var ScalarNodeDefinition $node */
@@ -156,6 +153,87 @@ protected function typeSection(bool $isRequired = false): ScalarNodeDefinition
156153
return $node;
157154
}
158155

156+
protected function resolverNormalization(NodeDefinition $node, string $new, string $old): void
157+
{
158+
$node
159+
->beforeNormalization()
160+
->ifTrue(fn ($options) => !empty($options[$old]) && empty($options[$new]))
161+
->then(function ($options) use ($old, $new) {
162+
if (is_callable($options[$old])) {
163+
if (is_array($options[$old])) {
164+
$options[$new]['method'] = implode('::', $options[$old]);
165+
} else {
166+
$options[$new]['method'] = $options[$old];
167+
}
168+
} elseif (is_string($options[$old])) {
169+
$options[$new]['expression'] = ExpressionLanguage::stringHasTrigger($options[$old]) ?
170+
ExpressionLanguage::unprefixExpression($options[$old]) :
171+
json_encode($options[$old]);
172+
} else {
173+
$options[$new]['expression'] = json_encode($options[$old]);
174+
}
175+
176+
return $options;
177+
})
178+
->end()
179+
->beforeNormalization()
180+
->ifTrue(fn ($options) => is_array($options) && array_key_exists($old, $options))
181+
->then(function ($options) use ($old) {
182+
unset($options[$old]);
183+
184+
return $options;
185+
})
186+
->end()
187+
->validate()
188+
->ifTrue(fn (array $v) => !empty($v[$new]) && !empty($v[$old]))
189+
->thenInvalid(sprintf(
190+
'"%s" and "%s" should not be use together in "%%s".',
191+
$new,
192+
$old,
193+
))
194+
->end()
195+
;
196+
}
197+
198+
protected function resolverSection(string $name, string $info): ArrayNodeDefinition
199+
{
200+
/** @var ArrayNodeDefinition $node */
201+
$node = self::createNode($name);
202+
/** @phpstan-ignore-next-line */
203+
$node
204+
->info($info)
205+
->validate()
206+
->ifTrue(fn (array $v) => !empty($v['method']) && !empty($v['expression']))
207+
->thenInvalid('"method" and "expression" should not be use together.')
208+
->end()
209+
->beforeNormalization()
210+
// Allow short syntax
211+
->ifTrue(fn ($options) => is_string($options) && ExpressionLanguage::stringHasTrigger($options))
212+
->then(fn ($options) => ['expression' => ExpressionLanguage::unprefixExpression($options)])
213+
->end()
214+
->beforeNormalization()
215+
->ifTrue(fn ($options) => is_string($options) && !ExpressionLanguage::stringHasTrigger($options))
216+
->then(fn ($options) => ['method' => $options])
217+
->end()
218+
->beforeNormalization()
219+
// clean expression
220+
->ifTrue(fn ($options) => isset($options['expression']) && is_string($options['expression']) && ExpressionLanguage::stringHasTrigger($options['expression']))
221+
->then(function ($options) {
222+
$options['expression'] = ExpressionLanguage::unprefixExpression($options['expression']);
223+
224+
return $options;
225+
})
226+
->end()
227+
->children()
228+
->scalarNode('method')->end()
229+
->scalarNode('expression')->end()
230+
->scalarNode('id')->end()
231+
->end()
232+
;
233+
234+
return $node;
235+
}
236+
159237
/**
160238
* @return mixed
161239
*

src/Config/TypeWithOutputFieldsDefinition.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ protected function outputFieldsSection(): NodeDefinition
1818
$node->isRequired()->requiresAtLeastOneElement();
1919

2020
$prototype = $node->useAttributeAsKey('name', false)->prototype('array');
21+
$this->resolverNormalization($prototype, 'resolver', 'resolve');
2122

2223
/** @phpstan-ignore-next-line */
2324
$prototype
@@ -68,9 +69,7 @@ protected function outputFieldsSection(): NodeDefinition
6869
->end()
6970
->end()
7071
->end()
71-
->variableNode('resolve')
72-
->info('Value resolver (expression language can be used here)')
73-
->end()
72+
->append($this->resolverSection('resolver', 'GraphQL value resolver'))
7473
->append($this->descriptionSection())
7574
->append($this->deprecationReasonSection())
7675
->variableNode('access')

src/Config/UnionTypeDefinition.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public function getDefinition(): ArrayNodeDefinition
1212
{
1313
/** @var ArrayNodeDefinition $node */
1414
$node = self::createNode('_union_config');
15+
$this->resolverNormalization($node, 'typeResolver', 'resolveType');
1516

1617
/** @phpstan-ignore-next-line */
1718
$node
@@ -24,7 +25,7 @@ public function getDefinition(): ArrayNodeDefinition
2425
->isRequired()
2526
->requiresAtLeastOneElement()
2627
->end()
27-
->append($this->resolveTypeSection())
28+
->append($this->resolverSection('typeResolver', 'GraphQL type resolver'))
2829
->append($this->descriptionSection())
2930
->end();
3031

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator\Config;
6+
7+
use InvalidArgumentException;
8+
9+
/**
10+
* @internal
11+
*/
12+
abstract class AbstractConfig
13+
{
14+
protected const NORMALIZERS = [];
15+
16+
public function __construct(array $config)
17+
{
18+
$this->populate($config);
19+
}
20+
21+
protected function populate(array $config): void
22+
{
23+
foreach ($config as $key => $value) {
24+
$property = lcfirst(str_replace('_', '', ucwords($key, '_')));
25+
$normalizer = static::NORMALIZERS[$property] ?? 'normalize'.ucfirst($property);
26+
if (method_exists($this, $normalizer)) {
27+
$this->$property = $this->$normalizer($value);
28+
} elseif (property_exists($this, $property)) {
29+
$this->$property = $value;
30+
} else {
31+
throw new InvalidArgumentException(sprintf('Unknown config "%s".', $property));
32+
}
33+
}
34+
}
35+
36+
/**
37+
* @param array|mixed $value
38+
*/
39+
protected function normalizeCallback($value): Callback
40+
{
41+
return new Callback($value);
42+
}
43+
44+
protected function normalizeValidation(array $config): Validation
45+
{
46+
return new Validation($config);
47+
}
48+
}

src/Generator/Config/Arg.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator\Config;
6+
7+
final class Arg extends AbstractConfig
8+
{
9+
public string $type;
10+
public ?string $description = null;
11+
public ?Validation $validation = null;
12+
13+
/**
14+
* @var mixed
15+
*/
16+
public $defaultValue;
17+
18+
public bool $hasDefaultValue;
19+
20+
public function __construct(array $config)
21+
{
22+
parent::__construct($config);
23+
$this->hasDefaultValue = array_key_exists('defaultValue', $config);
24+
}
25+
}

src/Generator/Config/Callback.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Generator\Config;
6+
7+
final class Callback extends AbstractConfig
8+
{
9+
public ?string $method = null;
10+
public ?string $expression = null;
11+
public ?string $id = null;
12+
}

src/Generator/Config/Config.php

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 Overblog\GraphQLBundle\Generator\Config;
6+
7+
/**
8+
* @internal
9+
*/
10+
final class Config extends AbstractConfig
11+
{
12+
protected const NORMALIZERS = [
13+
'fieldResolver' => 'normalizeCallback',
14+
'typeResolver' => 'normalizeCallback',
15+
// 'fieldsDefaultAccess' => 'normalizeCallback',
16+
// 'isTypeOf' => 'normalizeCallback',
17+
// 'fieldsDefaultPublic' => 'normalizeCallback',
18+
];
19+
20+
public string $name;
21+
public ?string $description = null;
22+
public string $className;
23+
/** @var Field[]|null */
24+
public ?array $fields = null;
25+
public ?array $interfaces = null;
26+
public ?Callback $fieldResolver = null;
27+
public ?Callback $typeResolver = null;
28+
public ?Validation $validation = null;
29+
public ?array $builders = null;
30+
public ?array $types = null;
31+
public ?array $values = null;
32+
/** @var mixed|null */
33+
/*?Callback*/ public $fieldsDefaultAccess = null;
34+
/** @var mixed|null */
35+
/*?Callback*/ public $isTypeOf = null;
36+
/** @var mixed|null */
37+
/*?Callback*/ public $fieldsDefaultPublic = null;
38+
public ?string $scalarType = null;
39+
/** @var callable|null */
40+
public $serialize = null;
41+
/** @var callable|null */
42+
public $parseValue = null;
43+
/** @var callable|null */
44+
public $parseLiteral = null;
45+
46+
protected function normalizeFields(array $fields): array
47+
{
48+
return array_map(fn (array $field) => new Field($field), $fields);
49+
}
50+
}

src/Generator/Config/Field.php

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 Overblog\GraphQLBundle\Generator\Config;
6+
7+
final class Field extends AbstractConfig
8+
{
9+
protected const NORMALIZERS = [
10+
'resolver' => 'normalizeCallback',
11+
// 'access' => 'normalizeCallback',
12+
// 'public' => 'normalizeCallback',
13+
// 'complexity' => 'normalizeCallback',
14+
];
15+
16+
public string $type;
17+
public ?string $description = null;
18+
/** @var Arg[]|null */
19+
public ?array $args = null;
20+
public ?Callback $resolver = null;
21+
/** @var mixed|null */
22+
/*?Callback*/ public $access = null;
23+
/** @var mixed|null */
24+
/*?Callback*/ public $public = null;
25+
/** @var mixed|null */
26+
/*?Callback*/ public $complexity = null;
27+
public ?Validation $validation = null;
28+
public ?array $validationGroups = null;
29+
public ?string $deprecationReason = null;
30+
31+
/**
32+
* @var mixed
33+
*/
34+
public $defaultValue;
35+
36+
public bool $hasDefaultValue;
37+
public bool $hasOnlyType;
38+
39+
public function __construct(array $config)
40+
{
41+
parent::__construct($config);
42+
$this->hasOnlyType = 1 === count($config) && isset($config['type']);
43+
$this->hasDefaultValue = array_key_exists('defaultValue', $config);
44+
}
45+
46+
protected function normalizeArgs(array $args): array
47+
{
48+
return array_map(fn (array $arg) => new Arg($arg), $args);
49+
}
50+
}

0 commit comments

Comments
 (0)