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

api-platform / core / 17062168720

19 Aug 2025 07:04AM UTC coverage: 22.236%. First build
17062168720

Pull #7299

github

web-flow
Merge bde86e9a2 into 6491bfc7a
Pull Request #7299: feat(symfony): stop watch system provider/processor

34 of 36 new or added lines in 10 files covered. (94.44%)

11683 of 52542 relevant lines covered (22.24%)

24.04 hits per line

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

77.18
/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
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\Symfony\Bundle\DependencyInjection;
15

16
use ApiPlatform\Doctrine\Odm\Extension\AggregationCollectionExtensionInterface;
17
use ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface;
18
use ApiPlatform\Doctrine\Odm\Filter\AbstractFilter as DoctrineMongoDbOdmAbstractFilter;
19
use ApiPlatform\Doctrine\Odm\State\LinksHandlerInterface as OdmLinksHandlerInterface;
20
use ApiPlatform\Doctrine\Orm\Extension\EagerLoadingExtension;
21
use ApiPlatform\Doctrine\Orm\Extension\FilterEagerLoadingExtension;
22
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface as DoctrineQueryCollectionExtensionInterface;
23
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
24
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter as DoctrineOrmAbstractFilter;
25
use ApiPlatform\Doctrine\Orm\State\LinksHandlerInterface as OrmLinksHandlerInterface;
26
use ApiPlatform\Elasticsearch\Extension\RequestBodySearchCollectionExtensionInterface;
27
use ApiPlatform\GraphQl\Error\ErrorHandlerInterface;
28
use ApiPlatform\GraphQl\Executor;
29
use ApiPlatform\GraphQl\Resolver\MutationResolverInterface;
30
use ApiPlatform\GraphQl\Resolver\QueryCollectionResolverInterface;
31
use ApiPlatform\GraphQl\Resolver\QueryItemResolverInterface;
32
use ApiPlatform\GraphQl\Type\Definition\TypeInterface as GraphQlTypeInterface;
33
use ApiPlatform\Metadata\ApiResource;
34
use ApiPlatform\Metadata\AsOperationMutator;
35
use ApiPlatform\Metadata\AsResourceMutator;
36
use ApiPlatform\Metadata\FilterInterface;
37
use ApiPlatform\Metadata\OperationMutatorInterface;
38
use ApiPlatform\Metadata\ResourceMutatorInterface;
39
use ApiPlatform\Metadata\UriVariableTransformerInterface;
40
use ApiPlatform\Metadata\UrlGeneratorInterface;
41
use ApiPlatform\OpenApi\Model\Tag;
42
use ApiPlatform\RamseyUuid\Serializer\UuidDenormalizer;
43
use ApiPlatform\State\ApiResource\Error;
44
use ApiPlatform\State\ParameterProviderInterface;
45
use ApiPlatform\State\ProcessorInterface;
46
use ApiPlatform\State\ProviderInterface;
47
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRestrictionMetadataInterface;
48
use ApiPlatform\Symfony\Validator\ValidationGroupsGeneratorInterface;
49
use ApiPlatform\Validator\Exception\ValidationException;
50
use Doctrine\Persistence\ManagerRegistry;
51
use PHPStan\PhpDocParser\Parser\PhpDocParser;
52
use Ramsey\Uuid\Uuid;
53
use Symfony\Component\Config\FileLocator;
54
use Symfony\Component\Config\Resource\DirectoryResource;
55
use Symfony\Component\DependencyInjection\ChildDefinition;
56
use Symfony\Component\DependencyInjection\ContainerBuilder;
57
use Symfony\Component\DependencyInjection\Definition;
58
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
59
use Symfony\Component\DependencyInjection\Extension\Extension;
60
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
61
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
62
use Symfony\Component\DependencyInjection\Reference;
63
use Symfony\Component\Finder\Finder;
64
use Symfony\Component\HttpClient\ScopingHttpClient;
65
use Symfony\Component\ObjectMapper\ObjectMapper;
66
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
67
use Symfony\Component\Uid\AbstractUid;
68
use Symfony\Component\Validator\Validator\ValidatorInterface;
69
use Symfony\Component\Yaml\Yaml;
70
use Twig\Environment;
71

72
/**
73
 * The extension of this bundle.
74
 *
75
 * @author Kévin Dunglas <dunglas@gmail.com>
76
 */
77
final class ApiPlatformExtension extends Extension implements PrependExtensionInterface
78
{
79
    /**
80
     * {@inheritdoc}
81
     */
82
    public function prepend(ContainerBuilder $container): void
83
    {
84
        if (isset($container->getExtensions()['framework'])) {
4✔
85
            $container->prependExtensionConfig('framework', [
4✔
86
                'serializer' => [
4✔
87
                    'enabled' => true,
4✔
88
                ],
4✔
89
            ]);
4✔
90
            $container->prependExtensionConfig('framework', [
4✔
91
                'property_info' => [
4✔
92
                    'enabled' => true,
4✔
93
                ],
4✔
94
            ]);
4✔
95
        }
96
        if (isset($container->getExtensions()['lexik_jwt_authentication'])) {
4✔
97
            $container->prependExtensionConfig('lexik_jwt_authentication', [
×
98
                'api_platform' => [
×
99
                    'enabled' => true,
×
100
                ],
×
101
            ]);
×
102
        }
103
    }
104

105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function load(array $configs, ContainerBuilder $container): void
109
    {
110
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
4✔
111

112
        $configuration = new Configuration();
4✔
113
        $config = $this->processConfiguration($configuration, $configs);
4✔
114
        $container->setParameter('api_platform.use_symfony_listeners', $config['use_symfony_listeners']);
4✔
115

116
        $formats = $this->getFormats($config['formats']);
4✔
117
        $patchFormats = $this->getFormats($config['patch_formats']);
4✔
118
        $errorFormats = $this->getFormats($config['error_formats']);
4✔
119
        $docsFormats = $this->getFormats($config['docs_formats']);
4✔
120

121
        if (!$config['enable_docs']) {
4✔
122
            // JSON-LD documentation format is mandatory, even if documentation is disabled.
123
            $docsFormats = isset($formats['jsonld']) ? ['jsonld' => ['application/ld+json']] : [];
×
124
            // If documentation is disabled, the Hydra documentation for all the resources is hidden by default.
125
            if (!isset($config['defaults']['hideHydraOperation']) && !isset($config['defaults']['hide_hydra_operation'])) {
×
126
                $config['defaults']['hideHydraOperation'] = true;
×
127
            }
128
        }
129
        $jsonSchemaFormats = $config['jsonschema_formats'];
4✔
130

131
        if (!$jsonSchemaFormats) {
4✔
132
            foreach (array_merge(array_keys($formats), array_keys($errorFormats)) as $f) {
4✔
133
                // Distinct JSON-based formats must have names that start with 'json'
134
                if (str_starts_with($f, 'json')) {
4✔
135
                    $jsonSchemaFormats[$f] = true;
4✔
136
                }
137
            }
138
        }
139

140
        if (!isset($errorFormats['json'])) {
4✔
141
            $errorFormats['json'] = ['application/problem+json', 'application/json'];
4✔
142
        }
143

144
        if (!isset($errorFormats['jsonproblem'])) {
4✔
145
            $errorFormats['jsonproblem'] = ['application/problem+json'];
×
146
        }
147

148
        if (isset($formats['jsonapi']) && !isset($patchFormats['jsonapi'])) {
4✔
149
            $patchFormats['jsonapi'] = ['application/vnd.api+json'];
4✔
150
        }
151

152
        $this->registerCommonConfiguration($container, $config, $loader, $formats, $patchFormats, $errorFormats, $docsFormats);
4✔
153
        $this->registerMetadataConfiguration($container, $config, $loader);
4✔
154
        $this->registerOAuthConfiguration($container, $config);
4✔
155
        $this->registerOpenApiConfiguration($container, $config, $loader);
4✔
156
        $this->registerSwaggerConfiguration($container, $config, $loader);
4✔
157
        $this->registerJsonApiConfiguration($formats, $loader, $config);
4✔
158
        $this->registerJsonLdHydraConfiguration($container, $formats, $loader, $config);
4✔
159
        $this->registerJsonHalConfiguration($formats, $loader);
4✔
160
        $this->registerJsonProblemConfiguration($errorFormats, $loader);
4✔
161
        $this->registerGraphQlConfiguration($container, $config, $loader);
4✔
162
        $this->registerCacheConfiguration($container);
4✔
163
        $this->registerDoctrineOrmConfiguration($container, $config, $loader);
4✔
164
        $this->registerDoctrineMongoDbOdmConfiguration($container, $config, $loader);
4✔
165
        $this->registerHttpCacheConfiguration($container, $config, $loader);
4✔
166
        $this->registerValidatorConfiguration($container, $config, $loader);
4✔
167
        $this->registerDataCollectorConfiguration($container, $config, $loader);
4✔
168
        $this->registerMercureConfiguration($container, $config, $loader);
4✔
169
        $this->registerMessengerConfiguration($container, $config, $loader);
4✔
170
        $this->registerElasticsearchConfiguration($container, $config, $loader);
4✔
171
        $this->registerSecurityConfiguration($container, $config, $loader);
4✔
172
        $this->registerMakerConfiguration($container, $config, $loader);
4✔
173
        $this->registerArgumentResolverConfiguration($loader);
4✔
174
        $this->registerLinkSecurityConfiguration($loader, $config);
4✔
175

176
        if (class_exists(ObjectMapper::class)) {
4✔
177
            $loader->load('state/object_mapper.xml');
4✔
178
        }
179
        $container->registerForAutoconfiguration(FilterInterface::class)
4✔
180
            ->addTag('api_platform.filter');
4✔
181
        $container->registerForAutoconfiguration(ProviderInterface::class)
4✔
182
            ->addTag('api_platform.state_provider');
4✔
183
        $container->registerForAutoconfiguration(ProcessorInterface::class)
4✔
184
            ->addTag('api_platform.state_processor');
4✔
185
        $container->registerForAutoconfiguration(UriVariableTransformerInterface::class)
4✔
186
            ->addTag('api_platform.uri_variables.transformer');
4✔
187
        $container->registerForAutoconfiguration(ParameterProviderInterface::class)
4✔
188
            ->addTag('api_platform.parameter_provider');
4✔
189
        $container->registerAttributeForAutoconfiguration(ApiResource::class, static function (ChildDefinition $definition): void {
4✔
190
            $definition->setAbstract(true)
×
191
                ->addTag('api_platform.resource')
×
192
                ->addTag('container.excluded', ['source' => 'by #[ApiResource] attribute']);
×
193
        });
4✔
194
        $container->registerAttributeForAutoconfiguration(AsResourceMutator::class,
4✔
195
            static function (ChildDefinition $definition, AsResourceMutator $attribute, \Reflector $reflector): void {
4✔
196
                if (!$reflector instanceof \ReflectionClass) {
×
197
                    return;
×
198
                }
199

200
                if (!is_a($reflector->name, ResourceMutatorInterface::class, true)) {
×
201
                    throw new RuntimeException(\sprintf('Resource mutator "%s" should implement %s', $reflector->name, ResourceMutatorInterface::class));
×
202
                }
203

204
                $definition->addTag('api_platform.resource_mutator', [
×
205
                    'resourceClass' => $attribute->resourceClass,
×
206
                ]);
×
207
            },
4✔
208
        );
4✔
209

210
        $container->registerAttributeForAutoconfiguration(AsOperationMutator::class,
4✔
211
            static function (ChildDefinition $definition, AsOperationMutator $attribute, \Reflector $reflector): void {
4✔
212
                if (!$reflector instanceof \ReflectionClass) {
×
213
                    return;
×
214
                }
215

216
                if (!is_a($reflector->name, OperationMutatorInterface::class, true)) {
×
217
                    throw new RuntimeException(\sprintf('Operation mutator "%s" should implement %s', $reflector->name, OperationMutatorInterface::class));
×
218
                }
219

220
                $definition->addTag('api_platform.operation_mutator', [
×
221
                    'operationName' => $attribute->operationName,
×
222
                ]);
×
223
            },
4✔
224
        );
4✔
225

226
        if (!$container->has('api_platform.state.item_provider')) {
4✔
227
            $container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
×
228
        }
229

230
        if ($container->getParameter('kernel.debug')) {
4✔
231
            $this->injectStopwatch($container);
4✔
232
        }
233
    }
234

235
    private function injectStopwatch(ContainerBuilder $container): void
236
    {
237
        $services = [
4✔
238
            'api_platform.state_processor.add_link_header',
4✔
239
            'api_platform.state_processor.respond',
4✔
240
            'api_platform.state_processor.serialize',
4✔
241
            'api_platform.state_processor.write',
4✔
242
            'api_platform.state_provider.content_negotiation',
4✔
243
            'api_platform.state_provider.deserialize',
4✔
244
            'api_platform.state_provider.parameter',
4✔
245
            'api_platform.state_provider.read',
4✔
246
        ];
4✔
247

248
        foreach ($services as $id) {
4✔
249
            if (!$container->hasDefinition($id)) {
4✔
NEW
250
                continue;
×
251
            }
252

253
            $definition = $container->getDefinition($id);
4✔
254
            $definition->addMethodCall('setStopwatch', [new Reference('debug.stopwatch', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE)]);
4✔
255
        }
256
    }
257

258
    private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats): void
259
    {
260
        $loader->load('state/state.xml');
4✔
261
        $loader->load('symfony/symfony.xml');
4✔
262
        $loader->load('api.xml');
4✔
263
        $loader->load('filter.xml');
4✔
264

265
        if (class_exists(UuidDenormalizer::class) && class_exists(Uuid::class)) {
4✔
266
            $loader->load('ramsey_uuid.xml');
4✔
267
        }
268

269
        if (class_exists(AbstractUid::class)) {
4✔
270
            $loader->load('symfony/uid.xml');
4✔
271
        }
272

273
        $defaultContext = ['hydra_prefix' => $config['serializer']['hydra_prefix']] + ($container->hasParameter('serializer.default_context') ? $container->getParameter('serializer.default_context') : []);
4✔
274

275
        $container->setParameter('api_platform.serializer.default_context', $defaultContext);
4✔
276
        if (!$container->hasParameter('serializer.default_context')) {
4✔
277
            $container->setParameter('serializer.default_context', $container->getParameter('api_platform.serializer.default_context'));
4✔
278
        }
279
        if ($config['use_symfony_listeners']) {
4✔
280
            $loader->load('symfony/events.xml');
2✔
281
        } else {
282
            $loader->load('symfony/controller.xml');
2✔
283
            $loader->load('state/provider.xml');
2✔
284
            $loader->load('state/processor.xml');
2✔
285
        }
286
        $loader->load('state/parameter_provider.xml');
4✔
287

288
        $container->setParameter('api_platform.enable_entrypoint', $config['enable_entrypoint']);
4✔
289
        $container->setParameter('api_platform.enable_docs', $config['enable_docs']);
4✔
290
        $container->setParameter('api_platform.title', $config['title']);
4✔
291
        $container->setParameter('api_platform.description', $config['description']);
4✔
292
        $container->setParameter('api_platform.version', $config['version']);
4✔
293
        $container->setParameter('api_platform.show_webby', $config['show_webby']);
4✔
294
        $container->setParameter('api_platform.url_generation_strategy', $config['defaults']['url_generation_strategy'] ?? UrlGeneratorInterface::ABS_PATH);
4✔
295
        $container->setParameter('api_platform.exception_to_status', $config['exception_to_status']);
4✔
296
        $container->setParameter('api_platform.formats', $formats);
4✔
297
        $container->setParameter('api_platform.patch_formats', $patchFormats);
4✔
298
        $container->setParameter('api_platform.error_formats', $errorFormats);
4✔
299
        $container->setParameter('api_platform.docs_formats', $docsFormats);
4✔
300
        $container->setParameter('api_platform.jsonschema_formats', []);
4✔
301
        $container->setParameter('api_platform.eager_loading.enabled', $this->isConfigEnabled($container, $config['eager_loading']));
4✔
302
        $container->setParameter('api_platform.eager_loading.max_joins', $config['eager_loading']['max_joins']);
4✔
303
        $container->setParameter('api_platform.eager_loading.fetch_partial', $config['eager_loading']['fetch_partial']);
4✔
304
        $container->setParameter('api_platform.eager_loading.force_eager', $config['eager_loading']['force_eager']);
4✔
305
        $container->setParameter('api_platform.collection.exists_parameter_name', $config['collection']['exists_parameter_name']);
4✔
306
        $container->setParameter('api_platform.collection.order', $config['collection']['order']);
4✔
307
        $container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']);
4✔
308
        $container->setParameter('api_platform.collection.order_nulls_comparison', $config['collection']['order_nulls_comparison']);
4✔
309
        $container->setParameter('api_platform.collection.pagination.enabled', $config['defaults']['pagination_enabled'] ?? true);
4✔
310
        $container->setParameter('api_platform.collection.pagination.partial', $config['defaults']['pagination_partial'] ?? false);
4✔
311
        $container->setParameter('api_platform.collection.pagination.client_enabled', $config['defaults']['pagination_client_enabled'] ?? false);
4✔
312
        $container->setParameter('api_platform.collection.pagination.client_items_per_page', $config['defaults']['pagination_client_items_per_page'] ?? false);
4✔
313
        $container->setParameter('api_platform.collection.pagination.client_partial', $config['defaults']['pagination_client_partial'] ?? false);
4✔
314
        $container->setParameter('api_platform.collection.pagination.items_per_page', $config['defaults']['pagination_items_per_page'] ?? 30);
4✔
315
        $container->setParameter('api_platform.collection.pagination.maximum_items_per_page', $config['defaults']['pagination_maximum_items_per_page'] ?? null);
4✔
316
        $container->setParameter('api_platform.collection.pagination.page_parameter_name', $config['defaults']['pagination_page_parameter_name'] ?? $config['collection']['pagination']['page_parameter_name']);
4✔
317
        $container->setParameter('api_platform.collection.pagination.enabled_parameter_name', $config['defaults']['pagination_enabled_parameter_name'] ?? $config['collection']['pagination']['enabled_parameter_name']);
4✔
318
        $container->setParameter('api_platform.collection.pagination.items_per_page_parameter_name', $config['defaults']['pagination_items_per_page_parameter_name'] ?? $config['collection']['pagination']['items_per_page_parameter_name']);
4✔
319
        $container->setParameter('api_platform.collection.pagination.partial_parameter_name', $config['defaults']['pagination_partial_parameter_name'] ?? $config['collection']['pagination']['partial_parameter_name']);
4✔
320
        $container->setParameter('api_platform.collection.pagination', $this->getPaginationDefaults($config['defaults'] ?? [], $config['collection']['pagination']));
4✔
321
        $container->setParameter('api_platform.handle_symfony_errors', $config['handle_symfony_errors'] ?? false);
4✔
322
        $container->setParameter('api_platform.http_cache.etag', $config['defaults']['cache_headers']['etag'] ?? true);
4✔
323
        $container->setParameter('api_platform.http_cache.max_age', $config['defaults']['cache_headers']['max_age'] ?? null);
4✔
324
        $container->setParameter('api_platform.http_cache.shared_max_age', $config['defaults']['cache_headers']['shared_max_age'] ?? null);
4✔
325
        $container->setParameter('api_platform.http_cache.vary', $config['defaults']['cache_headers']['vary'] ?? ['Accept']);
4✔
326
        $container->setParameter('api_platform.http_cache.public', $config['defaults']['cache_headers']['public'] ?? $config['http_cache']['public']);
4✔
327
        $container->setParameter('api_platform.http_cache.invalidation.max_header_length', $config['defaults']['cache_headers']['invalidation']['max_header_length'] ?? $config['http_cache']['invalidation']['max_header_length']);
4✔
328
        $container->setParameter('api_platform.http_cache.invalidation.xkey.glue', $config['defaults']['cache_headers']['invalidation']['xkey']['glue'] ?? $config['http_cache']['invalidation']['xkey']['glue']);
4✔
329

330
        $container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
4✔
331
        $container->setAlias('api_platform.inflector', $config['inflector']);
4✔
332

333
        if ($config['name_converter']) {
4✔
334
            $container->setAlias('api_platform.name_converter', $config['name_converter']);
4✔
335
        }
336
        $container->setParameter('api_platform.asset_package', $config['asset_package']);
4✔
337
        $container->setParameter('api_platform.defaults', $this->normalizeDefaults($config['defaults'] ?? []));
4✔
338

339
        if ($container->getParameter('kernel.debug')) {
4✔
340
            $container->removeDefinition('api_platform.serializer.mapping.cache_class_metadata_factory');
4✔
341
        }
342
    }
343

344
    /**
345
     * This method will be removed in 3.0 when "defaults" will be the regular configuration path for the pagination.
346
     */
347
    private function getPaginationDefaults(array $defaults, array $collectionPaginationConfiguration): array
348
    {
349
        $paginationOptions = [];
4✔
350

351
        foreach ($defaults as $key => $value) {
4✔
352
            if (!str_starts_with($key, 'pagination_')) {
4✔
353
                continue;
4✔
354
            }
355

356
            $paginationOptions[str_replace('pagination_', '', $key)] = $value;
4✔
357
        }
358

359
        return array_merge($collectionPaginationConfiguration, $paginationOptions);
4✔
360
    }
361

362
    private function normalizeDefaults(array $defaults): array
363
    {
364
        $normalizedDefaults = ['extra_properties' => $defaults['extra_properties'] ?? []];
4✔
365
        unset($defaults['extra_properties']);
4✔
366

367
        $rc = new \ReflectionClass(ApiResource::class);
4✔
368
        $publicProperties = [];
4✔
369
        foreach ($rc->getConstructor()->getParameters() as $param) {
4✔
370
            $publicProperties[$param->getName()] = true;
4✔
371
        }
372

373
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
4✔
374
        foreach ($defaults as $option => $value) {
4✔
375
            if (isset($publicProperties[$nameConverter->denormalize($option)])) {
4✔
376
                $normalizedDefaults[$option] = $value;
4✔
377

378
                continue;
4✔
379
            }
380

381
            $normalizedDefaults['extra_properties'][$option] = $value;
×
382
        }
383

384
        return $normalizedDefaults;
4✔
385
    }
386

387
    private function registerMetadataConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
388
    {
389
        [$xmlResources, $yamlResources, $phpResources] = $this->getResourcesToWatch($container, $config);
4✔
390

391
        $container->setParameter('api_platform.class_name_resources', $this->getClassNameResources());
4✔
392

393
        $loader->load('metadata/resource_name.xml');
4✔
394
        $loader->load('metadata/property_name.xml');
4✔
395

396
        if (!empty($config['resource_class_directories'])) {
4✔
397
            $container->setParameter('api_platform.resource_class_directories', array_merge(
×
398
                $config['resource_class_directories'],
×
399
                $container->getParameter('api_platform.resource_class_directories')
×
400
            ));
×
401
        }
402

403
        // V3 metadata
404
        $loader->load('metadata/php.xml');
4✔
405
        $loader->load('metadata/xml.xml');
4✔
406
        $loader->load('metadata/links.xml');
4✔
407
        $loader->load('metadata/property.xml');
4✔
408
        $loader->load('metadata/resource.xml');
4✔
409
        $loader->load('metadata/operation.xml');
4✔
410
        $loader->load('metadata/mutator.xml');
4✔
411

412
        $container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
4✔
413
        $container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
4✔
414

415
        if (class_exists(PhpDocParser::class)) {
4✔
416
            $loader->load('metadata/php_doc.xml');
4✔
417
        }
418

419
        if (class_exists(Yaml::class)) {
4✔
420
            $loader->load('metadata/yaml.xml');
4✔
421
            $container->getDefinition('api_platform.metadata.resource_extractor.yaml')->replaceArgument(0, $yamlResources);
4✔
422
            $container->getDefinition('api_platform.metadata.property_extractor.yaml')->replaceArgument(0, $yamlResources);
4✔
423
        }
424

425
        $container->getDefinition('api_platform.metadata.resource_extractor.php_file')->replaceArgument(0, $phpResources);
4✔
426
    }
427

428
    private function getClassNameResources(): array
429
    {
430
        return [
4✔
431
            Error::class,
4✔
432
            ValidationException::class,
4✔
433
        ];
4✔
434
    }
435

436
    private function getBundlesResourcesPaths(ContainerBuilder $container, array $config): array
437
    {
438
        $bundlesResourcesPaths = [];
4✔
439

440
        foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
4✔
441
            $dirname = $bundle['path'];
4✔
442
            $paths = [
4✔
443
                "$dirname/ApiResource",
4✔
444
                "$dirname/src/ApiResource",
4✔
445
            ];
4✔
446
            foreach (['.yaml', '.yml', '.xml', ''] as $extension) {
4✔
447
                $paths[] = "$dirname/Resources/config/api_resources$extension";
4✔
448
                $paths[] = "$dirname/config/api_resources$extension";
4✔
449
            }
450
            if ($this->isConfigEnabled($container, $config['doctrine'])) {
4✔
451
                $paths[] = "$dirname/Entity";
4✔
452
                $paths[] = "$dirname/src/Entity";
4✔
453
            }
454
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
4✔
455
                $paths[] = "$dirname/Document";
×
456
                $paths[] = "$dirname/src/Document";
×
457
            }
458

459
            foreach ($paths as $path) {
4✔
460
                if ($container->fileExists($path, false)) {
4✔
461
                    $bundlesResourcesPaths[] = $path;
4✔
462
                }
463
            }
464
        }
465

466
        return $bundlesResourcesPaths;
4✔
467
    }
468

469
    private function getResourcesToWatch(ContainerBuilder $container, array $config): array
470
    {
471
        $paths = array_unique(array_merge($this->getBundlesResourcesPaths($container, $config), $config['mapping']['paths']));
4✔
472

473
        if (!$config['mapping']['paths']) {
4✔
474
            $projectDir = $container->getParameter('kernel.project_dir');
×
475
            foreach (["$projectDir/config/api_platform", "$projectDir/src/ApiResource"] as $dir) {
×
476
                if (is_dir($dir)) {
×
477
                    $paths[] = $dir;
×
478
                }
479
            }
480

481
            if ($this->isConfigEnabled($container, $config['doctrine']) && is_dir($doctrinePath = "$projectDir/src/Entity")) {
×
482
                $paths[] = $doctrinePath;
×
483
            }
484

485
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm']) && is_dir($documentPath = "$projectDir/src/Document")) {
×
486
                $paths[] = $documentPath;
×
487
            }
488
        }
489

490
        $resources = ['yml' => [], 'xml' => [], 'php' => [], 'dir' => []];
4✔
491

492
        foreach ($config['mapping']['imports'] ?? [] as $path) {
4✔
493
            if (is_dir($path)) {
×
494
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.php$/')->sortByName() as $file) {
×
495
                    $resources[$file->getExtension()][] = $file->getRealPath();
×
496
                }
497

498
                $resources['dir'][] = $path;
×
499
                $container->addResource(new DirectoryResource($path, '/\.php$/'));
×
500

501
                continue;
×
502
            }
503

504
            if ($container->fileExists($path, false)) {
×
505
                if (!str_ends_with($path, '.php')) {
×
506
                    throw new RuntimeException(\sprintf('Unsupported mapping type in "%s", supported type is PHP.', $path));
×
507
                }
508

509
                $resources['php'][] = $path;
×
510

511
                continue;
×
512
            }
513

514
            throw new RuntimeException(\sprintf('Could not open file or directory "%s".', $path));
×
515
        }
516

517
        foreach ($paths as $path) {
4✔
518
            if (is_dir($path)) {
4✔
519
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.(xml|ya?ml)$/')->sortByName() as $file) {
4✔
520
                    $resources['yaml' === ($extension = $file->getExtension()) ? 'yml' : $extension][] = $file->getRealPath();
4✔
521
                }
522

523
                $resources['dir'][] = $path;
4✔
524
                $container->addResource(new DirectoryResource($path, '/\.(xml|ya?ml|php)$/'));
4✔
525

526
                continue;
4✔
527
            }
528

529
            if ($container->fileExists($path, false)) {
×
530
                if (!preg_match('/\.(xml|ya?ml)$/', (string) $path, $matches)) {
×
531
                    throw new RuntimeException(\sprintf('Unsupported mapping type in "%s", supported types are XML & YAML.', $path));
×
532
                }
533

534
                $resources['yaml' === $matches[1] ? 'yml' : $matches[1]][] = $path;
×
535

536
                continue;
×
537
            }
538

539
            throw new RuntimeException(\sprintf('Could not open file or directory "%s".', $path));
×
540
        }
541

542
        $container->setParameter('api_platform.resource_class_directories', $resources['dir']);
4✔
543

544
        return [$resources['xml'], $resources['yml'], $resources['php']];
4✔
545
    }
546

547
    private function registerOAuthConfiguration(ContainerBuilder $container, array $config): void
548
    {
549
        if (!$config['oauth']) {
4✔
550
            return;
×
551
        }
552

553
        $container->setParameter('api_platform.oauth.enabled', $this->isConfigEnabled($container, $config['oauth']));
4✔
554
        $container->setParameter('api_platform.oauth.clientId', $config['oauth']['clientId']);
4✔
555
        $container->setParameter('api_platform.oauth.clientSecret', $config['oauth']['clientSecret']);
4✔
556
        $container->setParameter('api_platform.oauth.type', $config['oauth']['type']);
4✔
557
        $container->setParameter('api_platform.oauth.flow', $config['oauth']['flow']);
4✔
558
        $container->setParameter('api_platform.oauth.tokenUrl', $config['oauth']['tokenUrl']);
4✔
559
        $container->setParameter('api_platform.oauth.authorizationUrl', $config['oauth']['authorizationUrl']);
4✔
560
        $container->setParameter('api_platform.oauth.refreshUrl', $config['oauth']['refreshUrl']);
4✔
561
        $container->setParameter('api_platform.oauth.scopes', $config['oauth']['scopes']);
4✔
562
        $container->setParameter('api_platform.oauth.pkce', $config['oauth']['pkce']);
4✔
563
    }
564

565
    /**
566
     * Registers the Swagger, ReDoc and Swagger UI configuration.
567
     */
568
    private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
569
    {
570
        foreach (array_keys($config['swagger']['api_keys']) as $keyName) {
4✔
571
            if (!preg_match('/^[a-zA-Z0-9._-]+$/', $keyName)) {
4✔
572
                throw new RuntimeException(\sprintf('The swagger api_keys key "%s" is not valid, it should match "^[a-zA-Z0-9._-]+$"', $keyName));
×
573
            }
574
        }
575

576
        $container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
4✔
577

578
        if (!$config['enable_swagger'] && $config['enable_swagger_ui']) {
4✔
579
            throw new RuntimeException('You can not enable the Swagger UI without enabling Swagger, fix this by enabling swagger via the configuration "enable_swagger: true".');
×
580
        }
581

582
        if (!$config['enable_swagger']) {
4✔
583
            return;
×
584
        }
585

586
        $loader->load('openapi.xml');
4✔
587

588
        if (class_exists(Yaml::class)) {
4✔
589
            $loader->load('openapi/yaml.xml');
4✔
590
        }
591

592
        $loader->load('swagger_ui.xml');
4✔
593

594
        if ($config['use_symfony_listeners']) {
4✔
595
            $loader->load('symfony/swagger_ui.xml');
2✔
596
        }
597

598
        if ($config['enable_swagger_ui']) {
4✔
599
            $loader->load('state/swagger_ui.xml');
4✔
600
        }
601

602
        if (!$config['enable_swagger_ui'] && !$config['enable_re_doc']) {
4✔
603
            // Remove the listener but keep the controller to allow customizing the path of the UI
604
            $container->removeDefinition('api_platform.swagger.listener.ui');
×
605
        }
606

607
        $container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']);
4✔
608
        $container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
4✔
609
        $container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
4✔
610
        $container->setParameter('api_platform.swagger.persist_authorization', $config['swagger']['persist_authorization']);
4✔
611
        $container->setParameter('api_platform.swagger.http_auth', $config['swagger']['http_auth']);
4✔
612
        if ($config['openapi']['swagger_ui_extra_configuration'] && $config['swagger']['swagger_ui_extra_configuration']) {
4✔
613
            throw new RuntimeException('You can not set "swagger_ui_extra_configuration" twice - in "openapi" and "swagger" section.');
×
614
        }
615
        $container->setParameter('api_platform.swagger_ui.extra_configuration', $config['openapi']['swagger_ui_extra_configuration'] ?: $config['swagger']['swagger_ui_extra_configuration']);
4✔
616
    }
617

618
    private function registerJsonApiConfiguration(array $formats, XmlFileLoader $loader, array $config): void
619
    {
620
        if (!isset($formats['jsonapi'])) {
4✔
621
            return;
×
622
        }
623

624
        $loader->load('jsonapi.xml');
4✔
625
        $loader->load('state/jsonapi.xml');
4✔
626
    }
627

628
    private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, XmlFileLoader $loader, array $config): void
629
    {
630
        if (!isset($formats['jsonld'])) {
4✔
631
            return;
×
632
        }
633

634
        if ($config['use_symfony_listeners']) {
4✔
635
            $loader->load('symfony/jsonld.xml');
2✔
636
        } else {
637
            $loader->load('state/jsonld.xml');
2✔
638
        }
639

640
        $loader->load('state/hydra.xml');
4✔
641
        $loader->load('jsonld.xml');
4✔
642
        $loader->load('hydra.xml');
4✔
643

644
        if (!$container->has('api_platform.json_schema.schema_factory')) {
4✔
645
            $container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
×
646
        }
647
    }
648

649
    private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader): void
650
    {
651
        if (!isset($formats['jsonhal'])) {
4✔
652
            return;
×
653
        }
654

655
        $loader->load('hal.xml');
4✔
656
    }
657

658
    private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLoader $loader): void
659
    {
660
        if (!isset($errorFormats['jsonproblem'])) {
4✔
661
            return;
×
662
        }
663

664
        $loader->load('problem.xml');
4✔
665
    }
666

667
    private function registerGraphQlConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
668
    {
669
        $enabled = $this->isConfigEnabled($container, $config['graphql']);
4✔
670
        $graphqlIntrospectionEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['introspection']);
4✔
671
        $graphiqlEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']);
4✔
672
        $maxQueryDepth = (int) $config['graphql']['max_query_depth'];
4✔
673
        $maxQueryComplexity = (int) $config['graphql']['max_query_complexity'];
4✔
674

675
        $container->setParameter('api_platform.graphql.enabled', $enabled);
4✔
676
        $container->setParameter('api_platform.graphql.max_query_depth', $maxQueryDepth);
4✔
677
        $container->setParameter('api_platform.graphql.max_query_complexity', $maxQueryComplexity);
4✔
678
        $container->setParameter('api_platform.graphql.introspection.enabled', $graphqlIntrospectionEnabled);
4✔
679
        $container->setParameter('api_platform.graphql.graphiql.enabled', $graphiqlEnabled);
4✔
680
        $container->setParameter('api_platform.graphql.collection.pagination', $config['graphql']['collection']['pagination']);
4✔
681

682
        if (!$enabled) {
4✔
683
            return;
×
684
        }
685

686
        if (!class_exists(Executor::class)) {
4✔
687
            throw new \RuntimeException('Graphql is enabled but not installed, run: composer require "api-platform/graphql".');
×
688
        }
689

690
        $container->setParameter('api_platform.graphql.default_ide', $config['graphql']['default_ide']);
4✔
691
        $container->setParameter('api_platform.graphql.nesting_separator', $config['graphql']['nesting_separator']);
4✔
692

693
        $loader->load('graphql.xml');
4✔
694

695
        if (!class_exists(Environment::class) || !isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
4✔
696
            if ($graphiqlEnabled) {
×
697
                throw new RuntimeException(\sprintf('GraphiQL interfaces depend on Twig. Please activate TwigBundle for the %s environnement or disable GraphiQL.', $container->getParameter('kernel.environment')));
×
698
            }
699
            $container->removeDefinition('api_platform.graphql.action.graphiql');
×
700
        }
701

702
        $container->registerForAutoconfiguration(QueryItemResolverInterface::class)
4✔
703
            ->addTag('api_platform.graphql.resolver');
4✔
704
        $container->registerForAutoconfiguration(QueryCollectionResolverInterface::class)
4✔
705
            ->addTag('api_platform.graphql.resolver');
4✔
706
        $container->registerForAutoconfiguration(MutationResolverInterface::class)
4✔
707
            ->addTag('api_platform.graphql.resolver');
4✔
708
        $container->registerForAutoconfiguration(GraphQlTypeInterface::class)
4✔
709
            ->addTag('api_platform.graphql.type');
4✔
710
        $container->registerForAutoconfiguration(ErrorHandlerInterface::class)
4✔
711
            ->addTag('api_platform.graphql.error_handler');
4✔
712
    }
713

714
    private function registerCacheConfiguration(ContainerBuilder $container): void
715
    {
716
        if (!$container->hasParameter('kernel.debug') || !$container->getParameter('kernel.debug')) {
4✔
717
            $container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
×
718
        }
719
    }
720

721
    private function registerDoctrineOrmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
722
    {
723
        if (!$this->isConfigEnabled($container, $config['doctrine'])) {
4✔
724
            return;
×
725
        }
726

727
        // For older versions of doctrine bridge this allows autoconfiguration for filters
728
        if (!$container->has(ManagerRegistry::class)) {
4✔
729
            $container->setAlias(ManagerRegistry::class, 'doctrine');
4✔
730
        }
731

732
        $container->registerForAutoconfiguration(QueryItemExtensionInterface::class)
4✔
733
            ->addTag('api_platform.doctrine.orm.query_extension.item');
4✔
734
        $container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
4✔
735
            ->addTag('api_platform.doctrine.orm.query_extension.collection');
4✔
736
        $container->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class);
4✔
737

738
        $container->registerForAutoconfiguration(OrmLinksHandlerInterface::class)
4✔
739
            ->addTag('api_platform.doctrine.orm.links_handler');
4✔
740

741
        $loader->load('doctrine_orm.xml');
4✔
742

743
        if ($this->isConfigEnabled($container, $config['eager_loading'])) {
4✔
744
            return;
4✔
745
        }
746

747
        $container->removeAlias(EagerLoadingExtension::class);
×
748
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading');
×
749
        $container->removeAlias(FilterEagerLoadingExtension::class);
×
750
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.filter_eager_loading');
×
751
    }
752

753
    private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
754
    {
755
        if (!$this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
4✔
756
            return;
4✔
757
        }
758

759
        $container->registerForAutoconfiguration(AggregationItemExtensionInterface::class)
×
760
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.item');
×
761
        $container->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)
×
762
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection');
×
763
        $container->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
×
764
            ->setBindings(['$managerRegistry' => new Reference('doctrine_mongodb')]);
×
765
        $container->registerForAutoconfiguration(OdmLinksHandlerInterface::class)
×
766
            ->addTag('api_platform.doctrine.odm.links_handler');
×
767

768
        $loader->load('doctrine_mongodb_odm.xml');
×
769
    }
770

771
    private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
772
    {
773
        $loader->load('http_cache.xml');
4✔
774

775
        if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
4✔
776
            return;
×
777
        }
778

779
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
4✔
780
            $loader->load('doctrine_orm_http_cache_purger.xml');
4✔
781
        }
782

783
        $loader->load('state/http_cache_purger.xml');
4✔
784
        $loader->load('http_cache_purger.xml');
4✔
785

786
        foreach ($config['http_cache']['invalidation']['scoped_clients'] as $client) {
4✔
787
            $definition = $container->getDefinition($client);
×
788
            $definition->addTag('api_platform.http_cache.http_client');
×
789
        }
790

791
        if (!($urls = $config['http_cache']['invalidation']['urls'])) {
4✔
792
            $urls = $config['http_cache']['invalidation']['varnish_urls'];
4✔
793
        }
794

795
        foreach ($urls as $key => $url) {
4✔
796
            $definition = new Definition(ScopingHttpClient::class, [new Reference('http_client'), $url, ['base_uri' => $url] + $config['http_cache']['invalidation']['request_options']]);
×
797
            $definition->setFactory([ScopingHttpClient::class, 'forBaseUri']);
×
798
            $definition->addTag('api_platform.http_cache.http_client');
×
799
            $container->setDefinition('api_platform.invalidation_http_client.'.$key, $definition);
×
800
        }
801

802
        $serviceName = $config['http_cache']['invalidation']['purger'];
4✔
803

804
        if (!$container->hasDefinition('api_platform.http_cache.purger')) {
4✔
805
            $container->setAlias('api_platform.http_cache.purger', $serviceName);
4✔
806
        }
807
    }
808

809
    /**
810
     * Normalizes the format from config to the one accepted by Symfony HttpFoundation.
811
     */
812
    private function getFormats(array $configFormats): array
813
    {
814
        $formats = [];
4✔
815
        foreach ($configFormats as $format => $value) {
4✔
816
            foreach ($value['mime_types'] as $mimeType) {
4✔
817
                $formats[$format][] = $mimeType;
4✔
818
            }
819
        }
820

821
        return $formats;
4✔
822
    }
823

824
    private function registerValidatorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
825
    {
826
        if (interface_exists(ValidatorInterface::class)) {
4✔
827
            $loader->load('metadata/validator.xml');
4✔
828
            $loader->load('validator/validator.xml');
4✔
829

830
            if ($this->isConfigEnabled($container, $config['graphql'])) {
4✔
831
                $loader->load('graphql/validator.xml');
4✔
832
            }
833

834
            $loader->load($config['use_symfony_listeners'] ? 'validator/events.xml' : 'validator/state.xml');
4✔
835

836
            $container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
4✔
837
                ->addTag('api_platform.validation_groups_generator');
4✔
838
            $container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
4✔
839
                ->addTag('api_platform.metadata.property_schema_restriction');
4✔
840
        }
841

842
        if (!$config['validator']) {
4✔
843
            return;
×
844
        }
845

846
        $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']);
4✔
847
    }
848

849
    private function registerDataCollectorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
850
    {
851
        if (!$config['enable_profiler']) {
4✔
852
            return;
×
853
        }
854

855
        $loader->load('data_collector.xml');
4✔
856

857
        if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
4✔
858
            $loader->load('debug.xml');
4✔
859
        }
860
    }
861

862
    private function registerMercureConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
863
    {
864
        if (!$this->isConfigEnabled($container, $config['mercure'])) {
4✔
865
            return;
×
866
        }
867

868
        $container->setParameter('api_platform.mercure.include_type', $config['mercure']['include_type']);
4✔
869
        $loader->load('state/mercure.xml');
4✔
870

871
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
4✔
872
            $loader->load('doctrine_orm_mercure_publisher.xml');
4✔
873
        }
874
        if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
4✔
875
            $loader->load('doctrine_odm_mercure_publisher.xml');
×
876
        }
877

878
        if ($this->isConfigEnabled($container, $config['graphql'])) {
4✔
879
            $loader->load('graphql_mercure.xml');
4✔
880
        }
881
    }
882

883
    private function registerMessengerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
884
    {
885
        if (!$this->isConfigEnabled($container, $config['messenger'])) {
4✔
886
            return;
×
887
        }
888

889
        $loader->load('messenger.xml');
4✔
890
    }
891

892
    private function registerElasticsearchConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
893
    {
894
        $enabled = $this->isConfigEnabled($container, $config['elasticsearch']);
4✔
895

896
        $container->setParameter('api_platform.elasticsearch.enabled', $enabled);
4✔
897

898
        if (!$enabled) {
4✔
899
            return;
4✔
900
        }
901

902
        $clientClass = !class_exists(\Elasticsearch\Client::class)
×
903
            // ES v7
×
904
            ? \Elastic\Elasticsearch\Client::class
×
905
            // ES v8 and up
×
906
            : \Elasticsearch\Client::class;
×
907

908
        $clientDefinition = new Definition($clientClass);
×
909
        $container->setDefinition('api_platform.elasticsearch.client', $clientDefinition);
×
910
        $container->registerForAutoconfiguration(RequestBodySearchCollectionExtensionInterface::class)
×
911
            ->addTag('api_platform.elasticsearch.request_body_search_extension.collection');
×
912
        $container->setParameter('api_platform.elasticsearch.hosts', $config['elasticsearch']['hosts']);
×
913
        $loader->load('elasticsearch.xml');
×
914
    }
915

916
    private function registerSecurityConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
917
    {
918
        /** @var string[] $bundles */
919
        $bundles = $container->getParameter('kernel.bundles');
4✔
920

921
        if (!isset($bundles['SecurityBundle'])) {
4✔
922
            return;
×
923
        }
924

925
        $loader->load('security.xml');
4✔
926

927
        $loader->load('state/security.xml');
4✔
928

929
        if (interface_exists(ValidatorInterface::class)) {
4✔
930
            $loader->load('state/security_validator.xml');
4✔
931
        }
932

933
        if ($this->isConfigEnabled($container, $config['graphql'])) {
4✔
934
            $loader->load('graphql/security.xml');
4✔
935
        }
936
    }
937

938
    private function registerOpenApiConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
939
    {
940
        $container->setParameter('api_platform.openapi.termsOfService', $config['openapi']['termsOfService']);
4✔
941
        $container->setParameter('api_platform.openapi.contact.name', $config['openapi']['contact']['name']);
4✔
942
        $container->setParameter('api_platform.openapi.contact.url', $config['openapi']['contact']['url']);
4✔
943
        $container->setParameter('api_platform.openapi.contact.email', $config['openapi']['contact']['email']);
4✔
944
        $container->setParameter('api_platform.openapi.license.name', $config['openapi']['license']['name']);
4✔
945
        $container->setParameter('api_platform.openapi.license.url', $config['openapi']['license']['url']);
4✔
946
        $container->setParameter('api_platform.openapi.license.identifier', $config['openapi']['license']['identifier']);
4✔
947
        $container->setParameter('api_platform.openapi.overrideResponses', $config['openapi']['overrideResponses']);
4✔
948

949
        $tags = [];
4✔
950
        foreach ($config['openapi']['tags'] as $tag) {
4✔
951
            $tags[] = new Tag($tag['name'], $tag['description'] ?? null);
×
952
        }
953

954
        $container->setParameter('api_platform.openapi.tags', $tags);
4✔
955

956
        $container->setParameter('api_platform.openapi.errorResourceClass', $config['openapi']['error_resource_class'] ?? null);
4✔
957
        $container->setParameter('api_platform.openapi.validationErrorResourceClass', $config['openapi']['validation_error_resource_class'] ?? null);
4✔
958

959
        $loader->load('json_schema.xml');
4✔
960
    }
961

962
    private function registerMakerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
963
    {
964
        if (!$this->isConfigEnabled($container, $config['maker'])) {
4✔
965
            return;
×
966
        }
967

968
        $loader->load('maker.xml');
4✔
969
    }
970

971
    private function registerArgumentResolverConfiguration(XmlFileLoader $loader): void
972
    {
973
        $loader->load('argument_resolver.xml');
4✔
974
    }
975

976
    private function registerLinkSecurityConfiguration(XmlFileLoader $loader, array $config): void
977
    {
978
        if ($config['enable_link_security']) {
4✔
979
            $loader->load('link_security.xml');
4✔
980
        }
981
    }
982
}
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