Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — 0.14 ( 6c4d30 )
by Jérémiah
97:45 queued 93:57
created

OverblogGraphQLExtension   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 260
Duplicated Lines 0 %

Test Coverage

Coverage 98.79%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 133
c 1
b 0
f 0
dl 0
loc 260
ccs 163
cts 165
cp 0.9879
rs 9.52
wmc 36

19 Methods

Rating   Name   Duplication   Size   Complexity  
A setBatchingMethod() 0 3 1
A setDefaultFieldResolver() 0 3 1
A setSecurity() 0 11 3
A setProfilerParameters() 0 3 1
A setCompilerCacheWarmer() 0 8 1
A setSchemaBuilderArguments() 0 4 1
A setErrorHandler() 0 31 4
A loadConfigFiles() 0 12 1
A setDefinitionParameters() 0 8 1
A setConfigBuilders() 0 7 4
A setDebugListener() 0 6 2
A buildExceptionMap() 0 15 3
A load() 0 23 1
A getAlias() 0 3 1
A setClassLoaderListener() 0 12 2
A setServicesAliases() 0 6 3
A setSchemaArguments() 0 32 3
A getConfiguration() 0 7 2
A registerForAutoconfiguration() 0 10 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\DependencyInjection;
6
7
use Closure;
8
use GraphQL\Error\UserError;
9
use GraphQL\Type\Definition\Type;
10
use GraphQL\Type\Schema;
11
use Overblog\GraphQLBundle\CacheWarmer\CompileCacheWarmer;
12
use Overblog\GraphQLBundle\Config\Processor\BuilderProcessor;
13
use Overblog\GraphQLBundle\Definition\Builder\SchemaBuilder;
14
use Overblog\GraphQLBundle\Definition\Resolver\MutationInterface;
15
use Overblog\GraphQLBundle\Definition\Resolver\QueryInterface;
16
use Overblog\GraphQLBundle\Error\ErrorHandler;
17
use Overblog\GraphQLBundle\Error\ExceptionConverter;
18
use Overblog\GraphQLBundle\Error\ExceptionConverterInterface;
19
use Overblog\GraphQLBundle\Error\UserWarning;
20
use Overblog\GraphQLBundle\Event\Events;
21
use Overblog\GraphQLBundle\EventListener\ClassLoaderListener;
22
use Overblog\GraphQLBundle\EventListener\DebugListener;
23
use Overblog\GraphQLBundle\EventListener\ErrorHandlerListener;
24
use Overblog\GraphQLBundle\EventListener\ErrorLoggerListener;
25
use Overblog\GraphQLBundle\Request\Executor;
26
use Symfony\Component\Config\FileLocator;
27
use Symfony\Component\DependencyInjection\ContainerBuilder;
28
use Symfony\Component\DependencyInjection\ContainerInterface;
29
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
30
use Symfony\Component\DependencyInjection\Reference;
31
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
32
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
33
use function array_fill_keys;
34
use function realpath;
35
use function sprintf;
36
37
class OverblogGraphQLExtension extends Extension
38
{
39 43
    public function load(array $configs, ContainerBuilder $container): void
40
    {
41 43
        $this->loadConfigFiles($container);
42 43
        $configuration = $this->getConfiguration($configs, $container);
43 43
        $config = $this->processConfiguration($configuration, $configs);
44
45 43
        $this->setBatchingMethod($config, $container);
46 43
        $this->setServicesAliases($config, $container);
47 43
        $this->setSchemaBuilderArguments($config, $container);
48 43
        $this->setSchemaArguments($config, $container);
49 43
        $this->setErrorHandler($config, $container);
50 43
        $this->setSecurity($config, $container);
51 43
        $this->setConfigBuilders($config, $container);
52 43
        $this->setDebugListener($config, $container);
53 43
        $this->setDefinitionParameters($config, $container);
54 43
        $this->setProfilerParameters($config, $container);
55 43
        $this->setClassLoaderListener($config, $container);
56 43
        $this->setCompilerCacheWarmer($config, $container);
57 43
        $this->registerForAutoconfiguration($container);
58 43
        $this->setDefaultFieldResolver($config, $container);
59
60 43
        $container->setParameter($this->getAlias().'.config', $config);
61 43
        $container->setParameter($this->getAlias().'.resources_dir', realpath(__DIR__.'/../Resources'));
62 43
    }
63
64 43
    public function getAlias(): string
65
    {
66 43
        return Configuration::NAME;
67
    }
68
69 43
    public function getConfiguration(array $config, ContainerBuilder $container): Configuration
70
    {
71 43
        return new Configuration(
72
            // @phpstan-ignore-next-line
73 43
            $container->getParameter('kernel.debug'),
74
            // @phpstan-ignore-next-line
75 43
            $container->hasParameter('kernel.cache_dir') ? $container->getParameter('kernel.cache_dir') : null
76
        );
77
    }
78
79 43
    private function loadConfigFiles(ContainerBuilder $container): void
80
    {
81 43
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
82 43
        $loader->load('services.yaml');
83 43
        $loader->load('commands.yaml');
84 43
        $loader->load('listeners.yaml');
85 43
        $loader->load('graphql_types.yaml');
86 43
        $loader->load('graphql_resolvers.yaml');
87 43
        $loader->load('expression_language_functions.yaml');
88 43
        $loader->load('definition_config_processors.yaml');
89 43
        $loader->load('aliases.yaml');
90 43
        $loader->load('profiler.yaml');
91 43
    }
92
93 43
    private function registerForAutoconfiguration(ContainerBuilder $container): void
94
    {
95 43
        $container->registerForAutoconfiguration(MutationInterface::class)
96 43
            ->addTag('overblog_graphql.mutation');
97
98 43
        $container->registerForAutoconfiguration(QueryInterface::class)
99 43
            ->addTag('overblog_graphql.query');
100
101 43
        $container->registerForAutoconfiguration(Type::class)
102 43
            ->addTag('overblog_graphql.type');
103 43
    }
104
105 43
    private function setDefaultFieldResolver(array $config, ContainerBuilder $container): void
106
    {
107 43
        $container->setAlias($this->getAlias().'.default_field_resolver', $config['definitions']['default_field_resolver']);
108 43
    }
109
110 43
    private function setCompilerCacheWarmer(array $config, ContainerBuilder $container): void
111
    {
112 43
        $container->register(CompileCacheWarmer::class)
113 43
            ->setArguments([
114 43
                new Reference($this->getAlias().'.cache_compiler'),
115 43
                $config['definitions']['auto_compile'],
116
            ])
117 43
            ->addTag('kernel.cache_warmer', ['priority' => 50])
118
        ;
119 43
    }
120
121 43
    private function setClassLoaderListener(array $config, ContainerBuilder $container): void
122
    {
123 43
        $container->setParameter($this->getAlias().'.use_classloader_listener', $config['definitions']['use_classloader_listener']);
124 43
        if ($config['definitions']['use_classloader_listener']) {
125 42
            $definition = $container->register(
126 42
                $this->getAlias().'.event_listener.classloader_listener',
127 42
                ClassLoaderListener::class
128
            );
129 42
            $definition->setPublic(true);
130 42
            $definition->setArguments([new Reference($this->getAlias().'.cache_compiler')]);
131 42
            $definition->addTag('kernel.event_listener', ['event' => 'kernel.request', 'method' => 'load', 'priority' => 255]);
132 42
            $definition->addTag('kernel.event_listener', ['event' => 'console.command', 'method' => 'load', 'priority' => 255]);
133
        }
134 43
    }
135
136 43
    private function setDefinitionParameters(array $config, ContainerBuilder $container): void
137
    {
138
        // generator and config
139 43
        $container->setParameter($this->getAlias().'.class_namespace', $config['definitions']['class_namespace']);
140 43
        $container->setParameter($this->getAlias().'.cache_dir', $config['definitions']['cache_dir']);
141 43
        $container->setParameter($this->getAlias().'.cache_dir_permissions', $config['definitions']['cache_dir_permissions']);
142 43
        $container->setParameter($this->getAlias().'.argument_class', $config['definitions']['argument_class']);
143 43
        $container->setParameter($this->getAlias().'.use_experimental_executor', $config['definitions']['use_experimental_executor']);
144 43
    }
145
146 43
    private function setProfilerParameters(array $config, ContainerBuilder $container): void
147
    {
148 43
        $container->setParameter($this->getAlias().'.profiler.query_match', $config['profiler']['query_match']);
149 43
    }
150
151 43
    private function setBatchingMethod(array $config, ContainerBuilder $container): void
152
    {
153 43
        $container->setParameter($this->getAlias().'.batching_method', $config['batching_method']);
154 43
    }
155
156 43
    private function setDebugListener(array $config, ContainerBuilder $container): void
157
    {
158 43
        if ($config['definitions']['show_debug_info']) {
159 1
            $definition = $container->register(DebugListener::class);
160 1
            $definition->addTag('kernel.event_listener', ['event' => Events::PRE_EXECUTOR, 'method' => 'onPreExecutor']);
161 1
            $definition->addTag('kernel.event_listener', ['event' => Events::POST_EXECUTOR, 'method' => 'onPostExecutor']);
162
        }
163 43
    }
164
165 43
    private function setConfigBuilders(array $config, ContainerBuilder $container): void
166
    {
167 43
        foreach (BuilderProcessor::BUILDER_TYPES as $type) {
168 43
            if (!empty($config['definitions']['builders'][$type])) {
169 5
                foreach ($config['definitions']['builders'][$type] as $params) {
170 5
                    $container->addObjectResource($params['class']);
171 5
                    BuilderProcessor::addBuilderClass($params['alias'], $type, $params['class']);
172
                }
173
            }
174
        }
175 43
    }
176
177 43
    private function setSecurity(array $config, ContainerBuilder $container): void
178
    {
179 43
        $executorDefinition = $container->getDefinition(Executor::class);
180 43
        if ($config['security']['enable_introspection']) {
181 42
            $executorDefinition->addMethodCall('enableIntrospectionQuery');
182
        } else {
183 1
            $executorDefinition->addMethodCall('disableIntrospectionQuery');
184
        }
185
186 43
        foreach ($config['security'] as $key => $value) {
187 43
            $container->setParameter(sprintf('%s.%s', $this->getAlias(), $key), $value);
188
        }
189 43
    }
190
191 43
    private function setErrorHandler(array $config, ContainerBuilder $container): void
192
    {
193 43
        if (!$config['errors_handler']['enabled']) {
194
            return;
195
        }
196
197 43
        $container->register(ExceptionConverter::class)
198 43
            ->setArgument(0, $this->buildExceptionMap($config['errors_handler']['exceptions']))
199 43
            ->setArgument(1, $config['errors_handler']['map_exceptions_to_parent']);
200
201 43
        $container->register(ErrorHandler::class)
202 43
            ->setArgument(0, new Reference(EventDispatcherInterface::class))
203 43
            ->setArgument(1, new Reference(ExceptionConverterInterface::class))
204 43
            ->setArgument(2, $config['errors_handler']['internal_error_message']);
205
206 43
        $container->register(ErrorHandlerListener::class)
207 43
            ->setArgument(0, new Reference(ErrorHandler::class))
208 43
            ->setArgument(1, $config['errors_handler']['rethrow_internal_exceptions'])
209 43
            ->setArgument(2, $config['errors_handler']['debug'])
210 43
            ->addTag('kernel.event_listener', ['event' => Events::POST_EXECUTOR, 'method' => 'onPostExecutor']);
211
212 43
        $container->setAlias(ExceptionConverterInterface::class, ExceptionConverter::class);
213
214 43
        if ($config['errors_handler']['log']) {
215 43
            $loggerServiceId = $config['errors_handler']['logger_service'];
216 43
            $invalidBehavior = ErrorLoggerListener::DEFAULT_LOGGER_SERVICE === $loggerServiceId ? ContainerInterface::NULL_ON_INVALID_REFERENCE : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
217
218 43
            $container->register(ErrorLoggerListener::class)
219 43
                ->setPublic(true)
220 43
                ->addArgument(new Reference($loggerServiceId, $invalidBehavior))
221 43
                ->addTag('kernel.event_listener', ['event' => Events::ERROR_FORMATTING, 'method' => 'onErrorFormatting']);
222
        }
223 43
    }
224
225 43
    private function setSchemaBuilderArguments(array $config, ContainerBuilder $container): void
226
    {
227 43
        $container->getDefinition(SchemaBuilder::class)
228 43
            ->replaceArgument(1, $config['definitions']['config_validation']);
229 43
    }
230
231 43
    private function setSchemaArguments(array $config, ContainerBuilder $container): void
232
    {
233 43
        if (!isset($config['definitions']['schema'])) {
234
            return;
235
        }
236
237 43
        $executorDefinition = $container->getDefinition(Executor::class);
238 43
        $resolverMapsBySchema = [];
239
240 43
        foreach ($config['definitions']['schema'] as $schemaName => $schemaConfig) {
241
            // builder
242 34
            $schemaBuilderID = sprintf('%s.schema_builder_%s', $this->getAlias(), $schemaName);
243 34
            $definition = $container->register($schemaBuilderID, Closure::class);
244 34
            $definition->setFactory([new Reference('overblog_graphql.schema_builder'), 'getBuilder']);
245 34
            $definition->setArguments([
246 34
                $schemaName,
247 34
                $schemaConfig['query'],
248 34
                $schemaConfig['mutation'],
249 34
                $schemaConfig['subscription'],
250 34
                $schemaConfig['types'],
251
            ]);
252
            // schema
253 34
            $schemaID = sprintf('%s.schema_%s', $this->getAlias(), $schemaName);
254 34
            $definition = $container->register($schemaID, Schema::class);
255 34
            $definition->setFactory([new Reference($schemaBuilderID), 'call']);
256
257 34
            $executorDefinition->addMethodCall('addSchemaBuilder', [$schemaName, new Reference($schemaBuilderID)]);
258
259 34
            $resolverMapsBySchema[$schemaName] = array_fill_keys($schemaConfig['resolver_maps'], 0);
260
        }
261
262 43
        $container->setParameter(sprintf('%s.resolver_maps', $this->getAlias()), $resolverMapsBySchema);
263 43
    }
264
265 43
    private function setServicesAliases(array $config, ContainerBuilder $container): void
266
    {
267 43
        if (isset($config['services'])) {
268 43
            foreach ($config['services'] as $name => $id) {
269 43
                $alias = sprintf('%s.%s', $this->getAlias(), $name);
270 43
                $container->setAlias($alias, $id);
271
            }
272
        }
273 43
    }
274
275
    /**
276
     * Returns a list of custom exceptions mapped to error/warning classes.
277
     *
278
     * @param array<string, array<string>> $exceptionConfig
279
     *
280
     * @return array<string, string> Custom exception map, [exception => UserError/UserWarning]
281
     */
282 43
    private function buildExceptionMap(array $exceptionConfig): array
283
    {
284 43
        $exceptionMap = [];
285 43
        $errorsMapping = [
286
            'errors' => UserError::class,
287
            'warnings' => UserWarning::class,
288
        ];
289
290 43
        foreach ($exceptionConfig as $type => $exceptionList) {
291 43
            foreach ($exceptionList as $exception) {
292 2
                $exceptionMap[$exception] = $errorsMapping[$type];
293
            }
294
        }
295
296 43
        return $exceptionMap;
297
    }
298
}
299