Passed
Pull Request — master (#256)
by Sam
02:41
created

assertOutputType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Digia\GraphQL\Type;
4
5
use Digia\GraphQL\Error\InvariantException;
6
use Digia\GraphQL\Schema\Schema;
7
use Digia\GraphQL\Type\Definition\Argument;
8
use Digia\GraphQL\Type\Definition\Directive;
9
use Digia\GraphQL\Type\Definition\EnumType;
10
use Digia\GraphQL\Type\Definition\EnumValue;
11
use Digia\GraphQL\Type\Definition\Field;
12
use Digia\GraphQL\Type\Definition\InputField;
13
use Digia\GraphQL\Type\Definition\InputObjectType;
14
use Digia\GraphQL\Type\Definition\InputTypeInterface;
15
use Digia\GraphQL\Type\Definition\InterfaceType;
16
use Digia\GraphQL\Type\Definition\ListType;
17
use Digia\GraphQL\Type\Definition\NamedTypeInterface;
18
use Digia\GraphQL\Type\Definition\NonNullType;
19
use Digia\GraphQL\Type\Definition\ObjectType;
20
use Digia\GraphQL\Type\Definition\OutputTypeInterface;
21
use Digia\GraphQL\Type\Definition\ScalarType;
22
use Digia\GraphQL\Type\Definition\TypeInterface;
23
use Digia\GraphQL\Type\Definition\UnionType;
24
use Digia\GraphQL\Type\Definition\WrappingTypeInterface;
25
use function Digia\GraphQL\Util\invariant;
26
use function Digia\GraphQL\Util\toString;
27
28
/**
29
 * @param callable|array|null $maybeThunk
30
 * @return null|array
31
 */
32
function resolveThunk($maybeThunk)
33
{
34
    return \is_callable($maybeThunk) ? $maybeThunk() : $maybeThunk;
0 ignored issues
show
Bug Best Practice introduced by
The expression return is_callable($mayb...beThunk() : $maybeThunk also could return the type callable which is incompatible with the documented return type null|array.
Loading history...
35
}
36
37
/**
38
 * @param mixed $value
39
 * @return bool
40
 */
41
function isAssocArray($value): bool
42
{
43
    if (!\is_array($value)) {
44
        return false;
45
    }
46
    if (empty($value)) {
47
        return true;
48
    }
49
    $keys = \array_keys($value);
50
    return $keys !== \array_keys($keys);
51
}
52
53
/**
54
 * @param mixed $type
55
 * @throws InvariantException
56
 */
57
function assertType($type)
58
{
59
    invariant(
60
        $type instanceof TypeInterface,
61
        \sprintf('Expected %s to be a GraphQL type.', toString($type))
62
    );
63
}
64
65
/**
66
 * Whether a type is an input type cannot be determined with `instanceof`
67
 * because lists and non-nulls can also be output types if the wrapped type is an output type.
68
 *
69
 * @param TypeInterface|null $type
70
 * @return bool
71
 */
72
function isInputType(?TypeInterface $type): bool
73
{
74
    return null !== $type &&
75
        ($type instanceof InputTypeInterface ||
76
            ($type instanceof WrappingTypeInterface && isInputType($type->getOfType())));
77
}
78
79
/**
80
 * Whether a type is an output type cannot be determined with `instanceof`
81
 * because lists and non-nulls can also be output types if the wrapped type is an output type.
82
 *
83
 * @param TypeInterface|null $type
84
 * @return bool
85
 */
86
function isOutputType(?TypeInterface $type): bool
87
{
88
    return null !== $type &&
89
        ($type instanceof OutputTypeInterface ||
90
            ($type instanceof WrappingTypeInterface && isOutputType($type->getOfType())));
91
}
92
93
/**
94
 * @param TypeInterface|null $type
95
 * @return TypeInterface|null
96
 */
97
function getNullableType(?TypeInterface $type): ?TypeInterface
98
{
99
    if (null === $type) {
100
        return null;
101
    }
102
103
    return $type instanceof NonNullType ? $type->getOfType() : $type;
104
}
105
106
/**
107
 * @param TypeInterface|null $type
108
 * @return NamedTypeInterface|null
109
 */
110
function getNamedType(?TypeInterface $type): ?NamedTypeInterface
111
{
112
    if (!$type) {
113
        return null;
114
    }
115
116
    $unwrappedType = $type;
117
118
    while ($unwrappedType instanceof WrappingTypeInterface) {
119
        $unwrappedType = $unwrappedType->getOfType();
120
    }
121
122
    return $unwrappedType;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $unwrappedType returns the type Digia\GraphQL\Type\Definition\TypeInterface which includes types incompatible with the type-hinted return null|Digia\GraphQL\Type\...tion\NamedTypeInterface.
Loading history...
123
}
124
125
/**
126
 * Returns a new Scalar type after ensuring that its state is valid.
127
 *
128
 * @param array $config
129
 * @return ScalarType
130
 * @throws InvariantException
131
 */
132
function newScalarType(array $config = []): ScalarType
133
{
134
    invariant(isset($config['name']), 'Must provide name.');
135
136
    invariant(
137
        isset($config['serialize']) && \is_callable($config['serialize']),
138
        \sprintf(
139
            '%s must provide "serialize" function. If this custom Scalar ' .
140
            'is also used as an input type, ensure "parseValue" and "parseLiteral" ' .
141
            'functions are also provided.',
142
            $config['name']
143
        )
144
    );
145
146
    if (isset($config['parseValue']) || isset($config['parseLiteral'])) {
147
        invariant(
148
            (isset($config['parseValue']) && \is_callable($config['parseValue'])) &&
149
            (isset($config['parseLiteral']) && \is_callable($config['parseLiteral'])),
150
            \sprintf('%s must provide both "parseValue" and "parseLiteral" functions.', $config['name'])
151
        );
152
    }
153
154
    return new ScalarType(
155
        $config['name'],
156
        $config['description'] ?? null,
157
        $config['serialize'],
158
        $config['parseValue'] ?? null,
159
        $config['parseLiteral'] ?? null,
160
        $config['astNode'] ?? null
161
    );
162
}
163
164
/**
165
 * Returns a new Enum type after ensuring that its state is valid.
166
 *
167
 * @param array $config
168
 * @return EnumType
169
 * @throws InvariantException
170
 */
171
function newEnumType(array $config = []): EnumType
172
{
173
    invariant(isset($config['name']), 'Must provide name.');
174
175
    return new EnumType(
176
        $config['name'],
177
        $config['description'] ?? null,
178
        $config['values'] ?? [],
179
        $config['astNode'] ?? null
180
    );
181
}
182
183
/**
184
 * Returns a new Enum value after ensuring that its state is valid.
185
 *
186
 * @param array $config
187
 * @return EnumValue
188
 * @throws InvariantException
189
 */
190
function newEnumValue(array $config = []): EnumValue
191
{
192
    invariant(isset($config['name']), 'Must provide name.');
193
194
    return new EnumValue(
195
        $config['name'],
196
        $config['description'] ?? null,
197
        $config['deprecationReason'] ?? null,
198
        $config['astNode'] ?? null,
199
        $config['value'] ?? null
200
    );
201
}
202
203
/**
204
 * Returns a new Input Object type after ensuring that its state is valid.
205
 *
206
 * @param array $config
207
 * @return InputObjectType
208
 * @throws InvariantException
209
 */
210
function newInputObjectType(array $config = []): InputObjectType
211
{
212
    invariant(isset($config['name']), 'Must provide name.');
213
214
    return new InputObjectType(
215
        $config['name'],
216
        $config['description'] ?? null,
217
        $config['fields'] ?? [],
218
        $config['astNode'] ?? null
219
    );
220
}
221
222
/**
223
 * Returns a new Input field after ensuring that its state is valid.
224
 *
225
 * @param array $config
226
 * @return InputField
227
 * @throws InvariantException
228
 */
229
function newInputField(array $config = []): InputField
230
{
231
    invariant(isset($config['name']), 'Must provide name.');
232
233
    return new InputField(
234
        $config['name'],
235
        $config['description'] ?? null,
236
        $config['type'] ?? null,
237
        $config['defaultValue'] ?? null,
238
        $config['astNode'] ?? null
239
    );
240
}
241
242
/**
243
 * Returns a new Interface type after ensuring that its state is valid.
244
 *
245
 * @param array $config
246
 * @return InterfaceType
247
 * @throws InvariantException
248
 */
249
function newInterfaceType(array $config = []): InterfaceType
250
{
251
    invariant(isset($config['name']), 'Must provide name.');
252
253
    invariant(
254
        !isset($config['resolveType']) || null === $config['resolveType'] || \is_callable($config['resolveType']),
255
        \sprintf('%s must provide "resolveType" as a function.', $config['name'])
256
    );
257
258
    return new InterfaceType(
259
        $config['name'],
260
        $config['description'] ?? null,
261
        $config['fields'] ?? [],
262
        $config['resolveType'] ?? null,
263
        $config['astNode'] ?? null,
264
        $config['extensionASTNodes'] ?? []
265
    );
266
}
267
268
/**
269
 * Returns a new Object type after ensuring that its state is valid.
270
 *
271
 * @param array $config
272
 * @return ObjectType
273
 * @throws InvariantException
274
 */
275
function newObjectType(array $config = []): ObjectType
276
{
277
    invariant(isset($config['name']), 'Must provide name.');
278
279
    if (isset($config['isTypeOf'])) {
280
        invariant(
281
            \is_callable($config['isTypeOf']),
282
            \sprintf('%s must provide "isTypeOf" as a function.', $config['name'])
283
        );
284
    }
285
286
    return new ObjectType(
287
        $config['name'],
288
        $config['description'] ?? null,
289
        $config['fields'] ?? [],
290
        $config['interfaces'] ?? [],
291
        $config['isTypeOf'] ?? null,
292
        $config['astNode'] ?? null,
293
        $config['extensionASTNodes'] ?? []
294
    );
295
}
296
297
/**
298
 * Returns a new Field after ensuring that its state is valid.
299
 *
300
 * @param array $config
301
 * @return Field
302
 * @throws InvariantException
303
 */
304
function newField(array $config = []): Field
305
{
306
    invariant(isset($config['name']), 'Must provide name.');
307
308
    return new Field(
309
        $config['name'],
310
        $config['description'] ?? null,
311
        $config['type'] ?? null,
312
        $config['args'] ?? [],
313
        $config['resolve'] ?? null,
314
        $config['subscribe'] ?? null,
315
        $config['deprecationReason'] ?? null,
316
        $config['astNode'] ?? null,
317
        $config['typeName'] ?? ''
318
    );
319
}
320
321
/**
322
 * Returns a new Argument after ensuring that its state is valid.
323
 *
324
 * @param array $config
325
 * @return Argument
326
 * @throws InvariantException
327
 */
328
function newArgument(array $config = []): Argument
329
{
330
    invariant(isset($config['name']), 'Must provide name.');
331
332
    return new Argument(
333
        $config['name'],
334
        $config['description'] ?? null,
335
        $config['type'] ?? null,
336
        $config['defaultValue'] ?? null,
337
        $config['astNode'] ?? null
338
    );
339
}
340
341
/**
342
 * Returns a new Union type after ensuring that its state is valid.
343
 *
344
 * @param array $config
345
 * @return UnionType
346
 * @throws InvariantException
347
 */
348
function newUnionType(array $config = []): UnionType
349
{
350
    invariant(isset($config['name']), 'Must provide name.');
351
352
    if (isset($config['resolveType'])) {
353
        invariant(
354
            \is_callable($config['resolveType']),
355
            \sprintf('%s must provide "resolveType" as a function.', $config['name'])
356
        );
357
    }
358
359
    return new UnionType(
360
        $config['name'],
361
        $config['description'] ?? null,
362
        $config['types'] ?? [],
363
        $config['resolveType'] ?? null,
364
        $config['astNode'] ?? null
365
    );
366
}
367
368
/**
369
 * Returns a new Schema after ensuring that its state is valid.
370
 *
371
 * @param array $config
372
 * @return Schema
373
 * @throws InvariantException
374
 */
375
function newSchema(array $config = []): Schema
376
{
377
    if (!isset($config['assumeValid']) || !$config['assumeValid']) {
378
        if (isset($config['types'])) {
379
            invariant(
380
                \is_array($config['types']),
381
                \sprintf('"types" must be Array if provided but got: %s.', toString($config['types']))
382
            );
383
        }
384
385
        if (isset($config['directives'])) {
386
            invariant(
387
                \is_array($config['directives']),
388
                \sprintf('"directives" must be Array if provided but got: %s.', toString($config['directives']))
389
            );
390
        }
391
    }
392
393
    return new Schema(
394
        $config['query'] ?? null,
395
        $config['mutation'] ?? null,
396
        $config['subscription'] ?? null,
397
        $config['types'] ?? [],
398
        $config['directives'] ?? [],
399
        $config['assumeValid'] ?? false,
400
        $config['astNode'] ?? null
401
    );
402
}
403
404
/**
405
 * Returns a new Directive after ensuring that its state is valid.
406
 *
407
 * @param array $config
408
 * @return Directive
409
 * @throws InvariantException
410
 */
411
function newDirective(array $config = []): Directive
412
{
413
    invariant(isset($config['name']), 'Must provide name.');
414
415
    invariant(
416
        isset($config['locations']) && \is_array($config['locations']),
417
        'Must provide locations for directive.'
418
    );
419
420
    return new Directive(
421
        $config['name'],
422
        $config['description'] ?? null,
423
        $config['locations'],
424
        $config['args'] ?? [],
425
        $config['astNode'] ?? null,
426
        $config['typeName'] ?? ''
427
    );
428
}
429
430
/**
431
 * Returns a new List type after ensuring that its state is valid.
432
 *
433
 * @param mixed $ofType
434
 * @return ListType
435
 * @throws InvariantException
436
 */
437
function newList($ofType): ListType
438
{
439
    assertType($ofType);
440
441
    return new ListType($ofType);
442
}
443
444
/**
445
 * Returns a new Non-null type after ensuring that its state is valid.
446
 *
447
 * @param mixed $ofType
448
 * @return NonNullType
449
 * @throws InvariantException
450
 */
451
function newNonNull($ofType): NonNullType
452
{
453
    if ($ofType instanceof NonNullType) {
454
        throw new InvariantException(\sprintf('Expected %s to be a GraphQL nullable type.', toString($ofType)));
455
    }
456
457
    return new NonNullType($ofType);
458
}
459