• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

overblog / GraphQLBundle / 24230000246

10 Apr 2026 06:35AM UTC coverage: 98.481% (-0.07%) from 98.546%
24230000246

Pull #1243

github

web-flow
Merge 07076ede9 into 7e9f36ef2
Pull Request #1243: fix: only load profiler services when Symfony profiler is available

1 of 2 new or added lines in 1 file covered. (50.0%)

2 existing lines in 1 file now uncovered.

4539 of 4609 relevant lines covered (98.48%)

74.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.78
/src/DependencyInjection/OverblogGraphQLExtension.php
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\Extension\Extension;
30
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
31
use Symfony\Component\DependencyInjection\Reference;
32
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
33

34
use function realpath;
35
use function sprintf;
36

37
final class OverblogGraphQLExtension extends Extension
38
{
39
    public function load(array $configs, ContainerBuilder $container): void
40
    {
41
        $this->loadConfigFiles($container);
98✔
42
        $configuration = $this->getConfiguration($configs, $container);
98✔
43
        $config = $this->processConfiguration($configuration, $configs);
98✔
44

45
        $this->setBatchingMethod($config, $container);
98✔
46
        $this->setServicesAliases($config, $container);
98✔
47
        $this->setSchemaBuilderArguments($config, $container);
98✔
48
        $this->setSchemaArguments($config, $container);
98✔
49
        $this->setErrorHandler($config, $container);
98✔
50
        $this->setSecurity($config, $container);
98✔
51
        $this->setConfigBuilders($config, $container);
98✔
52
        $this->setDebugListener($config, $container);
98✔
53
        $this->setDefinitionParameters($config, $container);
98✔
54
        $this->setProfilerParameters($config, $container);
98✔
55
        $this->setClassLoaderListener($config, $container);
98✔
56
        $this->setCompilerCacheWarmer($config, $container);
98✔
57
        $this->registerForAutoconfiguration($container);
98✔
58
        $this->setDefaultFieldResolver($config, $container);
98✔
59

60
        $container->setParameter($this->getAlias().'.schemas', array_keys($config['definitions']['schema']));
98✔
61
        $container->setParameter($this->getAlias().'.config', $config);
98✔
62
        $container->setParameter($this->getAlias().'.resources_dir', realpath(__DIR__.'/../Resources'));
98✔
63
    }
64

65
    public function getAlias(): string
66
    {
67
        return Configuration::NAME;
98✔
68
    }
69

70
    public function getConfiguration(array $config, ContainerBuilder $container): Configuration
71
    {
72
        return new Configuration(
98✔
73
            // @phpstan-ignore-next-line
74
            $container->getParameter('kernel.debug')
98✔
75
        );
98✔
76
    }
77

78
    private function loadConfigFiles(ContainerBuilder $container): void
79
    {
80
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
98✔
81
        $loader->load('services.yaml');
98✔
82
        $loader->load('commands.yaml');
98✔
83
        $loader->load('listeners.yaml');
98✔
84
        $loader->load('graphql_types.yaml');
98✔
85
        $loader->load('graphql_resolvers.yaml');
98✔
86
        $loader->load('expression_language_functions.yaml');
98✔
87
        $loader->load('definition_config_processors.yaml');
98✔
88
        $loader->load('aliases.yaml');
98✔
89

90
        if ($container->has('profiler')) {
98✔
NEW
91
            $loader->load('profiler.yaml');
×
92
        }
93
    }
94

95
    private function registerForAutoconfiguration(ContainerBuilder $container): void
96
    {
97
        $container->registerForAutoconfiguration(MutationInterface::class)
98✔
98
            ->addTag('overblog_graphql.mutation');
98✔
99

100
        $container->registerForAutoconfiguration(QueryInterface::class)
98✔
101
            ->addTag('overblog_graphql.query');
98✔
102

103
        $container->registerForAutoconfiguration(Type::class)
98✔
104
            ->addTag('overblog_graphql.type');
98✔
105
    }
106

107
    private function setDefaultFieldResolver(array $config, ContainerBuilder $container): void
108
    {
109
        $container->setAlias($this->getAlias().'.default_field_resolver', $config['definitions']['default_field_resolver']);
98✔
110
    }
111

112
    private function setCompilerCacheWarmer(array $config, ContainerBuilder $container): void
113
    {
114
        $container->register(CompileCacheWarmer::class)
98✔
115
            ->setArguments([
98✔
116
                new Reference($this->getAlias().'.cache_compiler'),
98✔
117
                $config['definitions']['auto_compile'],
98✔
118
            ])
98✔
119
            ->addTag('kernel.cache_warmer', ['priority' => 50])
98✔
120
        ;
98✔
121
    }
122

123
    private function setClassLoaderListener(array $config, ContainerBuilder $container): void
124
    {
125
        $container->setParameter($this->getAlias().'.use_classloader_listener', $config['definitions']['use_classloader_listener']);
98✔
126
        if ($config['definitions']['use_classloader_listener']) {
98✔
127
            $definition = $container->register(
96✔
128
                $this->getAlias().'.event_listener.classloader_listener',
96✔
129
                ClassLoaderListener::class
96✔
130
            );
96✔
131
            $definition->setPublic(true);
96✔
132
            $definition->setArguments([new Reference($this->getAlias().'.cache_compiler')]);
96✔
133
            $definition->addTag('kernel.event_listener', ['event' => 'kernel.request', 'method' => 'load', 'priority' => 255]);
96✔
134
            $definition->addTag('kernel.event_listener', ['event' => 'console.command', 'method' => 'load', 'priority' => 255]);
96✔
135
        }
136
    }
137

138
    private function setDefinitionParameters(array $config, ContainerBuilder $container): void
139
    {
140
        // generator and config
141
        $container->setParameter($this->getAlias().'.class_namespace', $config['definitions']['class_namespace']);
98✔
142
        $container->setParameter($this->getAlias().'.cache_dir', $config['definitions']['cache_dir']);
98✔
143
        $container->setParameter($this->getAlias().'.cache_dir_permissions', $config['definitions']['cache_dir_permissions']);
98✔
144
        $container->setParameter($this->getAlias().'.argument_class', $config['definitions']['argument_class']);
98✔
145
    }
146

147
    private function setProfilerParameters(array $config, ContainerBuilder $container): void
148
    {
149
        $container->setParameter($this->getAlias().'.profiler.query_match', $config['profiler']['query_match']);
98✔
150
    }
151

152
    private function setBatchingMethod(array $config, ContainerBuilder $container): void
153
    {
154
        $container->setParameter($this->getAlias().'.batching_method', $config['batching_method']);
98✔
155
    }
156

157
    private function setDebugListener(array $config, ContainerBuilder $container): void
158
    {
159
        if ($config['definitions']['show_debug_info']) {
98✔
160
            $definition = $container->register(DebugListener::class);
3✔
161
            $definition->addTag('kernel.event_listener', ['event' => Events::PRE_EXECUTOR, 'method' => 'onPreExecutor']);
3✔
162
            $definition->addTag('kernel.event_listener', ['event' => Events::POST_EXECUTOR, 'method' => 'onPostExecutor']);
3✔
163
        }
164
    }
165

166
    private function setConfigBuilders(array $config, ContainerBuilder $container): void
167
    {
168
        foreach (BuilderProcessor::BUILDER_TYPES as $type) {
98✔
169
            if (!empty($config['definitions']['builders'][$type])) {
98✔
170
                foreach ($config['definitions']['builders'][$type] as $params) {
10✔
171
                    $container->addObjectResource($params['class']);
10✔
172
                    BuilderProcessor::addBuilderClass($params['alias'], $type, $params['class']);
10✔
173
                }
174
            }
175
        }
176
    }
177

178
    private function setSecurity(array $config, ContainerBuilder $container): void
179
    {
180
        $executorDefinition = $container->getDefinition(Executor::class);
98✔
181
        if ($config['security']['enable_introspection']) {
98✔
182
            $executorDefinition->addMethodCall('enableIntrospectionQuery');
97✔
183
        } else {
184
            $executorDefinition->addMethodCall('disableIntrospectionQuery');
3✔
185
        }
186

187
        foreach ($config['security'] as $key => $value) {
98✔
188
            $container->setParameter(sprintf('%s.%s', $this->getAlias(), $key), $value);
98✔
189
        }
190
    }
191

192
    private function setErrorHandler(array $config, ContainerBuilder $container): void
193
    {
194
        if (!$config['errors_handler']['enabled']) {
98✔
195
            return;
×
196
        }
197

198
        $container->register(ExceptionConverter::class)
98✔
199
            ->setArgument(0, $this->buildExceptionMap($config['errors_handler']['exceptions']))
98✔
200
            ->setArgument(1, $config['errors_handler']['map_exceptions_to_parent']);
98✔
201

202
        $container->register(ErrorHandler::class)
98✔
203
            ->setArgument(0, new Reference(EventDispatcherInterface::class))
98✔
204
            ->setArgument(1, new Reference(ExceptionConverterInterface::class))
98✔
205
            ->setArgument(2, $config['errors_handler']['internal_error_message']);
98✔
206

207
        $container->register(ErrorHandlerListener::class)
98✔
208
            ->setArgument(0, new Reference(ErrorHandler::class))
98✔
209
            ->setArgument(1, $config['errors_handler']['rethrow_internal_exceptions'])
98✔
210
            ->setArgument(2, $config['errors_handler']['debug'])
98✔
211
            ->addTag('kernel.event_listener', ['event' => Events::POST_EXECUTOR, 'method' => 'onPostExecutor']);
98✔
212

213
        $container->setAlias(ExceptionConverterInterface::class, ExceptionConverter::class);
98✔
214

215
        if ($config['errors_handler']['log']) {
98✔
216
            $loggerServiceId = $config['errors_handler']['logger_service'];
98✔
217
            $invalidBehavior = ErrorLoggerListener::DEFAULT_LOGGER_SERVICE === $loggerServiceId ? ContainerInterface::NULL_ON_INVALID_REFERENCE : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
98✔
218

219
            $container->register(ErrorLoggerListener::class)
98✔
220
                ->setPublic(true)
98✔
221
                ->addArgument(new Reference($loggerServiceId, $invalidBehavior))
98✔
222
                ->addTag('kernel.event_listener', ['event' => Events::ERROR_FORMATTING, 'method' => 'onErrorFormatting']);
98✔
223
        }
224
    }
225

226
    private function setSchemaBuilderArguments(array $config, ContainerBuilder $container): void
227
    {
228
        $container->getDefinition(SchemaBuilder::class)
98✔
229
            ->replaceArgument(1, $config['definitions']['config_validation']);
98✔
230
    }
231

232
    private function setSchemaArguments(array $config, ContainerBuilder $container): void
233
    {
234
        if (!isset($config['definitions']['schema'])) {
98✔
235
            return;
×
236
        }
237

238
        $executorDefinition = $container->getDefinition(Executor::class);
98✔
239

240
        foreach ($config['definitions']['schema'] as $schemaName => $schemaConfig) {
98✔
241
            // builder
242
            $schemaBuilderID = sprintf('%s.schema_builder_%s', $this->getAlias(), $schemaName);
82✔
243
            $definition = $container->register($schemaBuilderID, Closure::class);
82✔
244
            $definition->setFactory([new Reference('overblog_graphql.schema_builder'), 'getBuilder']);
82✔
245
            $definition->setArguments([
82✔
246
                $schemaName,
82✔
247
                $schemaConfig['query'],
82✔
248
                $schemaConfig['mutation'],
82✔
249
                $schemaConfig['subscription'],
82✔
250
                $schemaConfig['types'],
82✔
251
            ]);
82✔
252
            // schema
253
            $schemaID = sprintf('%s.schema_%s', $this->getAlias(), $schemaName);
82✔
254
            $definition = $container->register($schemaID, Schema::class);
82✔
255
            $definition->setFactory([new Reference($schemaBuilderID), 'call']);
82✔
256

257
            $executorDefinition->addMethodCall('addSchemaBuilder', [$schemaName, new Reference($schemaBuilderID)]);
82✔
258
        }
259
    }
260

261
    private function setServicesAliases(array $config, ContainerBuilder $container): void
262
    {
263
        if (isset($config['services'])) {
98✔
264
            foreach ($config['services'] as $name => $id) {
98✔
265
                $alias = sprintf('%s.%s', $this->getAlias(), $name);
98✔
266
                $container->setAlias($alias, $id);
98✔
267
            }
268
        }
269
    }
270

271
    /**
272
     * Returns a list of custom exceptions mapped to error/warning classes.
273
     *
274
     * @param array<string, array<string>> $exceptionConfig
275
     *
276
     * @return array<string, string> Custom exception map, [exception => UserError/UserWarning]
277
     */
278
    private function buildExceptionMap(array $exceptionConfig): array
279
    {
280
        $exceptionMap = [];
98✔
281
        $errorsMapping = [
98✔
282
            'errors' => UserError::class,
98✔
283
            'warnings' => UserWarning::class,
98✔
284
        ];
98✔
285

286
        foreach ($exceptionConfig as $type => $exceptionList) {
98✔
287
            foreach ($exceptionList as $exception) {
98✔
288
                $exceptionMap[$exception] = $errorsMapping[$type];
5✔
289
            }
290
        }
291

292
        return $exceptionMap;
98✔
293
    }
294
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc