ApiPlatformExtension   F
last analyzed

Complexity

Total Complexity 97

Size/Duplication

Total Lines 588
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 317
dl 0
loc 588
rs 2
c 2
b 0
f 0
wmc 97

27 Methods

Rating   Name   Duplication   Size   Complexity  
A registerJsonHalConfiguration() 0 7 2
A registerJsonApiConfiguration() 0 7 2
A registerJsonProblemConfiguration() 0 7 2
A registerDataTransformerConfiguration() 0 4 1
A registerOAuthConfiguration() 0 14 2
A prepend() 0 11 2
A registerCommonConfiguration() 0 54 3
A registerMetadataConfiguration() 0 26 5
A normalizeDefaults() 0 20 3
B getBundlesResourcesPaths() 0 25 7
B getResourcesToWatch() 0 40 10
A registerJsonLdHydraConfiguration() 0 15 4
A registerDoctrineMongoDbOdmConfiguration() 0 14 2
A registerHttpCacheConfiguration() 0 24 4
A registerDoctrineOrmConfiguration() 0 23 3
A registerLegacyBundlesConfiguration() 0 11 5
A registerSwaggerConfiguration() 0 20 4
A getFormats() 0 10 3
A registerGraphQlConfiguration() 0 26 4
A registerCacheConfiguration() 0 22 5
A registerMessengerConfiguration() 0 7 2
A registerElasticsearchConfiguration() 0 17 2
A registerMercureConfiguration() 0 19 5
A registerDataCollectorConfiguration() 0 10 4
A registerSecurityConfiguration() 0 7 2
A registerValidatorConfiguration() 0 17 3
B load() 0 54 6

How to fix   Complexity   

Complex Class

Complex classes like ApiPlatformExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ApiPlatformExtension, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection;
15
16
use ApiPlatform\Core\Api\FilterInterface;
17
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationCollectionExtensionInterface;
18
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Extension\AggregationItemExtensionInterface;
19
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\AbstractFilter as DoctrineMongoDbOdmAbstractFilter;
20
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\EagerLoadingExtension;
21
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\FilterEagerLoadingExtension;
22
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface as DoctrineQueryCollectionExtensionInterface;
23
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
24
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter as DoctrineOrmAbstractContextAwareFilter;
25
use ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Extension\RequestBodySearchCollectionExtensionInterface;
26
use ApiPlatform\Core\Bridge\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRestrictionMetadataInterface;
27
use ApiPlatform\Core\Bridge\Symfony\Validator\ValidationGroupsGeneratorInterface;
28
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
29
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
30
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
31
use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
32
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
33
use ApiPlatform\Core\GraphQl\Resolver\MutationResolverInterface;
34
use ApiPlatform\Core\GraphQl\Resolver\QueryCollectionResolverInterface;
35
use ApiPlatform\Core\GraphQl\Resolver\QueryItemResolverInterface;
36
use ApiPlatform\Core\GraphQl\Type\Definition\TypeInterface as GraphQlTypeInterface;
37
use Doctrine\Common\Annotations\Annotation;
38
use phpDocumentor\Reflection\DocBlockFactoryInterface;
39
use Ramsey\Uuid\Uuid;
40
use Symfony\Component\BrowserKit\AbstractBrowser;
41
use Symfony\Component\Cache\Adapter\ArrayAdapter;
42
use Symfony\Component\Config\FileLocator;
43
use Symfony\Component\Config\Resource\DirectoryResource;
44
use Symfony\Component\DependencyInjection\ChildDefinition;
45
use Symfony\Component\DependencyInjection\ContainerBuilder;
46
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
47
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
48
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
49
use Symfony\Component\DependencyInjection\Reference;
50
use Symfony\Component\Finder\Finder;
51
use Symfony\Component\HttpClient\HttpClientTrait;
52
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
53
use Symfony\Component\Validator\Validator\ValidatorInterface;
54
use Symfony\Component\Yaml\Yaml;
55
56
/**
57
 * The extension of this bundle.
58
 *
59
 * @author Kévin Dunglas <[email protected]>
60
 */
61
final class ApiPlatformExtension extends Extension implements PrependExtensionInterface
62
{
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function prepend(ContainerBuilder $container): void
67
    {
68
        if (isset($container->getExtensions()['framework'])) {
69
            $container->prependExtensionConfig('framework', [
70
                'serializer' => [
71
                    'enabled' => true,
72
                ],
73
            ]);
74
            $container->prependExtensionConfig('framework', [
75
                'property_info' => [
76
                    'enabled' => true,
77
                ],
78
            ]);
79
        }
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function load(array $configs, ContainerBuilder $container): void
86
    {
87
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
88
89
        $configuration = new Configuration();
90
        $config = $this->processConfiguration($configuration, $configs);
91
92
        $formats = $this->getFormats($config['formats']);
93
        $patchFormats = $this->getFormats($config['patch_formats']);
94
        $errorFormats = $this->getFormats($config['error_formats']);
95
96
        // Backward Compatibility layer
97
        if (isset($formats['jsonapi']) && !isset($patchFormats['jsonapi'])) {
98
            $patchFormats['jsonapi'] = ['application/vnd.api+json'];
99
        }
100
101
        $this->registerCommonConfiguration($container, $config, $loader, $formats, $patchFormats, $errorFormats);
102
        $this->registerMetadataConfiguration($container, $config, $loader);
103
        $this->registerOAuthConfiguration($container, $config);
104
        $this->registerSwaggerConfiguration($container, $config, $loader);
105
        $this->registerJsonApiConfiguration($formats, $loader);
106
        $this->registerJsonLdHydraConfiguration($container, $formats, $loader, $config['enable_docs']);
107
        $this->registerJsonHalConfiguration($formats, $loader);
108
        $this->registerJsonProblemConfiguration($errorFormats, $loader);
109
        $this->registerGraphQlConfiguration($container, $config, $loader);
110
        $this->registerLegacyBundlesConfiguration($container, $config, $loader);
111
        $this->registerCacheConfiguration($container);
112
        $this->registerDoctrineOrmConfiguration($container, $config, $loader);
113
        $this->registerDoctrineMongoDbOdmConfiguration($container, $config, $loader);
114
        $this->registerHttpCacheConfiguration($container, $config, $loader);
115
        $this->registerValidatorConfiguration($container, $config, $loader);
116
        $this->registerDataCollectorConfiguration($container, $config, $loader);
117
        $this->registerMercureConfiguration($container, $config, $loader);
118
        $this->registerMessengerConfiguration($container, $config, $loader);
119
        $this->registerElasticsearchConfiguration($container, $config, $loader);
120
        $this->registerDataTransformerConfiguration($container);
121
        $this->registerSecurityConfiguration($container, $loader);
122
123
        $container->registerForAutoconfiguration(DataPersisterInterface::class)
124
            ->addTag('api_platform.data_persister');
125
        $container->registerForAutoconfiguration(ItemDataProviderInterface::class)
126
            ->addTag('api_platform.item_data_provider');
127
        $container->registerForAutoconfiguration(CollectionDataProviderInterface::class)
128
            ->addTag('api_platform.collection_data_provider');
129
        $container->registerForAutoconfiguration(SubresourceDataProviderInterface::class)
130
            ->addTag('api_platform.subresource_data_provider');
131
        $container->registerForAutoconfiguration(FilterInterface::class)
132
            ->addTag('api_platform.filter');
133
134
        if ($container->hasParameter('test.client.parameters')) {
135
            $loader->load('test.xml');
136
137
            if (!class_exists(AbstractBrowser::class) || !trait_exists(HttpClientTrait::class)) {
138
                $container->removeDefinition('test.api_platform.client');
139
            }
140
        }
141
    }
142
143
    private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats): void
144
    {
145
        $loader->load('api.xml');
146
        $loader->load('data_persister.xml');
147
        $loader->load('data_provider.xml');
148
        $loader->load('filter.xml');
149
150
        if (class_exists(Uuid::class)) {
151
            $loader->load('ramsey_uuid.xml');
152
        }
153
154
        $container->setParameter('api_platform.enable_entrypoint', $config['enable_entrypoint']);
155
        $container->setParameter('api_platform.enable_docs', $config['enable_docs']);
156
        $container->setParameter('api_platform.title', $config['title']);
157
        $container->setParameter('api_platform.description', $config['description']);
158
        $container->setParameter('api_platform.version', $config['version']);
159
        $container->setParameter('api_platform.show_webby', $config['show_webby']);
160
        $container->setParameter('api_platform.exception_to_status', $config['exception_to_status']);
161
        $container->setParameter('api_platform.formats', $formats);
162
        $container->setParameter('api_platform.patch_formats', $patchFormats);
163
        $container->setParameter('api_platform.error_formats', $errorFormats);
164
        $container->setParameter('api_platform.allow_plain_identifiers', $config['allow_plain_identifiers']);
165
        $container->setParameter('api_platform.eager_loading.enabled', $this->isConfigEnabled($container, $config['eager_loading']));
166
        $container->setParameter('api_platform.eager_loading.max_joins', $config['eager_loading']['max_joins']);
167
        $container->setParameter('api_platform.eager_loading.fetch_partial', $config['eager_loading']['fetch_partial']);
168
        $container->setParameter('api_platform.eager_loading.force_eager', $config['eager_loading']['force_eager']);
169
        $container->setParameter('api_platform.collection.exists_parameter_name', $config['collection']['exists_parameter_name']);
170
        $container->setParameter('api_platform.collection.order', $config['collection']['order']);
171
        $container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']);
172
        $container->setParameter('api_platform.collection.pagination.enabled', $this->isConfigEnabled($container, $config['collection']['pagination']));
173
        $container->setParameter('api_platform.collection.pagination.partial', $config['collection']['pagination']['partial']);
174
        $container->setParameter('api_platform.collection.pagination.client_enabled', $config['collection']['pagination']['client_enabled']);
175
        $container->setParameter('api_platform.collection.pagination.client_items_per_page', $config['collection']['pagination']['client_items_per_page']);
176
        $container->setParameter('api_platform.collection.pagination.client_partial', $config['collection']['pagination']['client_partial']);
177
        $container->setParameter('api_platform.collection.pagination.items_per_page', $config['collection']['pagination']['items_per_page']);
178
        $container->setParameter('api_platform.collection.pagination.maximum_items_per_page', $config['collection']['pagination']['maximum_items_per_page']);
179
        $container->setParameter('api_platform.collection.pagination.page_parameter_name', $config['collection']['pagination']['page_parameter_name']);
180
        $container->setParameter('api_platform.collection.pagination.enabled_parameter_name', $config['collection']['pagination']['enabled_parameter_name']);
181
        $container->setParameter('api_platform.collection.pagination.items_per_page_parameter_name', $config['collection']['pagination']['items_per_page_parameter_name']);
182
        $container->setParameter('api_platform.collection.pagination.partial_parameter_name', $config['collection']['pagination']['partial_parameter_name']);
183
        $container->setParameter('api_platform.collection.pagination', $config['collection']['pagination']);
184
        $container->setParameter('api_platform.http_cache.etag', $config['http_cache']['etag']);
185
        $container->setParameter('api_platform.http_cache.max_age', $config['http_cache']['max_age']);
186
        $container->setParameter('api_platform.http_cache.shared_max_age', $config['http_cache']['shared_max_age']);
187
        $container->setParameter('api_platform.http_cache.vary', $config['http_cache']['vary']);
188
        $container->setParameter('api_platform.http_cache.public', $config['http_cache']['public']);
189
190
        $container->setAlias('api_platform.operation_path_resolver.default', $config['default_operation_path_resolver']);
191
        $container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
192
193
        if ($config['name_converter']) {
194
            $container->setAlias('api_platform.name_converter', $config['name_converter']);
195
        }
196
        $container->setParameter('api_platform.defaults', $this->normalizeDefaults($config['defaults'] ?? []));
197
    }
198
199
    private function normalizeDefaults(array $defaults): array
200
    {
201
        $normalizedDefaults = ['attributes' => []];
202
        $rootLevelOptions = [
203
            'description',
204
            'iri',
205
            'item_operations',
206
            'collection_operations',
207
            'graphql',
208
        ];
209
210
        foreach ($defaults as $option => $value) {
211
            if (\in_array($option, $rootLevelOptions, true)) {
212
                $normalizedDefaults[$option] = $value;
213
            } else {
214
                $normalizedDefaults['attributes'][$option] = $value;
215
            }
216
        }
217
218
        return $normalizedDefaults;
219
    }
220
221
    private function registerMetadataConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
222
    {
223
        $loader->load('metadata/metadata.xml');
224
        $loader->load('metadata/xml.xml');
225
226
        [$xmlResources, $yamlResources] = $this->getResourcesToWatch($container, $config);
227
228
        if (!empty($config['resource_class_directories'])) {
229
            $container->setParameter('api_platform.resource_class_directories', array_merge(
230
                $config['resource_class_directories'], $container->getParameter('api_platform.resource_class_directories')
231
            ));
232
        }
233
234
        $container->getDefinition('api_platform.metadata.extractor.xml')->replaceArgument(0, $xmlResources);
235
236
        if (class_exists(Annotation::class)) {
237
            $loader->load('metadata/annotation.xml');
238
        }
239
240
        if (class_exists(Yaml::class)) {
241
            $loader->load('metadata/yaml.xml');
242
            $container->getDefinition('api_platform.metadata.extractor.yaml')->replaceArgument(0, $yamlResources);
243
        }
244
245
        if (interface_exists(DocBlockFactoryInterface::class)) {
246
            $loader->load('metadata/php_doc.xml');
247
        }
248
    }
249
250
    private function getBundlesResourcesPaths(ContainerBuilder $container, array $config): array
251
    {
252
        $bundlesResourcesPaths = [];
253
254
        foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
255
            $paths = [];
256
            $dirname = $bundle['path'];
257
            foreach (['.yaml', '.yml', '.xml', ''] as $extension) {
258
                $paths[] = "$dirname/Resources/config/api_resources$extension";
259
            }
260
            if ($this->isConfigEnabled($container, $config['doctrine'])) {
261
                $paths[] = "$dirname/Entity";
262
            }
263
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
264
                $paths[] = "$dirname/Document";
265
            }
266
267
            foreach ($paths as $path) {
268
                if ($container->fileExists($path, false)) {
269
                    $bundlesResourcesPaths[] = $path;
270
                }
271
            }
272
        }
273
274
        return $bundlesResourcesPaths;
275
    }
276
277
    private function getResourcesToWatch(ContainerBuilder $container, array $config): array
278
    {
279
        $paths = array_unique(array_merge($config['mapping']['paths'], $this->getBundlesResourcesPaths($container, $config)));
280
281
        // Flex structure (only if nothing specified)
282
        $projectDir = $container->getParameter('kernel.project_dir');
283
        if (!$paths && is_dir($dir = "$projectDir/config/api_platform")) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $paths of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
284
            $paths = [$dir];
285
        }
286
287
        $resources = ['yml' => [], 'xml' => [], 'dir' => []];
288
289
        foreach ($paths as $path) {
290
            if (is_dir($path)) {
291
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.(xml|ya?ml)$/') as $file) {
292
                    $resources['yaml' === ($extension = $file->getExtension()) ? 'yml' : $extension][] = $file->getRealPath();
293
                }
294
295
                $resources['dir'][] = $path;
296
                $container->addResource(new DirectoryResource($path, '/\.(xml|ya?ml|php)$/'));
297
298
                continue;
299
            }
300
301
            if ($container->fileExists($path, false)) {
302
                if (!preg_match('/\.(xml|ya?ml)$/', $path, $matches)) {
303
                    throw new RuntimeException(sprintf('Unsupported mapping type in "%s", supported types are XML & YAML.', $path));
304
                }
305
306
                $resources['yaml' === $matches[1] ? 'yml' : $matches[1]][] = $path;
307
308
                continue;
309
            }
310
311
            throw new RuntimeException(sprintf('Could not open file or directory "%s".', $path));
312
        }
313
314
        $container->setParameter('api_platform.resource_class_directories', $resources['dir']);
315
316
        return [$resources['xml'], $resources['yml']];
317
    }
318
319
    private function registerOAuthConfiguration(ContainerBuilder $container, array $config): void
320
    {
321
        if (!$config['oauth']) {
322
            return;
323
        }
324
325
        $container->setParameter('api_platform.oauth.enabled', $this->isConfigEnabled($container, $config['oauth']));
326
        $container->setParameter('api_platform.oauth.clientId', $config['oauth']['clientId']);
327
        $container->setParameter('api_platform.oauth.clientSecret', $config['oauth']['clientSecret']);
328
        $container->setParameter('api_platform.oauth.type', $config['oauth']['type']);
329
        $container->setParameter('api_platform.oauth.flow', $config['oauth']['flow']);
330
        $container->setParameter('api_platform.oauth.tokenUrl', $config['oauth']['tokenUrl']);
331
        $container->setParameter('api_platform.oauth.authorizationUrl', $config['oauth']['authorizationUrl']);
332
        $container->setParameter('api_platform.oauth.scopes', $config['oauth']['scopes']);
333
    }
334
335
    /**
336
     * Registers the Swagger, ReDoc and Swagger UI configuration.
337
     */
338
    private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
339
    {
340
        $container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
341
342
        if (empty($config['swagger']['versions'])) {
343
            return;
344
        }
345
346
        $loader->load('json_schema.xml');
347
        $loader->load('swagger.xml');
348
        $loader->load('swagger-ui.xml');
349
350
        if (!$config['enable_swagger_ui'] && !$config['enable_re_doc']) {
351
            // Remove the listener but keep the controller to allow customizing the path of the UI
352
            $container->removeDefinition('api_platform.swagger.listener.ui');
353
        }
354
355
        $container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']);
356
        $container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
357
        $container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
358
    }
359
360
    private function registerJsonApiConfiguration(array $formats, XmlFileLoader $loader): void
361
    {
362
        if (!isset($formats['jsonapi'])) {
363
            return;
364
        }
365
366
        $loader->load('jsonapi.xml');
367
    }
368
369
    private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, XmlFileLoader $loader, bool $docEnabled): void
370
    {
371
        if (!isset($formats['jsonld'])) {
372
            return;
373
        }
374
375
        $loader->load('jsonld.xml');
376
        $loader->load('hydra.xml');
377
378
        if (!$container->has('api_platform.json_schema.schema_factory')) {
379
            $container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
380
        }
381
382
        if (!$docEnabled) {
383
            $container->removeDefinition('api_platform.hydra.listener.response.add_link_header');
384
        }
385
    }
386
387
    private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader): void
388
    {
389
        if (!isset($formats['jsonhal'])) {
390
            return;
391
        }
392
393
        $loader->load('hal.xml');
394
    }
395
396
    private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLoader $loader): void
397
    {
398
        if (!isset($errorFormats['jsonproblem'])) {
399
            return;
400
        }
401
402
        $loader->load('problem.xml');
403
    }
404
405
    private function registerGraphQlConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
406
    {
407
        $enabled = $this->isConfigEnabled($container, $config['graphql']);
408
409
        $container->setParameter('api_platform.graphql.enabled', $enabled);
410
        $container->setParameter('api_platform.graphql.graphiql.enabled', $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']));
411
        $container->setParameter('api_platform.graphql.graphql_playground.enabled', $enabled && $this->isConfigEnabled($container, $config['graphql']['graphql_playground']));
412
        $container->setParameter('api_platform.graphql.collection.pagination', $config['graphql']['collection']['pagination']);
413
414
        if (!$enabled) {
415
            return;
416
        }
417
418
        $container->setParameter('api_platform.graphql.default_ide', $config['graphql']['default_ide']);
419
        $container->setParameter('api_platform.graphql.nesting_separator', $config['graphql']['nesting_separator']);
420
421
        $loader->load('graphql.xml');
422
423
        $container->registerForAutoconfiguration(QueryItemResolverInterface::class)
424
            ->addTag('api_platform.graphql.query_resolver');
425
        $container->registerForAutoconfiguration(QueryCollectionResolverInterface::class)
426
            ->addTag('api_platform.graphql.query_resolver');
427
        $container->registerForAutoconfiguration(MutationResolverInterface::class)
428
            ->addTag('api_platform.graphql.mutation_resolver');
429
        $container->registerForAutoconfiguration(GraphQlTypeInterface::class)
430
            ->addTag('api_platform.graphql.type');
431
    }
432
433
    private function registerLegacyBundlesConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
434
    {
435
        /** @var string[] $bundles */
436
        $bundles = $container->getParameter('kernel.bundles');
437
438
        if (isset($bundles['FOSUserBundle']) && $config['enable_fos_user']) {
439
            $loader->load('fos_user.xml');
440
        }
441
442
        if (isset($bundles['NelmioApiDocBundle']) && $config['enable_nelmio_api_doc']) {
443
            $loader->load('nelmio_api_doc.xml');
444
        }
445
    }
446
447
    private function registerCacheConfiguration(ContainerBuilder $container): void
448
    {
449
        if (!$container->hasParameter('kernel.debug') || !$container->getParameter('kernel.debug')) {
450
            $container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
451
        }
452
453
        if (!$container->hasParameter('api_platform.metadata_cache')) {
454
            return;
455
        }
456
457
        @trigger_error('The "api_platform.metadata_cache" parameter is deprecated since version 2.4 and will have no effect in 3.0.', E_USER_DEPRECATED);
458
459
        // BC
460
        if (!$container->getParameter('api_platform.metadata_cache')) {
461
            $container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
462
463
            $container->register('api_platform.cache.metadata.property', ArrayAdapter::class);
464
            $container->register('api_platform.cache.metadata.resource', ArrayAdapter::class);
465
            $container->register('api_platform.cache.route_name_resolver', ArrayAdapter::class);
466
            $container->register('api_platform.cache.identifiers_extractor', ArrayAdapter::class);
467
            $container->register('api_platform.cache.subresource_operation_factory', ArrayAdapter::class);
468
            $container->register('api_platform.elasticsearch.cache.metadata.document', ArrayAdapter::class);
469
        }
470
    }
471
472
    private function registerDoctrineOrmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
473
    {
474
        if (!$this->isConfigEnabled($container, $config['doctrine'])) {
475
            return;
476
        }
477
478
        $container->registerForAutoconfiguration(QueryItemExtensionInterface::class)
479
            ->addTag('api_platform.doctrine.orm.query_extension.item');
480
        $container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
481
            ->addTag('api_platform.doctrine.orm.query_extension.collection');
482
        $container->registerForAutoconfiguration(DoctrineOrmAbstractContextAwareFilter::class)
483
            ->setBindings(['$requestStack' => null]);
484
485
        $loader->load('doctrine_orm.xml');
486
487
        if ($this->isConfigEnabled($container, $config['eager_loading'])) {
488
            return;
489
        }
490
491
        $container->removeAlias(EagerLoadingExtension::class);
492
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading');
493
        $container->removeAlias(FilterEagerLoadingExtension::class);
494
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.filter_eager_loading');
495
    }
496
497
    private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
498
    {
499
        if (!$this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
500
            return;
501
        }
502
503
        $container->registerForAutoconfiguration(AggregationItemExtensionInterface::class)
504
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.item');
505
        $container->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)
506
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection');
507
        $container->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
508
            ->setBindings(['$managerRegistry' => new Reference('doctrine_mongodb')]);
509
510
        $loader->load('doctrine_mongodb_odm.xml');
511
    }
512
513
    private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
514
    {
515
        $loader->load('http_cache.xml');
516
517
        if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
518
            return;
519
        }
520
521
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
522
            $loader->load('doctrine_orm_http_cache_purger.xml');
523
        }
524
525
        $loader->load('http_cache_tags.xml');
526
527
        $definitions = [];
528
        foreach ($config['http_cache']['invalidation']['varnish_urls'] as $key => $url) {
529
            $definition = new ChildDefinition('api_platform.http_cache.purger.varnish_client');
530
            $definition->addArgument(['base_uri' => $url] + $config['http_cache']['invalidation']['request_options']);
531
532
            $definitions[] = $definition;
533
        }
534
535
        $container->getDefinition('api_platform.http_cache.purger.varnish')->addArgument($definitions);
536
        $container->setAlias('api_platform.http_cache.purger', 'api_platform.http_cache.purger.varnish');
537
    }
538
539
    /**
540
     * Normalizes the format from config to the one accepted by Symfony HttpFoundation.
541
     */
542
    private function getFormats(array $configFormats): array
543
    {
544
        $formats = [];
545
        foreach ($configFormats as $format => $value) {
546
            foreach ($value['mime_types'] as $mimeType) {
547
                $formats[$format][] = $mimeType;
548
            }
549
        }
550
551
        return $formats;
552
    }
553
554
    private function registerValidatorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
555
    {
556
        if (interface_exists(ValidatorInterface::class)) {
557
            $loader->load('validator.xml');
558
559
            $container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
560
                ->addTag('api_platform.validation_groups_generator')
561
                ->setPublic(true); // this line should be removed in 3.0
562
            $container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
563
                ->addTag('api_platform.metadata.property_schema_restriction');
564
        }
565
566
        if (!$config['validator']) {
567
            return;
568
        }
569
570
        $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']);
571
    }
572
573
    private function registerDataCollectorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
574
    {
575
        if (!$config['enable_profiler']) {
576
            return;
577
        }
578
579
        $loader->load('data_collector.xml');
580
581
        if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
582
            $loader->load('debug.xml');
583
        }
584
    }
585
586
    private function registerMercureConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
587
    {
588
        if (!$this->isConfigEnabled($container, $config['mercure'])) {
589
            return;
590
        }
591
592
        $loader->load('mercure.xml');
593
        $container->getDefinition('api_platform.mercure.listener.response.add_link_header')->addArgument($config['mercure']['hub_url'] ?? '%mercure.default_hub%');
594
595
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
596
            $loader->load('doctrine_orm_mercure_publisher.xml');
597
        }
598
        if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
599
            $loader->load('doctrine_mongodb_odm_mercure_publisher.xml');
600
        }
601
602
        if ($this->isConfigEnabled($container, $config['graphql'])) {
603
            $loader->load('graphql_mercure.xml');
604
            $container->getDefinition('api_platform.graphql.subscription.mercure_iri_generator')->addArgument($config['mercure']['hub_url'] ?? '%mercure.default_hub%');
605
        }
606
    }
607
608
    private function registerMessengerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
609
    {
610
        if (!$this->isConfigEnabled($container, $config['messenger'])) {
611
            return;
612
        }
613
614
        $loader->load('messenger.xml');
615
    }
616
617
    private function registerElasticsearchConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
618
    {
619
        $enabled = $this->isConfigEnabled($container, $config['elasticsearch']);
620
621
        $container->setParameter('api_platform.elasticsearch.enabled', $enabled);
622
623
        if (!$enabled) {
624
            return;
625
        }
626
627
        $loader->load('elasticsearch.xml');
628
629
        $container->registerForAutoconfiguration(RequestBodySearchCollectionExtensionInterface::class)
630
            ->addTag('api_platform.elasticsearch.request_body_search_extension.collection');
631
632
        $container->setParameter('api_platform.elasticsearch.hosts', $config['elasticsearch']['hosts']);
633
        $container->setParameter('api_platform.elasticsearch.mapping', $config['elasticsearch']['mapping']);
634
    }
635
636
    private function registerDataTransformerConfiguration(ContainerBuilder $container): void
637
    {
638
        $container->registerForAutoconfiguration(DataTransformerInterface::class)
639
            ->addTag('api_platform.data_transformer');
640
    }
641
642
    private function registerSecurityConfiguration(ContainerBuilder $container, XmlFileLoader $loader): void
643
    {
644
        /** @var string[] $bundles */
645
        $bundles = $container->getParameter('kernel.bundles');
646
647
        if (isset($bundles['SecurityBundle'])) {
648
            $loader->load('security.xml');
649
        }
650
    }
651
}
652