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

GraphQLBootloader::boot()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 10
nc 1
nop 11
dl 0
loc 24
ccs 11
cts 11
cp 1
crap 1
rs 9.9332
c 1
b 0
f 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Andi\GraphQL\Spiral\Bootloader;
6
7
use Andi\GraphQL\ArgumentResolver\ArgumentResolver;
8
use Andi\GraphQL\ArgumentResolver\ArgumentResolverInterface;
9
use Andi\GraphQL\InputObjectFieldResolver\InputObjectFieldResolver;
10
use Andi\GraphQL\InputObjectFieldResolver\InputObjectFieldResolverInterface;
11
use Andi\GraphQL\ObjectFieldResolver\Middleware\AbstractObjectFieldByReflectionMethodMiddleware;
12
use Andi\GraphQL\ObjectFieldResolver\Middleware\AbstractOuterObjectFieldByReflectionMethodMiddleware;
13
use Andi\GraphQL\ObjectFieldResolver\Middleware\AdditionalFieldByReflectionMethodMiddleware;
14
use Andi\GraphQL\ObjectFieldResolver\Middleware\InterfaceFieldByReflectionMethodMiddleware;
15
use Andi\GraphQL\ObjectFieldResolver\Middleware\MutationFieldByReflectionMethodMiddleware;
16
use Andi\GraphQL\ObjectFieldResolver\Middleware\ObjectFieldByReflectionMethodMiddleware;
17
use Andi\GraphQL\ObjectFieldResolver\Middleware\QueryFieldByReflectionMethodMiddleware;
18
use Andi\GraphQL\ObjectFieldResolver\ObjectFieldResolver;
19
use Andi\GraphQL\ObjectFieldResolver\ObjectFieldResolverInterface;
20
use Andi\GraphQL\Spiral\Command\ConfigCommand;
21
use Andi\GraphQL\Spiral\Common\SchemaWarmupper;
22
use Andi\GraphQL\Spiral\Config\GraphQLConfig;
23
use Andi\GraphQL\Spiral\Common\ValueResolver;
24
use Andi\GraphQL\Spiral\Listener\AdditionalFieldListener;
25
use Andi\GraphQL\Spiral\Listener\AttributedMutationFieldListener;
26
use Andi\GraphQL\Spiral\Listener\AttributedQueryFieldListener;
27
use Andi\GraphQL\Spiral\Listener\AttributedTypeLoaderListener;
28
use Andi\GraphQL\Spiral\Listener\MutationFieldListener;
29
use Andi\GraphQL\Spiral\Listener\QueryFieldListener;
30
use Andi\GraphQL\Spiral\Listener\TypeLoaderListener;
31
use Andi\GraphQL\Spiral\Middleware\GraphQLMiddleware;
32
use Andi\GraphQL\Type\MutationType;
33
use Andi\GraphQL\Type\QueryType;
34
use Andi\GraphQL\TypeRegistry;
35
use Andi\GraphQL\TypeRegistryInterface;
36
use Andi\GraphQL\TypeResolver\TypeResolver;
37
use Andi\GraphQL\TypeResolver\TypeResolverInterface;
38
use GraphQL\Server\ServerConfig;
39
use GraphQL\Server\StandardServer;
40
use GraphQL\Type\Definition as Webonyx;
41
use GraphQL\Type\Schema;
42
use GraphQL\Type\SchemaConfig;
43
use Psr\Container\ContainerInterface;
44
use Spiral\Attributes\ReaderInterface;
45
use Spiral\Boot\AbstractKernel;
46
use Spiral\Boot\Bootloader\Bootloader;
47
use Spiral\Boot\EnvironmentInterface;
48
use Spiral\Bootloader\Http\HttpBootloader;
49
use Spiral\Config\ConfiguratorInterface;
50
use Spiral\Console\Bootloader\ConsoleBootloader;
51
use Spiral\Core\Internal\Proxy;
52
use Spiral\Core\InvokerInterface;
53
use Spiral\Core\ScopeInterface;
54
use Spiral\Tokenizer\TokenizerListenerRegistryInterface;
55
56
final class GraphQLBootloader extends Bootloader
57
{
58
    protected const SINGLETONS = [
59
        StandardServer::class => [self::class, 'buildStandardServer'],
60
        ServerConfig::class => [self::class, 'buildServerConfig'],
61
        Schema::class => [self::class, 'buildSchema'],
62
        SchemaConfig::class => [self::class, 'buildSchemaConfig'],
63
64
        TypeRegistryInterface::class => TypeRegistry::class,
65
        TypeRegistry::class => [self::class, 'buildTypeRegistry'],
66
67
        TypeResolverInterface::class => TypeResolver::class,
68
        ObjectFieldResolverInterface::class => ObjectFieldResolver::class,
69
        InputObjectFieldResolverInterface::class => InputObjectFieldResolver::class,
70
        ArgumentResolverInterface::class => ArgumentResolver::class,
71
72
        TypeResolver::class => [self::class, 'buildTypeResolver'],
73
        ObjectFieldResolver::class => [self::class, 'buildObjectFieldResolver'],
74
        InputObjectFieldResolver::class => [self::class, 'buildInputObjectFieldResolver'],
75
        ArgumentResolver::class => [self::class, 'buildArgumentResolver'],
76
    ];
77
78
    protected const BINDINGS = [
79
        QueryFieldByReflectionMethodMiddleware::class => [self::class, 'buildQueryFieldByReflectionMethodMiddleware'],
80
        MutationFieldByReflectionMethodMiddleware::class => [self::class, 'buildMutationFieldByReflectionMethodMiddleware'],
81
        AdditionalFieldByReflectionMethodMiddleware::class => [self::class, 'buildAdditionalFieldByReflectionMethodMiddleware'],
82
83
        ObjectFieldByReflectionMethodMiddleware::class => [self::class, 'buildObjectFieldByReflectionMethodMiddleware'],
84
        InterfaceFieldByReflectionMethodMiddleware::class => [self::class, 'buildInterfaceFieldByReflectionMethodMiddleware'],
85
    ];
86
87 7
    public function __construct(
88
        private readonly ConfiguratorInterface $configurator,
89
    ) {
90 7
    }
91
92 7
    public function init(
93
        AbstractKernel $kernel,
94
        EnvironmentInterface $env,
95
        HttpBootloader $http,
96
        ConsoleBootloader $console,
97
    ): void {
98 7
        $this->configurator->setDefaults(GraphQLConfig::CONFIG, [
99 7
            'url' => $env->get('GRAPHQL_URL', '/api/graphql'),
100 7
        ]);
101
102 7
        $http->addMiddleware(GraphQLMiddleware::class);
103
104 7
        $console->addCommand(ConfigCommand::class);
105 7
        $kernel->bootstrapped(static function (Schema $schema): void {
106 7
            SchemaWarmupper::warmup($schema);
107 7
        });
108
    }
109
110 7
    public function boot(
111
        GraphQLConfig $config,
112
        TypeRegistryInterface $typeRegistry,
113
        TypeResolverInterface $typeResolver,
114
        TokenizerListenerRegistryInterface $listenerRegistry,
115
        AttributedTypeLoaderListener $attributedTypeLoaderListener,
116
        TypeLoaderListener $typeLoaderListener,
117
        QueryFieldListener $queryFieldListener,
118
        MutationFieldListener $mutationFieldListener,
119
        AttributedQueryFieldListener $attributedQueryFieldListener,
120
        AttributedMutationFieldListener $attributedMutationFieldListener,
121
        AdditionalFieldListener $additionalFieldListener,
122
    ): void {
123 7
        $this->registerQueryType($config->getQueryType(), $typeRegistry, $typeResolver);
124 7
        $this->registerMutationType($config->getMutationType(), $typeRegistry, $typeResolver);
125 7
        $this->registerAdditionalTypes($config->getAdditionalTypes(), $typeRegistry, $typeResolver);
126
127 7
        $listenerRegistry->addListener($attributedTypeLoaderListener);
128 7
        $listenerRegistry->addListener($typeLoaderListener);
129 7
        $listenerRegistry->addListener($queryFieldListener);
130 7
        $listenerRegistry->addListener($mutationFieldListener);
131 7
        $listenerRegistry->addListener($attributedQueryFieldListener);
132 7
        $listenerRegistry->addListener($attributedMutationFieldListener);
133 7
        $listenerRegistry->addListener($additionalFieldListener);
134
    }
135
136 7
    private function registerQueryType(
137
        string $class,
138
        TypeRegistryInterface $typeRegistry,
139
        TypeResolverInterface $typeResolver,
140
    ): void {
141 7
        if ($typeRegistry->has($class)) {
142
            return;
143
        }
144
145 7
        if (GraphQLConfig::DEFAULT_QUERY_TYPE === $class) {
146 7
            $class = QueryType::class;
147
        }
148
149 7
        $queryType = $typeResolver->resolve($class);
150 7
        \assert($queryType instanceof Webonyx\NamedType);
151 7
        $typeRegistry->register($queryType, $class);
152
    }
153
154 7
    private function registerMutationType(
155
        ?string $class,
156
        TypeRegistryInterface $typeRegistry,
157
        TypeResolverInterface $typeResolver,
158
    ): void {
159 7
        if (null === $class || $typeRegistry->has($class)) {
160 6
            return;
161
        }
162
163 1
        if (GraphQLConfig::DEFAULT_MUTATION_TYPE === $class) {
164 1
            $class = MutationType::class;
165
        }
166
167 1
        $mutationType = $typeResolver->resolve($class);
168 1
        \assert($mutationType instanceof Webonyx\NamedType);
169 1
        $typeRegistry->register($mutationType, $class);
170
    }
171
172 7
    private function registerAdditionalTypes(
173
        array $types,
174
        TypeRegistryInterface $typeRegistry,
175
        TypeResolverInterface $typeResolver,
176
    ): void {
177 7
        foreach ($types as $name => $aliases) {
178 1
            $aliases = (array)$aliases;
179 1
            if (\is_int($name)) {
180 1
                $name = \array_shift($aliases);
181
            }
182
183 1
            $type = $typeResolver->resolve($name);
184 1
            \assert($type instanceof Webonyx\NamedType);
185 1
            $typeRegistry->register($type, $name, ...$aliases);
186
        }
187
    }
188
189 1
    private function buildStandardServer(ServerConfig $config): StandardServer
190
    {
191 1
        return new StandardServer($config);
192
    }
193
194 3
    private function buildServerConfig(
195
        Schema $schema,
196
        GraphQLConfig $config,
197
        ContainerInterface $container,
198
    ): ServerConfig {
199 3
        $serverConfig = (new ServerConfig())->setSchema($schema);
200
201 3
        $scope = Proxy::create(
202 3
            new \ReflectionClass(ScopeInterface::class),
203 3
            null,
204 3
            new \Spiral\Core\Attribute\Proxy(),
205 3
        );
206 3
        $invoker = Proxy::create(
207 3
            new \ReflectionClass(InvokerInterface::class),
208 3
            null,
209 3
            new \Spiral\Core\Attribute\Proxy(),
210 3
        );
211
212 3
        if ($rootValueName = $config->getRootValue()) {
213 2
            $rootValue = $container->get($rootValueName);
214 2
            $rootValueFn = \is_callable($rootValue)
215 1
                ? $rootValue
216 1
                : static fn() => $rootValue;
217
218 2
            $serverConfig->setRootValue(new ValueResolver($scope, $invoker, $rootValueFn));
219
        }
220
221 3
        if ($contextName = $config->getContext()) {
222 2
            $context = $container->get($contextName);
223 2
            $contextFn = \is_callable($context)
224 1
                ? $context
225 1
                : static fn() => $context;
226
227 2
            $serverConfig->setContext(new ValueResolver($scope, $invoker, $contextFn));
228
        }
229
230 3
        $serverConfig->setDebugFlag($config->getDebugFlag());
231
232 3
        return $serverConfig;
233
    }
234
235 7
    private function buildSchema(SchemaConfig $config): Schema
236
    {
237 7
        return new Schema($config);
238
    }
239
240 7
    private function buildSchemaConfig(
241
        GraphQLConfig $config,
242
        TypeRegistryInterface $typeRegistry,
243
    ): SchemaConfig {
244 7
        $schemaConfig = new SchemaConfig();
245 7
        $schemaConfig->setTypeLoader($typeRegistry->get(...));
246 7
        $schemaConfig->setTypes($typeRegistry->getTypes(...));
247
248 7
        $schemaConfig->setQuery($typeRegistry->get($config->getQueryType()));
249
250 7
        $mutationType = $config->getMutationType();
251 7
        if (null !== $mutationType && $typeRegistry->has($mutationType)) {
252 1
            $schemaConfig->setMutation($typeRegistry->get($mutationType));
253
        }
254
255 7
        return $schemaConfig;
256
    }
257
258 7
    private function buildTypeRegistry(): TypeRegistry
259
    {
260 7
        return new TypeRegistry();
261
    }
262
263 7
    private function buildTypeResolver(
264
        ContainerInterface $container,
265
        GraphQLConfig $config,
266
    ): TypeResolver {
267 7
        $typeResolver = new TypeResolver();
268
269 7
        foreach ($config->getTypeResolverMiddlewares() as $name => $priority) {
270 7
            $typeResolver->pipe($container->get($name), $priority);
271
        }
272
273 7
        return $typeResolver;
274
    }
275
276 7
    private function buildObjectFieldResolver(
277
        ContainerInterface $container,
278
        GraphQLConfig $config,
279
    ): ObjectFieldResolver {
280 7
        $objectFieldResolver = new ObjectFieldResolver();
281
282 7
        foreach ($config->getObjectFieldResolverMiddlewares() as $name => $priority) {
283 7
            $objectFieldResolver->pipe($container->get($name), $priority);
284
        }
285
286 7
        return $objectFieldResolver;
287
    }
288
289 7
    private function buildInputObjectFieldResolver(
290
        ContainerInterface $container,
291
        GraphQLConfig $config,
292
    ): InputObjectFieldResolver {
293 7
        $inputObjectFieldResolver = new InputObjectFieldResolver();
294
295 7
        foreach ($config->getInputObjectFieldResolverMiddlewares() as $name => $priority) {
296 7
            $inputObjectFieldResolver->pipe($container->get($name), $priority);
297
        }
298
299 7
        return $inputObjectFieldResolver;
300
    }
301
302 7
    private function buildArgumentResolver(
303
        ContainerInterface $container,
304
        GraphQLConfig $config,
305
    ): ArgumentResolver {
306 7
        $argumentResolver = new ArgumentResolver();
307
308 7
        foreach ($config->getArgumentResolverMiddlewares() as $name => $priority) {
309 7
            $argumentResolver->pipe($container->get($name), $priority);
310
        }
311
312 7
        return $argumentResolver;
313
    }
314
315 7
    private function buildQueryFieldByReflectionMethodMiddleware(
316
        ReaderInterface $reader,
317
        TypeRegistryInterface $typeRegistry,
318
        ArgumentResolverInterface $argumentResolver,
319
    ): QueryFieldByReflectionMethodMiddleware {
320 7
        return $this->buildAbstractOuterObjectFieldByReflectionMethodMiddleware(
321 7
            QueryFieldByReflectionMethodMiddleware::class,
322 7
            $reader,
323 7
            $typeRegistry,
324 7
            $argumentResolver,
325 7
        );
326
    }
327
328 7
    private function buildMutationFieldByReflectionMethodMiddleware(
329
        ReaderInterface $reader,
330
        TypeRegistryInterface $typeRegistry,
331
        ArgumentResolverInterface $argumentResolver,
332
    ): MutationFieldByReflectionMethodMiddleware {
333 7
        return $this->buildAbstractOuterObjectFieldByReflectionMethodMiddleware(
334 7
            MutationFieldByReflectionMethodMiddleware::class,
335 7
            $reader,
336 7
            $typeRegistry,
337 7
            $argumentResolver,
338 7
        );
339
    }
340
341 7
    private function buildAdditionalFieldByReflectionMethodMiddleware(
342
        ReaderInterface $reader,
343
        TypeRegistryInterface $typeRegistry,
344
        ArgumentResolverInterface $argumentResolver,
345
    ): AdditionalFieldByReflectionMethodMiddleware {
346 7
        return $this->buildAbstractOuterObjectFieldByReflectionMethodMiddleware(
347 7
            AdditionalFieldByReflectionMethodMiddleware::class,
348 7
            $reader,
349 7
            $typeRegistry,
350 7
            $argumentResolver,
351 7
        );
352
    }
353
354
    /**
355
     * @param class-string<AbstractOuterObjectFieldByReflectionMethodMiddleware> $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractOut...ectionMethodMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractOuterObjectFieldByReflectionMethodMiddleware>.
Loading history...
356
     */
357 7
    private function buildAbstractOuterObjectFieldByReflectionMethodMiddleware(
358
        string $class,
359
        ReaderInterface $reader,
360
        TypeRegistryInterface $typeRegistry,
361
        ArgumentResolverInterface $argumentResolver,
362
    ): AbstractOuterObjectFieldByReflectionMethodMiddleware {
363 7
        $scope = Proxy::create(
364 7
            new \ReflectionClass(ScopeInterface::class),
365 7
            null,
366 7
            new \Spiral\Core\Attribute\Proxy(),
367 7
        );
368 7
        $invoker = Proxy::create(
369 7
            new \ReflectionClass(InvokerInterface::class),
370 7
            null,
371 7
            new \Spiral\Core\Attribute\Proxy(),
372 7
        );
373
374 7
        return new $class(
375 7
            $reader,
376 7
            $typeRegistry,
377 7
            $argumentResolver,
378 7
            $scope,
379 7
            $invoker,
380 7
        );
381
    }
382
383 7
    private function buildObjectFieldByReflectionMethodMiddleware(
384
        ReaderInterface $reader,
385
        TypeRegistryInterface $typeRegistry,
386
        ArgumentResolverInterface $argumentResolver,
387
    ): ObjectFieldByReflectionMethodMiddleware {
388 7
        return $this->buildAbstractObjectFieldByReflectionMethodMiddleware(
389 7
            ObjectFieldByReflectionMethodMiddleware::class,
390 7
            $reader,
391 7
            $typeRegistry,
392 7
            $argumentResolver,
393 7
        );
394
    }
395
396
397 7
    private function buildInterfaceFieldByReflectionMethodMiddleware(
398
        ReaderInterface $reader,
399
        TypeRegistryInterface $typeRegistry,
400
        ArgumentResolverInterface $argumentResolver,
401
    ): InterfaceFieldByReflectionMethodMiddleware {
402 7
        return $this->buildAbstractObjectFieldByReflectionMethodMiddleware(
403 7
            InterfaceFieldByReflectionMethodMiddleware::class,
404 7
            $reader,
405 7
            $typeRegistry,
406 7
            $argumentResolver,
407 7
        );
408
    }
409
410
    /**
411
     * @param class-string<AbstractObjectFieldByReflectionMethodMiddleware> $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<AbstractObj...ectionMethodMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<AbstractObjectFieldByReflectionMethodMiddleware>.
Loading history...
412
     */
413 7
    private function buildAbstractObjectFieldByReflectionMethodMiddleware(
414
        string $class,
415
        ReaderInterface $reader,
416
        TypeRegistryInterface $typeRegistry,
417
        ArgumentResolverInterface $argumentResolver,
418
    ): AbstractObjectFieldByReflectionMethodMiddleware {
419 7
        $scope = Proxy::create(
420 7
            new \ReflectionClass(ScopeInterface::class),
421 7
            null,
422 7
            new \Spiral\Core\Attribute\Proxy(),
423 7
        );
424 7
        $invoker = Proxy::create(
425 7
            new \ReflectionClass(InvokerInterface::class),
426 7
            null,
427 7
            new \Spiral\Core\Attribute\Proxy(),
428 7
        );
429
430 7
        return new $class(
431 7
            $reader,
432 7
            $typeRegistry,
433 7
            $argumentResolver,
434 7
            $scope,
435 7
            $invoker,
436 7
        );
437
    }
438
}
439