GraphQLBootloader::boot()   A
last analyzed

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\ObjectFieldResolver;
12
use Andi\GraphQL\ObjectFieldResolver\ObjectFieldResolverInterface;
13
use Andi\GraphQL\Spiral\Command\ConfigCommand;
14
use Andi\GraphQL\Spiral\Common\SchemaWarmupper;
15
use Andi\GraphQL\Spiral\Config\GraphQLConfig;
16
use Andi\GraphQL\Spiral\Common\ValueResolver;
17
use Andi\GraphQL\Spiral\Listener\AdditionalFieldListener;
18
use Andi\GraphQL\Spiral\Listener\AttributedMutationFieldListener;
19
use Andi\GraphQL\Spiral\Listener\AttributedQueryFieldListener;
20
use Andi\GraphQL\Spiral\Listener\AttributedTypeLoaderListener;
21
use Andi\GraphQL\Spiral\Listener\MutationFieldListener;
22
use Andi\GraphQL\Spiral\Listener\QueryFieldListener;
23
use Andi\GraphQL\Spiral\Listener\TypeLoaderListener;
24
use Andi\GraphQL\Spiral\Middleware\GraphQLMiddleware;
25
use Andi\GraphQL\Type\MutationType;
26
use Andi\GraphQL\Type\QueryType;
27
use Andi\GraphQL\TypeRegistry;
28
use Andi\GraphQL\TypeRegistryInterface;
29
use Andi\GraphQL\TypeResolver\TypeResolver;
30
use Andi\GraphQL\TypeResolver\TypeResolverInterface;
31
use GraphQL\Server\ServerConfig;
32
use GraphQL\Server\StandardServer;
33
use GraphQL\Type\Definition as Webonyx;
34
use GraphQL\Type\Schema;
35
use GraphQL\Type\SchemaConfig;
36
use Psr\Container\ContainerInterface;
37
use Spiral\Boot\AbstractKernel;
38
use Spiral\Boot\Bootloader\Bootloader;
39
use Spiral\Boot\EnvironmentInterface;
40
use Spiral\Bootloader\Http\HttpBootloader;
41
use Spiral\Config\ConfiguratorInterface;
42
use Spiral\Console\Bootloader\ConsoleBootloader;
43
use Spiral\Core\InvokerInterface;
44
use Spiral\Core\ScopeInterface;
45
use Spiral\Tokenizer\TokenizerListenerRegistryInterface;
46
47
final class GraphQLBootloader extends Bootloader
48
{
49
    protected const SINGLETONS = [
50
        StandardServer::class => [self::class, 'buildStandardServer'],
51
        ServerConfig::class => [self::class, 'buildServerConfig'],
52
        Schema::class => [self::class, 'buildSchema'],
53
        SchemaConfig::class => [self::class, 'buildSchemaConfig'],
54
55
        TypeRegistryInterface::class => TypeRegistry::class,
56
        TypeRegistry::class => [self::class, 'buildTypeRegistry'],
57
58
        TypeResolverInterface::class => TypeResolver::class,
59
        ObjectFieldResolverInterface::class => ObjectFieldResolver::class,
60
        InputObjectFieldResolverInterface::class => InputObjectFieldResolver::class,
61
        ArgumentResolverInterface::class => ArgumentResolver::class,
62
63
        TypeResolver::class => [self::class, 'buildTypeResolver'],
64
        ObjectFieldResolver::class => [self::class, 'buildObjectFieldResolver'],
65
        InputObjectFieldResolver::class => [self::class, 'buildInputObjectFieldResolver'],
66
        ArgumentResolver::class => [self::class, 'buildArgumentResolver'],
67
    ];
68
69 7
    public function __construct(
70
        private readonly ConfiguratorInterface $configurator,
71
    ) {
72 7
    }
73
74 7
    public function init(
75
        AbstractKernel $kernel,
76
        EnvironmentInterface $env,
77
        HttpBootloader $http,
78
        ConsoleBootloader $console,
79
    ): void {
80 7
        $this->configurator->setDefaults(GraphQLConfig::CONFIG, [
81 7
            'url' => $env->get('GRAPHQL_URL', '/api/graphql'),
82 7
        ]);
83
84 7
        $http->addMiddleware(GraphQLMiddleware::class);
85
86 7
        $console->addCommand(ConfigCommand::class);
87 7
        $kernel->bootstrapped(static function (Schema $schema): void {
88 7
            SchemaWarmupper::warmup($schema);
89 7
        });
90
    }
91
92 7
    public function boot(
93
        GraphQLConfig $config,
94
        TypeRegistryInterface $typeRegistry,
95
        TypeResolverInterface $typeResolver,
96
        TokenizerListenerRegistryInterface $listenerRegistry,
97
        AttributedTypeLoaderListener $attributedTypeLoaderListener,
98
        TypeLoaderListener $typeLoaderListener,
99
        QueryFieldListener $queryFieldListener,
100
        MutationFieldListener $mutationFieldListener,
101
        AttributedQueryFieldListener $attributedQueryFieldListener,
102
        AttributedMutationFieldListener $attributedMutationFieldListener,
103
        AdditionalFieldListener $additionalFieldListener,
104
    ): void {
105 7
        $this->registerQueryType($config->getQueryType(), $typeRegistry, $typeResolver);
106 7
        $this->registerMutationType($config->getMutationType(), $typeRegistry, $typeResolver);
107 7
        $this->registerAdditionalTypes($config->getAdditionalTypes(), $typeRegistry, $typeResolver);
108
109 7
        $listenerRegistry->addListener($attributedTypeLoaderListener);
110 7
        $listenerRegistry->addListener($typeLoaderListener);
111 7
        $listenerRegistry->addListener($queryFieldListener);
112 7
        $listenerRegistry->addListener($mutationFieldListener);
113 7
        $listenerRegistry->addListener($attributedQueryFieldListener);
114 7
        $listenerRegistry->addListener($attributedMutationFieldListener);
115 7
        $listenerRegistry->addListener($additionalFieldListener);
116
    }
117
118 7
    private function registerQueryType(
119
        string $class,
120
        TypeRegistryInterface $typeRegistry,
121
        TypeResolverInterface $typeResolver,
122
    ): void {
123 7
        if ($typeRegistry->has($class)) {
124
            return;
125
        }
126
127 7
        if (GraphQLConfig::DEFAULT_QUERY_TYPE === $class) {
128 7
            $class = QueryType::class;
129
        }
130
131 7
        $queryType = $typeResolver->resolve($class);
132 7
        \assert($queryType instanceof Webonyx\NamedType);
133 7
        $typeRegistry->register($queryType, $class);
134
    }
135
136 7
    private function registerMutationType(
137
        ?string $class,
138
        TypeRegistryInterface $typeRegistry,
139
        TypeResolverInterface $typeResolver,
140
    ): void {
141 7
        if (null === $class || $typeRegistry->has($class)) {
142 6
            return;
143
        }
144
145 1
        if (GraphQLConfig::DEFAULT_MUTATION_TYPE === $class) {
146 1
            $class = MutationType::class;
147
        }
148
149 1
        $mutationType = $typeResolver->resolve($class);
150 1
        \assert($mutationType instanceof Webonyx\NamedType);
151 1
        $typeRegistry->register($mutationType, $class);
152
    }
153
154 7
    private function registerAdditionalTypes(
155
        array $types,
156
        TypeRegistryInterface $typeRegistry,
157
        TypeResolverInterface $typeResolver,
158
    ): void {
159 7
        foreach ($types as $name => $aliases) {
160 1
            $aliases = (array) $aliases;
161 1
            if (\is_int($name)) {
162 1
                $name = \array_shift($aliases);
163
            }
164
165 1
            $type = $typeResolver->resolve($name);
166 1
            \assert($type instanceof Webonyx\NamedType);
167 1
            $typeRegistry->register($type, $name, ...$aliases);
168
        }
169
    }
170
171 1
    private function buildStandardServer(ServerConfig $config): StandardServer
172
    {
173 1
        return new StandardServer($config);
174
    }
175
176 3
    private function buildServerConfig(
177
        Schema $schema,
178
        GraphQLConfig $config,
179
        ContainerInterface $container,
180
        ScopeInterface $scope,
181
        InvokerInterface $invoker,
182
    ): ServerConfig {
183 3
        $serverConfig = (new ServerConfig())->setSchema($schema);
184
185 3
        if ($rootValueName = $config->getRootValue()) {
186 2
            $rootValue = $container->get($rootValueName);
187 2
            $rootValueFn = \is_callable($rootValue)
188 1
                ? $rootValue
189 1
                : static fn () => $rootValue;
190
191 2
            $serverConfig->setRootValue(new ValueResolver($scope, $invoker, $rootValueFn));
192
        }
193
194 3
        if ($contextName = $config->getContext()) {
195 2
            $context = $container->get($contextName);
196 2
            $contextFn = \is_callable($context)
197 1
                ? $context
198 1
                : static fn () => $context;
199
200 2
            $serverConfig->setContext(new ValueResolver($scope, $invoker, $contextFn));
201
        }
202
203 3
        $serverConfig->setDebugFlag($config->getDebugFlag());
204
205 3
        return $serverConfig;
206
    }
207
208 7
    private function buildSchema(SchemaConfig $config): Schema
209
    {
210 7
        return new Schema($config);
211
    }
212
213 7
    private function buildSchemaConfig(
214
        GraphQLConfig $config,
215
        TypeRegistryInterface $typeRegistry,
216
    ): SchemaConfig {
217 7
        $schemaConfig = new SchemaConfig();
218 7
        $schemaConfig->setTypeLoader($typeRegistry->get(...));
219 7
        $schemaConfig->setTypes($typeRegistry->getTypes(...));
220
221 7
        $schemaConfig->setQuery($typeRegistry->get($config->getQueryType()));
222
223 7
        $mutationType = $config->getMutationType();
224 7
        if (null !== $mutationType && $typeRegistry->has($mutationType)) {
225 1
            $schemaConfig->setMutation($typeRegistry->get($mutationType));
226
        }
227
228 7
        return $schemaConfig;
229
    }
230
231 7
    private function buildTypeRegistry(): TypeRegistry
232
    {
233 7
        return new TypeRegistry();
234
    }
235
236 7
    private function buildTypeResolver(
237
        ContainerInterface $container,
238
        GraphQLConfig $config,
239
    ): TypeResolver {
240 7
        $typeResolver = new TypeResolver();
241
242 7
        foreach ($config->getTypeResolverMiddlewares() as $name => $priority) {
243 7
            $typeResolver->pipe($container->get($name), $priority);
244
        }
245
246 7
        return $typeResolver;
247
    }
248
249 7
    private function buildObjectFieldResolver(
250
        ContainerInterface $container,
251
        GraphQLConfig $config,
252
    ): ObjectFieldResolver {
253 7
        $objectFieldResolver = new ObjectFieldResolver();
254
255 7
        foreach ($config->getObjectFieldResolverMiddlewares() as $name => $priority) {
256 7
            $objectFieldResolver->pipe($container->get($name), $priority);
257
        }
258
259 7
        return $objectFieldResolver;
260
    }
261
262 7
    private function buildInputObjectFieldResolver(
263
        ContainerInterface $container,
264
        GraphQLConfig $config,
265
    ): InputObjectFieldResolver {
266 7
        $inputObjectFieldResolver = new InputObjectFieldResolver();
267
268 7
        foreach ($config->getInputObjectFieldResolverMiddlewares() as $name => $priority) {
269 7
            $inputObjectFieldResolver->pipe($container->get($name), $priority);
270
        }
271
272 7
        return $inputObjectFieldResolver;
273
    }
274
275 7
    private function buildArgumentResolver(
276
        ContainerInterface $container,
277
        GraphQLConfig $config,
278
    ): ArgumentResolver {
279 7
        $argumentResolver = new ArgumentResolver();
280
281 7
        foreach ($config->getArgumentResolverMiddlewares() as $name => $priority) {
282 7
            $argumentResolver->pipe($container->get($name), $priority);
283
        }
284
285 7
        return $argumentResolver;
286
    }
287
}
288