Passed
Pull Request — master (#345)
by
unknown
03:45
created

GraphQL   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 436
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 147
dl 0
loc 436
rs 9.44
c 0
b 0
f 0
wmc 37

17 Methods

Rating   Name   Duplication   Size   Complexity  
B processAsync() 0 53 9
A parse() 0 6 1
A print() 0 6 1
A validate() 0 6 1
A getInstance() 0 7 2
A parseType() 0 6 1
A getContainer() 0 3 1
A execute() 0 22 1
A buildSchema() 0 11 2
B process() 0 53 9
A registerProviders() 0 4 2
A __construct() 0 7 1
A promiseExecute() 0 22 1
A make() 0 5 1
A extendSchema() 0 16 2
A validateSchema() 0 6 1
A parseValue() 0 6 1
1
<?php
2
3
namespace Digia\GraphQL;
4
5
use Digia\GraphQL\Error\Handler\ErrorHandlerInterface;
6
use Digia\GraphQL\Error\InvariantException;
7
use Digia\GraphQL\Execution\ExecutionInterface;
8
use Digia\GraphQL\Execution\ExecutionProvider;
9
use Digia\GraphQL\Execution\ExecutionResult;
10
use Digia\GraphQL\Execution\PromisedExecutionInterface;
11
use Digia\GraphQL\Language\LanguageProvider;
12
use Digia\GraphQL\Language\Node\DocumentNode;
13
use Digia\GraphQL\Language\Node\NodeInterface;
14
use Digia\GraphQL\Language\Node\TypeNodeInterface;
15
use Digia\GraphQL\Language\Node\ValueNodeInterface;
16
use Digia\GraphQL\Language\NodePrinterInterface;
17
use Digia\GraphQL\Language\ParserInterface;
18
use Digia\GraphQL\Language\Source;
19
use Digia\GraphQL\Language\SyntaxErrorException;
20
use Digia\GraphQL\Schema\Building\SchemaBuilderInterface;
21
use Digia\GraphQL\Schema\Building\SchemaBuildingProvider;
22
use Digia\GraphQL\Schema\Extension\SchemaExtenderInterface;
23
use Digia\GraphQL\Schema\Extension\SchemaExtensionProvider;
24
use Digia\GraphQL\Schema\Resolver\ResolverRegistry;
25
use Digia\GraphQL\Schema\Resolver\ResolverRegistryInterface;
26
use Digia\GraphQL\Schema\Schema;
27
use Digia\GraphQL\Schema\Validation\SchemaValidationProvider;
28
use Digia\GraphQL\Schema\Validation\SchemaValidatorInterface;
29
use Digia\GraphQL\Type\CoercerProvider;
30
use Digia\GraphQL\Type\DirectivesProvider;
31
use Digia\GraphQL\Type\IntrospectionProvider;
32
use Digia\GraphQL\Type\ScalarTypesProvider;
33
use Digia\GraphQL\Validation\RulesProvider;
34
use Digia\GraphQL\Validation\ValidationProvider;
35
use Digia\GraphQL\Validation\ValidatorInterface;
36
use League\Container\Container;
37
use React\Promise\PromiseInterface;
38
use function React\Promise\resolve;
39
40
class GraphQL
41
{
42
    public const BOOLEAN = 'GraphQLBoolean';
43
    public const FLOAT   = 'GraphQLFloat';
44
    public const INT     = 'GraphQLInt';
45
    public const ID      = 'GraphQLID';
46
    public const STRING  = 'GraphQLString';
47
48
    public const DEPRECATED_DIRECTIVE = 'GraphQLDeprecatedDirective';
49
    public const INCLUDE_DIRECTIVE    = 'GraphQLIncludeDirective';
50
    public const SKIP_DIRECTIVE       = 'GraphQLSkipDirective';
51
52
    public const SCHEMA_INTROSPECTION             = '__Schema';
53
    public const DIRECTIVE_INTROSPECTION          = '__Directive';
54
    public const DIRECTIVE_LOCATION_INTROSPECTION = '__DirectiveLocation';
55
    public const TYPE_INTROSPECTION               = '__Type';
56
    public const FIELD_INTROSPECTION              = '__Field';
57
    public const INPUT_VALUE_INTROSPECTION        = '__InputValue';
58
    public const ENUM_VALUE_INTROSPECTION         = '__EnumValue';
59
    public const TYPE_KIND_INTROSPECTION          = '__TypeKind';
60
61
    public const SCHEMA_META_FIELD_DEFINITION    = 'SchemaMetaFieldDefinition';
62
    public const TYPE_META_FIELD_DEFINITION      = 'TypeMetaFieldDefinition';
63
    public const TYPE_NAME_META_FIELD_DEFINITION = 'TypeNameMetaFieldDefinition';
64
65
    /**
66
     * @var array
67
     */
68
    private static $providers = [
69
        LanguageProvider::class,
70
        SchemaBuildingProvider::class,
71
        SchemaExtensionProvider::class,
72
        SchemaValidationProvider::class,
73
        CoercerProvider::class,
74
        IntrospectionProvider::class,
75
        ScalarTypesProvider::class,
76
        DirectivesProvider::class,
77
        RulesProvider::class,
78
        ValidationProvider::class,
79
        ExecutionProvider::class,
80
    ];
81
82
    /**
83
     * @var GraphQL
84
     */
85
    private static $instance;
86
87
    /**
88
     * @var Container
89
     */
90
    protected $container;
91
92
    /**
93
     * GraphQL constructor.
94
     */
95
    private function __construct()
96
    {
97
        $container = new Container();
98
99
        $this->registerProviders($container);
100
101
        $this->container = $container;
102
    }
103
104
    /**
105
     * @return GraphQL
106
     */
107
    public static function getInstance(): self
108
    {
109
        if (null === self::$instance) {
110
            self::$instance = new self();
111
        }
112
113
        return self::$instance;
114
    }
115
116
    /**
117
     * @param string $id
118
     * @return mixed
119
     */
120
    public static function make(string $id)
121
    {
122
        return static::getInstance()
123
            ->getContainer()
124
            ->get($id);
125
    }
126
127
    /**
128
     * @param Source                          $source
129
     * @param array|ResolverRegistryInterface $resolverRegistry
130
     * @param array                           $options
131
     * @return Schema
132
     */
133
    public static function buildSchema(Source $source, $resolverRegistry, array $options = []): Schema
134
    {
135
        /** @var SchemaBuilderInterface $schemaBuilder */
136
        $schemaBuilder = static::make(SchemaBuilderInterface::class);
137
138
        return $schemaBuilder->build(
139
            static::parse($source, $options),
140
            $resolverRegistry instanceof ResolverRegistryInterface
141
                ? $resolverRegistry
142
                : new ResolverRegistry($resolverRegistry),
143
            $options
144
        );
145
    }
146
147
    /**
148
     * @param Schema                          $schema
149
     * @param Source                          $source
150
     * @param array|ResolverRegistryInterface $resolverRegistry
151
     * @param array                           $options
152
     * @return Schema
153
     */
154
    public static function extendSchema(
155
        Schema $schema,
156
        Source $source,
157
        $resolverRegistry,
158
        array $options = []
159
    ): Schema {
160
        /** @var SchemaExtenderInterface $schemaExtender */
161
        $schemaExtender = static::make(SchemaExtenderInterface::class);
162
163
        return $schemaExtender->extend(
164
            $schema,
165
            static::parse($source, $options),
166
            $resolverRegistry instanceof ResolverRegistryInterface
167
                ? $resolverRegistry
168
                : new ResolverRegistry($resolverRegistry),
169
            $options
170
        );
171
    }
172
173
    /**
174
     * @param Schema $schema
175
     * @return array
176
     */
177
    public static function validateSchema(Schema $schema): array
178
    {
179
        /** @var SchemaValidatorInterface $schemaValidator */
180
        $schemaValidator = static::make(SchemaValidatorInterface::class);
181
182
        return $schemaValidator->validate($schema);
183
    }
184
185
    /**
186
     * @param Source $source
187
     * @param array  $options
188
     * @return DocumentNode
189
     */
190
    public static function parse(Source $source, array $options = []): DocumentNode
191
    {
192
        /** @var ParserInterface $parser */
193
        $parser = static::make(ParserInterface::class);
194
195
        return $parser->parse($source, $options);
196
    }
197
198
    /**
199
     * @param Source $source
200
     * @param array  $options
201
     * @return ValueNodeInterface
202
     */
203
    public static function parseValue(Source $source, array $options = []): ValueNodeInterface
204
    {
205
        /** @var ParserInterface $parser */
206
        $parser = static::make(ParserInterface::class);
207
208
        return $parser->parseValue($source, $options);
0 ignored issues
show
Bug introduced by
The method parseValue() does not exist on Digia\GraphQL\Language\ParserInterface. Did you maybe mean parse()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
        return $parser->/** @scrutinizer ignore-call */ parseValue($source, $options);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
209
    }
210
211
    /**
212
     * @param Source $source
213
     * @param array  $options
214
     * @return TypeNodeInterface
215
     */
216
    public static function parseType(Source $source, array $options = []): TypeNodeInterface
217
    {
218
        /** @var ParserInterface $parser */
219
        $parser = static::make(ParserInterface::class);
220
221
        return $parser->parseType($source, $options);
0 ignored issues
show
Bug introduced by
The method parseType() does not exist on Digia\GraphQL\Language\ParserInterface. Did you maybe mean parse()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

221
        return $parser->/** @scrutinizer ignore-call */ parseType($source, $options);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
222
    }
223
224
    /**
225
     * @param Schema       $schema
226
     * @param DocumentNode $document
227
     * @return array
228
     */
229
    public static function validate(Schema $schema, DocumentNode $document): array
230
    {
231
        /** @var ValidatorInterface $validator */
232
        $validator = static::make(ValidatorInterface::class);
233
234
        return $validator->validate($schema, $document);
235
    }
236
237
    /**
238
     * @param Schema                     $schema
239
     * @param DocumentNode               $document
240
     * @param mixed                      $rootValue
241
     * @param mixed                      $contextValue
242
     * @param array                      $variableValues
243
     * @param string|null                $operationName
244
     * @param callable|null              $fieldResolver
245
     * @param ErrorHandlerInterface|null $errorHandler
246
     * @return ExecutionResult
247
     */
248
    public static function execute(
249
        Schema $schema,
250
        DocumentNode $document,
251
        $rootValue = null,
252
        $contextValue = null,
253
        array $variableValues = [],
254
        $operationName = null,
255
        callable $fieldResolver = null,
256
        ?ErrorHandlerInterface $errorHandler = null
257
    ): ExecutionResult {
258
        /** @var ExecutionInterface $execution */
259
        $execution = static::make(ExecutionInterface::class);
260
261
        return $execution->execute(
262
            $schema,
263
            $document,
264
            $rootValue,
265
            $contextValue,
266
            $variableValues,
267
            $operationName,
268
            $fieldResolver,
269
            $errorHandler
270
        );
271
    }
272
273
    /**
274
     * @param Schema                     $schema
275
     * @param DocumentNode               $document
276
     * @param mixed                      $rootValue
277
     * @param mixed                      $contextValue
278
     * @param array                      $variableValues
279
     * @param string|null                $operationName
280
     * @param callable|null              $fieldResolver
281
     * @param ErrorHandlerInterface|null $errorHandler
282
     * @return PromiseInterface<ExecutionResult>
283
     */
284
    public static function promiseExecute(
285
        Schema $schema,
286
        DocumentNode $document,
287
        $rootValue = null,
288
        $contextValue = null,
289
        array $variableValues = [],
290
        $operationName = null,
291
        callable $fieldResolver = null,
292
        ?ErrorHandlerInterface $errorHandler = null
293
    ): PromiseInterface {
294
        /** @var PromisedExecutionInterface $execution */
295
        $execution = static::make(ExecutionInterface::class);
296
297
        return $execution->promiseExecute(
298
            $schema,
299
            $document,
300
            $rootValue,
301
            $contextValue,
302
            $variableValues,
303
            $operationName,
304
            $fieldResolver,
305
            $errorHandler
306
        );
307
    }
308
309
    /**
310
     * @param Schema                     $schema
311
     * @param string                     $source
312
     * @param mixed                      $rootValue
313
     * @param mixed                      $contextValue
314
     * @param array                      $variableValues
315
     * @param null|string                $operationName
316
     * @param callable|null              $fieldResolver
317
     * @param ErrorHandlerInterface|null $errorHandler
318
     * @return ExecutionResult
319
     * @throws InvariantException
320
     * @throws SyntaxErrorException
321
     */
322
    public static function process(
323
        Schema $schema,
324
        string $source,
325
        $rootValue = null,
326
        $contextValue = null,
327
        array $variableValues = [],
328
        ?string $operationName = null,
329
        ?callable $fieldResolver = null,
330
        ?ErrorHandlerInterface $errorHandler = null
331
    ): ExecutionResult {
332
        $schemaValidationErrors = validateSchema($schema);
333
334
        if (!empty($schemaValidationErrors)) {
335
            if (null !== $errorHandler) {
336
                foreach ($schemaValidationErrors as $schemaValidationError) {
337
                    $errorHandler->handleError($schemaValidationError);
338
                }
339
            }
340
341
            return new ExecutionResult(null, $schemaValidationErrors);
342
        }
343
344
        try {
345
            $document = parse($source);
346
        } catch (SyntaxErrorException $error) {
347
            if (null !== $errorHandler) {
348
                $errorHandler->handleError($error);
349
            }
350
351
            return new ExecutionResult(null, [$error]);
352
        }
353
354
        $validationErrors = validate($schema, $document);
355
356
        if (!empty($validationErrors)) {
357
            if (null !== $errorHandler) {
358
                foreach ($validationErrors as $validationError) {
359
                    $errorHandler->handleError($validationError);
360
                }
361
            }
362
363
            return new ExecutionResult(null, $validationErrors);
364
        }
365
366
        return execute(
367
            $schema,
368
            $document,
369
            $rootValue,
370
            $contextValue,
371
            $variableValues,
372
            $operationName,
373
            $fieldResolver,
374
            $errorHandler
375
        );
376
    }
377
378
    /**
379
     * @param Schema                     $schema
380
     * @param string                     $source
381
     * @param mixed                      $rootValue
382
     * @param mixed                      $contextValue
383
     * @param array                      $variableValues
384
     * @param null|string                $operationName
385
     * @param callable|null              $fieldResolver
386
     * @param ErrorHandlerInterface|null $errorHandler
387
     * @return PromiseInterface<ExecutionResult>
388
     * @throws InvariantException
389
     * @throws SyntaxErrorException
390
     */
391
    public static function processAsync(
392
        Schema $schema,
393
        string $source,
394
        $rootValue = null,
395
        $contextValue = null,
396
        array $variableValues = [],
397
        ?string $operationName = null,
398
        ?callable $fieldResolver = null,
399
        ?ErrorHandlerInterface $errorHandler = null
400
    ): PromiseInterface {
401
        $schemaValidationErrors = validateSchema($schema);
402
403
        if (!empty($schemaValidationErrors)) {
404
            if (null !== $errorHandler) {
405
                foreach ($schemaValidationErrors as $schemaValidationError) {
406
                    $errorHandler->handleError($schemaValidationError);
407
                }
408
            }
409
410
            return resolve(new ExecutionResult(null, $schemaValidationErrors));
411
        }
412
413
        try {
414
            $document = parse($source);
415
        } catch (SyntaxErrorException $error) {
416
            if (null !== $errorHandler) {
417
                $errorHandler->handleError($error);
418
            }
419
420
            return resolve(new ExecutionResult(null, [$error]));
421
        }
422
423
        $validationErrors = validate($schema, $document);
424
425
        if (!empty($validationErrors)) {
426
            if (null !== $errorHandler) {
427
                foreach ($validationErrors as $validationError) {
428
                    $errorHandler->handleError($validationError);
429
                }
430
            }
431
432
            return resolve(new ExecutionResult(null, $validationErrors));
433
        }
434
435
        return promiseExecute(
436
            $schema,
437
            $document,
438
            $rootValue,
439
            $contextValue,
440
            $variableValues,
441
            $operationName,
442
            $fieldResolver,
443
            $errorHandler
444
        );
445
    }
446
447
    /**
448
     * @param NodeInterface $node
449
     * @return string
450
     */
451
    public static function print(NodeInterface $node): string
452
    {
453
        /** @var NodePrinterInterface $nodePrinter */
454
        $nodePrinter = static::make(NodePrinterInterface::class);
455
456
        return $nodePrinter->print($node);
457
    }
458
459
    /**
460
     * @return Container
461
     */
462
    public function getContainer(): Container
463
    {
464
        return $this->container;
465
    }
466
467
    /**
468
     * Registers the service provides with the container.
469
     *
470
     * @param Container $container
471
     */
472
    protected function registerProviders(Container $container): void
473
    {
474
        foreach (self::$providers as $className) {
475
            $container->addServiceProvider($className);
476
        }
477
    }
478
}
479