Passed
Pull Request — master (#318)
by Sam
03:54
created

GraphQL::print()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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

205
        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...
206
    }
207
208
    /**
209
     * @param Source $source
210
     * @param array  $options
211
     * @return TypeNodeInterface
212
     */
213
    public static function parseType(Source $source, array $options = []): TypeNodeInterface
214
    {
215
        /** @var ParserInterface $parser */
216
        $parser = static::make(ParserInterface::class);
217
218
        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

218
        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...
219
    }
220
221
    /**
222
     * @param Schema       $schema
223
     * @param DocumentNode $document
224
     * @return array
225
     */
226
    public static function validate(Schema $schema, DocumentNode $document): array
227
    {
228
        /** @var ValidatorInterface $validator */
229
        $validator = static::make(ValidatorInterface::class);
230
231
        return $validator->validate($schema, $document);
232
    }
233
234
    /**
235
     * @param Schema                     $schema
236
     * @param DocumentNode               $document
237
     * @param mixed                      $rootValue
238
     * @param mixed                      $contextValue
239
     * @param array                      $variableValues
240
     * @param string|null                $operationName
241
     * @param callable|null              $fieldResolver
242
     * @param ErrorHandlerInterface|null $errorHandler
243
     * @return ExecutionResult
244
     */
245
    public static function execute(
246
        Schema $schema,
247
        DocumentNode $document,
248
        $rootValue = null,
249
        $contextValue = null,
250
        array $variableValues = [],
251
        $operationName = null,
252
        callable $fieldResolver = null,
253
        ?ErrorHandlerInterface $errorHandler = null
254
    ): ExecutionResult {
255
        /** @var ExecutionInterface $execution */
256
        $execution = static::make(ExecutionInterface::class);
257
258
        return $execution->execute(
259
            $schema,
260
            $document,
261
            $rootValue,
262
            $contextValue,
263
            $variableValues,
264
            $operationName,
265
            $fieldResolver,
266
            $errorHandler
267
        );
268
    }
269
270
    /**
271
     * @param Schema                     $schema
272
     * @param string                     $source
273
     * @param mixed                      $rootValue
274
     * @param mixed                      $contextValue
275
     * @param array                      $variableValues
276
     * @param null|string                $operationName
277
     * @param callable|null              $fieldResolver
278
     * @param ErrorHandlerInterface|null $errorHandler
279
     * @return ExecutionResult
280
     * @throws InvariantException
281
     * @throws SyntaxErrorException
282
     */
283
    public static function process(
284
        Schema $schema,
285
        string $source,
286
        $rootValue = null,
287
        $contextValue = null,
288
        array $variableValues = [],
289
        ?string $operationName = null,
290
        ?callable $fieldResolver = null,
291
        ?ErrorHandlerInterface $errorHandler = null
292
    ): ExecutionResult {
293
        $schemaValidationErrors = validateSchema($schema);
294
295
        if (!empty($schemaValidationErrors)) {
296
            if (null !== $errorHandler) {
297
                foreach ($schemaValidationErrors as $schemaValidationError) {
298
                    $errorHandler->handleError($schemaValidationError);
299
                }
300
            }
301
302
            return new ExecutionResult(null, $schemaValidationErrors);
303
        }
304
305
        try {
306
            $document = parse($source);
307
        } catch (SyntaxErrorException $error) {
308
            if (null !== $errorHandler) {
309
                $errorHandler->handleError($error);
310
            }
311
312
            return new ExecutionResult(null, [$error]);
313
        }
314
315
        $validationErrors = validate($schema, $document);
316
317
        if (!empty($validationErrors)) {
318
            if (null !== $errorHandler) {
319
                foreach ($validationErrors as $validationError) {
320
                    $errorHandler->handleError($validationError);
321
                }
322
            }
323
324
            return new ExecutionResult(null, $validationErrors);
325
        }
326
327
        return execute(
328
            $schema,
329
            $document,
330
            $rootValue,
331
            $contextValue,
332
            $variableValues,
333
            $operationName,
334
            $fieldResolver,
335
            $errorHandler
336
        );
337
    }
338
339
    /**
340
     * @param NodeInterface $node
341
     * @return string
342
     */
343
    public static function print(NodeInterface $node): string
344
    {
345
        /** @var NodePrinterInterface $nodePrinter */
346
        $nodePrinter = static::make(NodePrinterInterface::class);
347
348
        return $nodePrinter->print($node);
349
    }
350
351
    /**
352
     * @return Container
353
     */
354
    public function getContainer(): Container
355
    {
356
        return $this->container;
357
    }
358
359
    /**
360
     * Registers the service provides with the container.
361
     *
362
     * @param Container $container
363
     */
364
    protected function registerProviders(Container $container): void
365
    {
366
        foreach (self::$providers as $className) {
367
            $container->addServiceProvider($className);
368
        }
369
    }
370
}
371