Skip to content

Commit ca5fab2

Browse files
authored
Add strict native type hints for Schema and SchemaConfig (#917)
1 parent c36ff75 commit ca5fab2

11 files changed

+243
-420
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ You can find and compare releases at the [GitHub release page](https://github.co
1717
- Use native PHP types for properties of `Type` and its subclasses
1818
- Throw `SerializationError` over client safe `Error` when failing to serialize leaf types
1919
- Move debug entries in errors under `extensions` key
20+
- Use native PHP types for `Schema` and `SchemaConfig`
2021

2122
### Added
2223

benchmarks/Utils/QueryGenerator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ public function __construct(Schema $schema, float $percentOfLeafFields)
5151

5252
public function buildQuery(): string
5353
{
54-
$qtype = $this->schema->getQueryType();
54+
$queryType = $this->schema->getQueryType();
5555

5656
$ast = new DocumentNode([
5757
'definitions' => new NodeList([
5858
new OperationDefinitionNode([
5959
'name' => new NameNode(['value' => 'TestQuery']),
6060
'operation' => 'query',
61-
'selectionSet' => $this->buildSelectionSet($qtype->getFields()),
61+
'selectionSet' => $this->buildSelectionSet($queryType->getFields()),
6262
'variableDefinitions' => new NodeList([]),
6363
'directives' => new NodeList([]),
6464
]),

src/Executor/ReferenceExecutor.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,11 +607,14 @@ protected function getFieldDef(Schema $schema, ObjectType $parentType, string $f
607607
$schemaMetaFieldDef ??= Introspection::schemaMetaFieldDef();
608608
$typeMetaFieldDef ??= Introspection::typeMetaFieldDef();
609609
$typeNameMetaFieldDef ??= Introspection::typeNameMetaFieldDef();
610-
if ($fieldName === $schemaMetaFieldDef->name && $schema->getQueryType() === $parentType) {
610+
611+
$queryType = $schema->getQueryType();
612+
613+
if ($fieldName === $schemaMetaFieldDef->name && $queryType === $parentType) {
611614
return $schemaMetaFieldDef;
612615
}
613616

614-
if ($fieldName === $typeMetaFieldDef->name && $schema->getQueryType() === $parentType) {
617+
if ($fieldName === $typeMetaFieldDef->name && $queryType === $parentType) {
615618
return $typeMetaFieldDef;
616619
}
617620

src/Type/Schema.php

Lines changed: 48 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -51,38 +51,35 @@
5151
*/
5252
class Schema
5353
{
54-
/** @var SchemaConfig */
55-
private $config;
54+
private SchemaConfig $config;
5655

5756
/**
5857
* Contains currently resolved schema types
5958
*
60-
* @var Type[]
59+
* @var array<string, Type>
6160
*/
62-
private $resolvedTypes = [];
61+
private array $resolvedTypes = [];
6362

6463
/**
6564
* Lazily initialised.
6665
*
6766
* @var array<string, InterfaceImplementations>
6867
*/
69-
private $implementationsMap;
68+
private array $implementationsMap;
7069

7170
/**
72-
* True when $resolvedTypes contain all possible schema types
73-
*
74-
* @var bool
71+
* True when $resolvedTypes contains all possible schema types.
7572
*/
76-
private $fullyLoaded = false;
73+
private bool $fullyLoaded = false;
7774

78-
/** @var Error[] */
79-
private $validationErrors;
75+
/** @var array<int, Error> */
76+
private array $validationErrors;
8077

8178
/** @var array<int, SchemaTypeExtensionNode> */
8279
public $extensionASTNodes = [];
8380

8481
/**
85-
* @param mixed[]|SchemaConfig $config
82+
* @param SchemaConfig|array<string, mixed> $config
8683
*
8784
* @api
8885
*/
@@ -128,31 +125,38 @@ public function __construct($config)
128125
$this->config = $config;
129126
$this->extensionASTNodes = $config->extensionASTNodes;
130127

131-
if ($config->query !== null) {
132-
$this->resolvedTypes[$config->query->name] = $config->query;
128+
// TODO can we make the following assumption hold true?
129+
// No need to check for the existence of the root query type
130+
// since we already validated the schema thus it must exist.
131+
$query = $config->query;
132+
if ($query !== null) {
133+
$this->resolvedTypes[$query->name] = $query;
133134
}
134135

135-
if ($config->mutation !== null) {
136-
$this->resolvedTypes[$config->mutation->name] = $config->mutation;
136+
$mutation = $config->mutation;
137+
if ($mutation !== null) {
138+
$this->resolvedTypes[$mutation->name] = $mutation;
137139
}
138140

139-
if ($config->subscription !== null) {
140-
$this->resolvedTypes[$config->subscription->name] = $config->subscription;
141+
$subscription = $config->subscription;
142+
if ($subscription !== null) {
143+
$this->resolvedTypes[$subscription->name] = $subscription;
141144
}
142145

143146
if (is_array($this->config->types)) {
144147
foreach ($this->resolveAdditionalTypes() as $type) {
145-
if (isset($this->resolvedTypes[$type->name])) {
148+
$typeName = $type->name;
149+
if (isset($this->resolvedTypes[$typeName])) {
146150
Utils::invariant(
147-
$type === $this->resolvedTypes[$type->name],
151+
$type === $this->resolvedTypes[$typeName],
148152
sprintf(
149153
'Schema must contain unique named types but contains multiple types named "%s" (see https://webonyx.github.io/graphql-php/type-definitions/#type-registry).',
150154
$type
151155
)
152156
);
153157
}
154158

155-
$this->resolvedTypes[$type->name] = $type;
159+
$this->resolvedTypes[$typeName] = $type;
156160
}
157161
}
158162

@@ -196,12 +200,11 @@ private function resolveAdditionalTypes(): Generator
196200
}
197201

198202
/**
199-
* Returns array of all types in this schema. Keys of this array represent type names, values are instances
200-
* of corresponding type definitions
203+
* Returns all types in this schema.
201204
*
202-
* This operation requires full schema scan. Do not use in production environment.
205+
* This operation requires a full schema scan. Do not use in production environment.
203206
*
204-
* @return array<string, Type>
207+
* @return array<string, Type> Keys represent type names, values are instances of corresponding type definitions
205208
*
206209
* @api
207210
*/
@@ -216,9 +219,9 @@ public function getTypeMap(): array
216219
}
217220

218221
/**
219-
* @return Type[]
222+
* @return array<Type>
220223
*/
221-
private function collectAllTypes()
224+
private function collectAllTypes(): array
222225
{
223226
$typeMap = [];
224227
foreach ($this->resolvedTypes as $type) {
@@ -246,21 +249,16 @@ private function collectAllTypes()
246249
/**
247250
* Returns a list of directives supported by this schema
248251
*
249-
* @return Directive[]
252+
* @return array<Directive>
250253
*
251254
* @api
252255
*/
253-
public function getDirectives()
256+
public function getDirectives(): array
254257
{
255258
return $this->config->directives ?? GraphQL::getStandardDirectives();
256259
}
257260

258-
/**
259-
* @param string $operation
260-
*
261-
* @return ObjectType|null
262-
*/
263-
public function getOperationType($operation)
261+
public function getOperationType(string $operation): ?ObjectType
264262
{
265263
switch ($operation) {
266264
case 'query':
@@ -278,53 +276,45 @@ public function getOperationType($operation)
278276
}
279277

280278
/**
281-
* Returns schema query type
282-
*
283-
* @return ObjectType|null
279+
* Returns root query type.
284280
*
285281
* @api
286282
*/
287-
public function getQueryType(): ?Type
283+
public function getQueryType(): ?ObjectType
288284
{
289285
return $this->config->query;
290286
}
291287

292288
/**
293-
* Returns schema mutation type
294-
*
295-
* @return ObjectType|null
289+
* Returns root mutation type.
296290
*
297291
* @api
298292
*/
299-
public function getMutationType(): ?Type
293+
public function getMutationType(): ?ObjectType
300294
{
301295
return $this->config->mutation;
302296
}
303297

304298
/**
305299
* Returns schema subscription
306300
*
307-
* @return ObjectType|null
308-
*
309301
* @api
310302
*/
311-
public function getSubscriptionType(): ?Type
303+
public function getSubscriptionType(): ?ObjectType
312304
{
313305
return $this->config->subscription;
314306
}
315307

316308
/**
317-
* @return SchemaConfig
318-
*
319309
* @api
320310
*/
321-
public function getConfig()
311+
public function getConfig(): SchemaConfig
322312
{
323313
return $this->config;
324314
}
325315

326316
/**
327-
* Returns type by its name
317+
* Returns a type by name.
328318
*
329319
* @api
330320
*/
@@ -534,15 +524,15 @@ public function getAstNode(): ?SchemaDefinitionNode
534524
}
535525

536526
/**
537-
* Validates schema.
527+
* Throws if the schema is not valid.
538528
*
539-
* This operation requires full schema scan. Do not use in production environment.
529+
* This operation requires a full schema scan. Do not use in production environment.
540530
*
541531
* @throws InvariantViolation
542532
*
543533
* @api
544534
*/
545-
public function assertValid()
535+
public function assertValid(): void
546536
{
547537
$errors = $this->validate();
548538

@@ -574,18 +564,18 @@ public function assertValid()
574564
}
575565

576566
/**
577-
* Validates schema.
567+
* Validate the schema and return any errors.
578568
*
579-
* This operation requires full schema scan. Do not use in production environment.
569+
* This operation requires a full schema scan. Do not use in production environment.
580570
*
581-
* @return InvariantViolation[]|Error[]
571+
* @return array<int, Error>
582572
*
583573
* @api
584574
*/
585-
public function validate()
575+
public function validate(): array
586576
{
587577
// If this Schema has already been validated, return the previous results.
588-
if ($this->validationErrors !== null) {
578+
if (isset($this->validationErrors)) {
589579
return $this->validationErrors;
590580
}
591581

0 commit comments

Comments
 (0)