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

api-platform / core / 15681594877

16 Jun 2025 01:03PM UTC coverage: 21.908% (+0.03%) from 21.876%
15681594877

Pull #7213

github

web-flow
Merge 1b3ab0e56 into cff61eab8
Pull Request #7213: feat(metadata) Customize Resource & operations

39 of 101 new or added lines in 10 files covered. (38.61%)

123 existing lines in 11 files now uncovered.

11433 of 52186 relevant lines covered (21.91%)

20.97 hits per line

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

76.8
/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 phpDocumentor\Reflection\DocBlockFactoryInterface;
52
use PHPStan\PhpDocParser\Parser\PhpDocParser;
53
use Ramsey\Uuid\Uuid;
54
use Symfony\Component\Config\FileLocator;
55
use Symfony\Component\Config\Resource\DirectoryResource;
56
use Symfony\Component\DependencyInjection\ChildDefinition;
57
use Symfony\Component\DependencyInjection\ContainerBuilder;
58
use Symfony\Component\DependencyInjection\Definition;
59
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
60
use Symfony\Component\DependencyInjection\Extension\Extension;
61
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
62
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
63
use Symfony\Component\DependencyInjection\Reference;
64
use Symfony\Component\Finder\Finder;
65
use Symfony\Component\HttpClient\ScopingHttpClient;
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'])) {
2✔
85
            $container->prependExtensionConfig('framework', [
2✔
86
                'serializer' => [
2✔
87
                    'enabled' => true,
2✔
88
                ],
2✔
89
            ]);
2✔
90
            $container->prependExtensionConfig('framework', [
2✔
91
                'property_info' => [
2✔
92
                    'enabled' => true,
2✔
93
                ],
2✔
94
            ]);
2✔
95
        }
96
        if (isset($container->getExtensions()['lexik_jwt_authentication'])) {
2✔
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'));
2✔
111

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

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

121
        if (!$config['enable_docs']) {
2✔
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'];
2✔
130

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

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

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

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

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

176
        $container->registerForAutoconfiguration(FilterInterface::class)
2✔
177
            ->addTag('api_platform.filter');
2✔
178
        $container->registerForAutoconfiguration(ProviderInterface::class)
2✔
179
            ->addTag('api_platform.state_provider');
2✔
180
        $container->registerForAutoconfiguration(ProcessorInterface::class)
2✔
181
            ->addTag('api_platform.state_processor');
2✔
182
        $container->registerForAutoconfiguration(UriVariableTransformerInterface::class)
2✔
183
            ->addTag('api_platform.uri_variables.transformer');
2✔
184
        $container->registerForAutoconfiguration(ParameterProviderInterface::class)
2✔
185
            ->addTag('api_platform.parameter_provider');
2✔
186
        $container->registerAttributeForAutoconfiguration(ApiResource::class, static function (ChildDefinition $definition): void {
2✔
187
            $definition->setAbstract(true)
×
188
                ->addTag('api_platform.resource')
×
189
                ->addTag('container.excluded', ['source' => 'by #[ApiResource] attribute']);
×
190
        });
2✔
191
        $container->registerAttributeForAutoconfiguration(AsResourceMutator::class,
2✔
192
            static function (ChildDefinition $definition, AsResourceMutator $attribute, \ReflectionClass $reflector): void {
2✔
NEW
193
                if (!is_a($reflector->name, ResourceMutatorInterface::class, true)) {
×
NEW
194
                    throw new RuntimeException(\sprintf('Resource mutator "%s" should implement %s', $reflector->name, ResourceMutatorInterface::class));
×
195
                }
196

NEW
197
                $definition->addTag('api_platform.resource_mutator', [
×
NEW
198
                    'resourceClass' => $attribute->resourceClass,
×
NEW
199
                ]);
×
200
            },
2✔
201
        );
2✔
202

203
        $container->registerAttributeForAutoconfiguration(AsOperationMutator::class,
2✔
204
            static function (ChildDefinition $definition, AsOperationMutator $attribute, \ReflectionClass $reflector): void {
2✔
NEW
205
                if (!is_a($reflector->name, OperationMutatorInterface::class, true)) {
×
NEW
206
                    throw new RuntimeException(\sprintf('Operation mutator "%s" should implement %s', $reflector->name, OperationMutatorInterface::class));
×
207
                }
208

NEW
209
                $definition->addTag('api_platform.operation_mutator', [
×
NEW
210
                    'operationName' => $attribute->operationName,
×
NEW
211
                ]);
×
212
            },
2✔
213
        );
2✔
214

215
        if (!$container->has('api_platform.state.item_provider')) {
2✔
216
            $container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
×
217
        }
218
    }
219

220
    private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats): void
221
    {
222
        $loader->load('state/state.xml');
2✔
223
        $loader->load('symfony/symfony.xml');
2✔
224
        $loader->load('api.xml');
2✔
225
        $loader->load('filter.xml');
2✔
226

227
        if (class_exists(UuidDenormalizer::class) && class_exists(Uuid::class)) {
2✔
228
            $loader->load('ramsey_uuid.xml');
2✔
229
        }
230

231
        if (class_exists(AbstractUid::class)) {
2✔
232
            $loader->load('symfony/uid.xml');
2✔
233
        }
234

235
        $defaultContext = ['hydra_prefix' => $config['serializer']['hydra_prefix']] + ($container->hasParameter('serializer.default_context') ? $container->getParameter('serializer.default_context') : []);
2✔
236

237
        $container->setParameter('api_platform.serializer.default_context', $defaultContext);
2✔
238
        if (!$container->hasParameter('serializer.default_context')) {
2✔
239
            $container->setParameter('serializer.default_context', $container->getParameter('api_platform.serializer.default_context'));
2✔
240
        }
241
        if ($config['use_symfony_listeners']) {
2✔
UNCOV
242
            $loader->load('symfony/events.xml');
1✔
243
        } else {
244
            $loader->load('symfony/controller.xml');
1✔
245
            $loader->load('state/provider.xml');
1✔
246
            $loader->load('state/processor.xml');
1✔
247
        }
248

249
        $container->setParameter('api_platform.enable_entrypoint', $config['enable_entrypoint']);
2✔
250
        $container->setParameter('api_platform.enable_docs', $config['enable_docs']);
2✔
251
        $container->setParameter('api_platform.title', $config['title']);
2✔
252
        $container->setParameter('api_platform.description', $config['description']);
2✔
253
        $container->setParameter('api_platform.version', $config['version']);
2✔
254
        $container->setParameter('api_platform.show_webby', $config['show_webby']);
2✔
255
        $container->setParameter('api_platform.url_generation_strategy', $config['defaults']['url_generation_strategy'] ?? UrlGeneratorInterface::ABS_PATH);
2✔
256
        $container->setParameter('api_platform.exception_to_status', $config['exception_to_status']);
2✔
257
        $container->setParameter('api_platform.formats', $formats);
2✔
258
        $container->setParameter('api_platform.patch_formats', $patchFormats);
2✔
259
        $container->setParameter('api_platform.error_formats', $errorFormats);
2✔
260
        $container->setParameter('api_platform.docs_formats', $docsFormats);
2✔
261
        $container->setParameter('api_platform.jsonschema_formats', []);
2✔
262
        $container->setParameter('api_platform.eager_loading.enabled', $this->isConfigEnabled($container, $config['eager_loading']));
2✔
263
        $container->setParameter('api_platform.eager_loading.max_joins', $config['eager_loading']['max_joins']);
2✔
264
        $container->setParameter('api_platform.eager_loading.fetch_partial', $config['eager_loading']['fetch_partial']);
2✔
265
        $container->setParameter('api_platform.eager_loading.force_eager', $config['eager_loading']['force_eager']);
2✔
266
        $container->setParameter('api_platform.collection.exists_parameter_name', $config['collection']['exists_parameter_name']);
2✔
267
        $container->setParameter('api_platform.collection.order', $config['collection']['order']);
2✔
268
        $container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']);
2✔
269
        $container->setParameter('api_platform.collection.order_nulls_comparison', $config['collection']['order_nulls_comparison']);
2✔
270
        $container->setParameter('api_platform.collection.pagination.enabled', $config['defaults']['pagination_enabled'] ?? true);
2✔
271
        $container->setParameter('api_platform.collection.pagination.partial', $config['defaults']['pagination_partial'] ?? false);
2✔
272
        $container->setParameter('api_platform.collection.pagination.client_enabled', $config['defaults']['pagination_client_enabled'] ?? false);
2✔
273
        $container->setParameter('api_platform.collection.pagination.client_items_per_page', $config['defaults']['pagination_client_items_per_page'] ?? false);
2✔
274
        $container->setParameter('api_platform.collection.pagination.client_partial', $config['defaults']['pagination_client_partial'] ?? false);
2✔
275
        $container->setParameter('api_platform.collection.pagination.items_per_page', $config['defaults']['pagination_items_per_page'] ?? 30);
2✔
276
        $container->setParameter('api_platform.collection.pagination.maximum_items_per_page', $config['defaults']['pagination_maximum_items_per_page'] ?? null);
2✔
277
        $container->setParameter('api_platform.collection.pagination.page_parameter_name', $config['defaults']['pagination_page_parameter_name'] ?? $config['collection']['pagination']['page_parameter_name']);
2✔
278
        $container->setParameter('api_platform.collection.pagination.enabled_parameter_name', $config['defaults']['pagination_enabled_parameter_name'] ?? $config['collection']['pagination']['enabled_parameter_name']);
2✔
279
        $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']);
2✔
280
        $container->setParameter('api_platform.collection.pagination.partial_parameter_name', $config['defaults']['pagination_partial_parameter_name'] ?? $config['collection']['pagination']['partial_parameter_name']);
2✔
281
        $container->setParameter('api_platform.collection.pagination', $this->getPaginationDefaults($config['defaults'] ?? [], $config['collection']['pagination']));
2✔
282
        $container->setParameter('api_platform.handle_symfony_errors', $config['handle_symfony_errors'] ?? false);
2✔
283
        $container->setParameter('api_platform.http_cache.etag', $config['defaults']['cache_headers']['etag'] ?? true);
2✔
284
        $container->setParameter('api_platform.http_cache.max_age', $config['defaults']['cache_headers']['max_age'] ?? null);
2✔
285
        $container->setParameter('api_platform.http_cache.shared_max_age', $config['defaults']['cache_headers']['shared_max_age'] ?? null);
2✔
286
        $container->setParameter('api_platform.http_cache.vary', $config['defaults']['cache_headers']['vary'] ?? ['Accept']);
2✔
287
        $container->setParameter('api_platform.http_cache.public', $config['defaults']['cache_headers']['public'] ?? $config['http_cache']['public']);
2✔
288
        $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']);
2✔
289
        $container->setParameter('api_platform.http_cache.invalidation.xkey.glue', $config['defaults']['cache_headers']['invalidation']['xkey']['glue'] ?? $config['http_cache']['invalidation']['xkey']['glue']);
2✔
290

291
        $container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
2✔
292
        $container->setAlias('api_platform.inflector', $config['inflector']);
2✔
293

294
        if ($config['name_converter']) {
2✔
295
            $container->setAlias('api_platform.name_converter', $config['name_converter']);
2✔
296
        }
297
        $container->setParameter('api_platform.asset_package', $config['asset_package']);
2✔
298
        $container->setParameter('api_platform.defaults', $this->normalizeDefaults($config['defaults'] ?? []));
2✔
299

300
        if ($container->getParameter('kernel.debug')) {
2✔
301
            $container->removeDefinition('api_platform.serializer.mapping.cache_class_metadata_factory');
2✔
302
        }
303
    }
304

305
    /**
306
     * This method will be removed in 3.0 when "defaults" will be the regular configuration path for the pagination.
307
     */
308
    private function getPaginationDefaults(array $defaults, array $collectionPaginationConfiguration): array
309
    {
310
        $paginationOptions = [];
2✔
311

312
        foreach ($defaults as $key => $value) {
2✔
313
            if (!str_starts_with($key, 'pagination_')) {
2✔
314
                continue;
2✔
315
            }
316

317
            $paginationOptions[str_replace('pagination_', '', $key)] = $value;
2✔
318
        }
319

320
        return array_merge($collectionPaginationConfiguration, $paginationOptions);
2✔
321
    }
322

323
    private function normalizeDefaults(array $defaults): array
324
    {
325
        $normalizedDefaults = ['extra_properties' => $defaults['extra_properties'] ?? []];
2✔
326
        unset($defaults['extra_properties']);
2✔
327

328
        $rc = new \ReflectionClass(ApiResource::class);
2✔
329
        $publicProperties = [];
2✔
330
        foreach ($rc->getConstructor()->getParameters() as $param) {
2✔
331
            $publicProperties[$param->getName()] = true;
2✔
332
        }
333

334
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
2✔
335
        foreach ($defaults as $option => $value) {
2✔
336
            if (isset($publicProperties[$nameConverter->denormalize($option)])) {
2✔
337
                $normalizedDefaults[$option] = $value;
2✔
338

339
                continue;
2✔
340
            }
341

342
            $normalizedDefaults['extra_properties'][$option] = $value;
×
343
        }
344

345
        return $normalizedDefaults;
2✔
346
    }
347

348
    private function registerMetadataConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
349
    {
350
        [$xmlResources, $yamlResources, $phpResources] = $this->getResourcesToWatch($container, $config);
2✔
351

352
        $container->setParameter('api_platform.class_name_resources', $this->getClassNameResources());
2✔
353

354
        $loader->load('metadata/resource_name.xml');
2✔
355
        $loader->load('metadata/property_name.xml');
2✔
356

357
        if (!empty($config['resource_class_directories'])) {
2✔
358
            $container->setParameter('api_platform.resource_class_directories', array_merge(
×
359
                $config['resource_class_directories'],
×
360
                $container->getParameter('api_platform.resource_class_directories')
×
361
            ));
×
362
        }
363

364
        // V3 metadata
365
        $loader->load('metadata/php.xml');
2✔
366
        $loader->load('metadata/xml.xml');
2✔
367
        $loader->load('metadata/links.xml');
2✔
368
        $loader->load('metadata/property.xml');
2✔
369
        $loader->load('metadata/resource.xml');
2✔
370
        $loader->load('metadata/operation.xml');
2✔
371
        $loader->load('metadata/mutator.xml');
2✔
372

373
        $container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
2✔
374
        $container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
2✔
375

376
        if (class_exists(PhpDocParser::class) || interface_exists(DocBlockFactoryInterface::class)) {
2✔
377
            $loader->load('metadata/php_doc.xml');
2✔
378
        }
379

380
        if (class_exists(Yaml::class)) {
2✔
381
            $loader->load('metadata/yaml.xml');
2✔
382
            $container->getDefinition('api_platform.metadata.resource_extractor.yaml')->replaceArgument(0, $yamlResources);
2✔
383
            $container->getDefinition('api_platform.metadata.property_extractor.yaml')->replaceArgument(0, $yamlResources);
2✔
384
        }
385

386
        $container->getDefinition('api_platform.metadata.resource_extractor.php_file')->replaceArgument(0, $phpResources);
2✔
387
    }
388

389
    private function getClassNameResources(): array
390
    {
391
        return [
2✔
392
            Error::class,
2✔
393
            ValidationException::class,
2✔
394
        ];
2✔
395
    }
396

397
    private function getBundlesResourcesPaths(ContainerBuilder $container, array $config): array
398
    {
399
        $bundlesResourcesPaths = [];
2✔
400

401
        foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
2✔
402
            $dirname = $bundle['path'];
2✔
403
            $paths = [
2✔
404
                "$dirname/ApiResource",
2✔
405
                "$dirname/src/ApiResource",
2✔
406
            ];
2✔
407
            foreach (['.yaml', '.yml', '.xml', ''] as $extension) {
2✔
408
                $paths[] = "$dirname/Resources/config/api_resources$extension";
2✔
409
                $paths[] = "$dirname/config/api_resources$extension";
2✔
410
            }
411
            if ($this->isConfigEnabled($container, $config['doctrine'])) {
2✔
412
                $paths[] = "$dirname/Entity";
2✔
413
                $paths[] = "$dirname/src/Entity";
2✔
414
            }
415
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
2✔
416
                $paths[] = "$dirname/Document";
×
417
                $paths[] = "$dirname/src/Document";
×
418
            }
419

420
            foreach ($paths as $path) {
2✔
421
                if ($container->fileExists($path, false)) {
2✔
422
                    $bundlesResourcesPaths[] = $path;
2✔
423
                }
424
            }
425
        }
426

427
        return $bundlesResourcesPaths;
2✔
428
    }
429

430
    private function getResourcesToWatch(ContainerBuilder $container, array $config): array
431
    {
432
        $paths = array_unique(array_merge($this->getBundlesResourcesPaths($container, $config), $config['mapping']['paths']));
2✔
433

434
        if (!$config['mapping']['paths']) {
2✔
435
            $projectDir = $container->getParameter('kernel.project_dir');
×
436
            foreach (["$projectDir/config/api_platform", "$projectDir/src/ApiResource"] as $dir) {
×
437
                if (is_dir($dir)) {
×
438
                    $paths[] = $dir;
×
439
                }
440
            }
441

442
            if ($this->isConfigEnabled($container, $config['doctrine']) && is_dir($doctrinePath = "$projectDir/src/Entity")) {
×
443
                $paths[] = $doctrinePath;
×
444
            }
445

446
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm']) && is_dir($documentPath = "$projectDir/src/Document")) {
×
447
                $paths[] = $documentPath;
×
448
            }
449
        }
450

451
        $resources = ['yml' => [], 'xml' => [], 'php' => [], 'dir' => []];
2✔
452

453
        foreach ($config['mapping']['imports'] ?? [] as $path) {
2✔
454
            if (is_dir($path)) {
×
455
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.php$/')->sortByName() as $file) {
×
456
                    $resources[$file->getExtension()][] = $file->getRealPath();
×
457
                }
458

459
                $resources['dir'][] = $path;
×
460
                $container->addResource(new DirectoryResource($path, '/\.php$/'));
×
461

462
                continue;
×
463
            }
464

465
            if ($container->fileExists($path, false)) {
×
466
                if (!str_ends_with($path, '.php')) {
×
467
                    throw new RuntimeException(\sprintf('Unsupported mapping type in "%s", supported type is PHP.', $path));
×
468
                }
469

470
                $resources['php'][] = $path;
×
471

472
                continue;
×
473
            }
474

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

478
        foreach ($paths as $path) {
2✔
479
            if (is_dir($path)) {
2✔
480
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.(xml|ya?ml)$/')->sortByName() as $file) {
2✔
481
                    $resources['yaml' === ($extension = $file->getExtension()) ? 'yml' : $extension][] = $file->getRealPath();
2✔
482
                }
483

484
                $resources['dir'][] = $path;
2✔
485
                $container->addResource(new DirectoryResource($path, '/\.(xml|ya?ml|php)$/'));
2✔
486

487
                continue;
2✔
488
            }
489

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

495
                $resources['yaml' === $matches[1] ? 'yml' : $matches[1]][] = $path;
×
496

497
                continue;
×
498
            }
499

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

503
        $container->setParameter('api_platform.resource_class_directories', $resources['dir']);
2✔
504

505
        return [$resources['xml'], $resources['yml'], $resources['php']];
2✔
506
    }
507

508
    private function registerOAuthConfiguration(ContainerBuilder $container, array $config): void
509
    {
510
        if (!$config['oauth']) {
2✔
511
            return;
×
512
        }
513

514
        $container->setParameter('api_platform.oauth.enabled', $this->isConfigEnabled($container, $config['oauth']));
2✔
515
        $container->setParameter('api_platform.oauth.clientId', $config['oauth']['clientId']);
2✔
516
        $container->setParameter('api_platform.oauth.clientSecret', $config['oauth']['clientSecret']);
2✔
517
        $container->setParameter('api_platform.oauth.type', $config['oauth']['type']);
2✔
518
        $container->setParameter('api_platform.oauth.flow', $config['oauth']['flow']);
2✔
519
        $container->setParameter('api_platform.oauth.tokenUrl', $config['oauth']['tokenUrl']);
2✔
520
        $container->setParameter('api_platform.oauth.authorizationUrl', $config['oauth']['authorizationUrl']);
2✔
521
        $container->setParameter('api_platform.oauth.refreshUrl', $config['oauth']['refreshUrl']);
2✔
522
        $container->setParameter('api_platform.oauth.scopes', $config['oauth']['scopes']);
2✔
523
        $container->setParameter('api_platform.oauth.pkce', $config['oauth']['pkce']);
2✔
524

525
        if ($container->hasDefinition('api_platform.swagger_ui.action')) {
2✔
526
            $container->getDefinition('api_platform.swagger_ui.action')->setArgument(10, $config['oauth']['pkce']);
×
527
        }
528
    }
529

530
    /**
531
     * Registers the Swagger, ReDoc and Swagger UI configuration.
532
     */
533
    private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
534
    {
535
        foreach (array_keys($config['swagger']['api_keys']) as $keyName) {
2✔
536
            if (!preg_match('/^[a-zA-Z0-9._-]+$/', $keyName)) {
2✔
537
                trigger_deprecation('api-platform/core', '3.1', \sprintf('The swagger api_keys key "%s" is not valid with OpenAPI 3.1 it should match "^[a-zA-Z0-9._-]+$"', $keyName));
×
538
            }
539
        }
540

541
        $container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
2✔
542

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

547
        if (!$config['enable_swagger']) {
2✔
548
            return;
×
549
        }
550

551
        $loader->load('openapi.xml');
2✔
552

553
        if (class_exists(Yaml::class)) {
2✔
554
            $loader->load('openapi/yaml.xml');
2✔
555
        }
556

557
        $loader->load('swagger_ui.xml');
2✔
558

559
        if ($config['use_symfony_listeners']) {
2✔
UNCOV
560
            $loader->load('symfony/swagger_ui.xml');
1✔
561
        }
562

563
        if ($config['enable_swagger_ui']) {
2✔
564
            $loader->load('state/swagger_ui.xml');
2✔
565
        }
566

567
        if (!$config['enable_swagger_ui'] && !$config['enable_re_doc']) {
2✔
568
            // Remove the listener but keep the controller to allow customizing the path of the UI
569
            $container->removeDefinition('api_platform.swagger.listener.ui');
×
570
        }
571

572
        $container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']);
2✔
573
        $container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
2✔
574
        $container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
2✔
575
        $container->setParameter('api_platform.swagger.persist_authorization', $config['swagger']['persist_authorization']);
2✔
576
        $container->setParameter('api_platform.swagger.http_auth', $config['swagger']['http_auth']);
2✔
577
        if ($config['openapi']['swagger_ui_extra_configuration'] && $config['swagger']['swagger_ui_extra_configuration']) {
2✔
578
            throw new RuntimeException('You can not set "swagger_ui_extra_configuration" twice - in "openapi" and "swagger" section.');
×
579
        }
580
        $container->setParameter('api_platform.swagger_ui.extra_configuration', $config['openapi']['swagger_ui_extra_configuration'] ?: $config['swagger']['swagger_ui_extra_configuration']);
2✔
581
    }
582

583
    private function registerJsonApiConfiguration(array $formats, XmlFileLoader $loader, array $config): void
584
    {
585
        if (!isset($formats['jsonapi'])) {
2✔
586
            return;
×
587
        }
588

589
        $loader->load('jsonapi.xml');
2✔
590
        $loader->load('state/jsonapi.xml');
2✔
591
    }
592

593
    private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, XmlFileLoader $loader, array $config): void
594
    {
595
        if (!isset($formats['jsonld'])) {
2✔
596
            return;
×
597
        }
598

599
        if ($config['use_symfony_listeners']) {
2✔
UNCOV
600
            $loader->load('symfony/jsonld.xml');
1✔
601
        } else {
602
            $loader->load('state/jsonld.xml');
1✔
603
        }
604

605
        $loader->load('state/hydra.xml');
2✔
606
        $loader->load('jsonld.xml');
2✔
607
        $loader->load('hydra.xml');
2✔
608

609
        if (!$container->has('api_platform.json_schema.schema_factory')) {
2✔
610
            $container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
×
611
        }
612
    }
613

614
    private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader): void
615
    {
616
        if (!isset($formats['jsonhal'])) {
2✔
617
            return;
×
618
        }
619

620
        $loader->load('hal.xml');
2✔
621
    }
622

623
    private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLoader $loader): void
624
    {
625
        if (!isset($errorFormats['jsonproblem'])) {
2✔
626
            return;
×
627
        }
628

629
        $loader->load('problem.xml');
2✔
630
    }
631

632
    private function registerGraphQlConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
633
    {
634
        $enabled = $this->isConfigEnabled($container, $config['graphql']);
2✔
635
        $graphqlIntrospectionEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['introspection']);
2✔
636
        $graphiqlEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']);
2✔
637
        $graphqlPlayGroundEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphql_playground']);
2✔
638
        $maxQueryDepth = (int) $config['graphql']['max_query_depth'];
2✔
639
        $maxQueryComplexity = (int) $config['graphql']['max_query_complexity'];
2✔
640
        if ($graphqlPlayGroundEnabled) {
2✔
641
            trigger_deprecation('api-platform/core', '3.1', 'GraphQL Playground is deprecated and will be removed in API Platform 4.0. Only GraphiQL will be available in the future. Set api_platform.graphql.graphql_playground to false in the configuration to remove this deprecation.');
×
642
        }
643

644
        $container->setParameter('api_platform.graphql.enabled', $enabled);
2✔
645
        $container->setParameter('api_platform.graphql.max_query_depth', $maxQueryDepth);
2✔
646
        $container->setParameter('api_platform.graphql.max_query_complexity', $maxQueryComplexity);
2✔
647
        $container->setParameter('api_platform.graphql.introspection.enabled', $graphqlIntrospectionEnabled);
2✔
648
        $container->setParameter('api_platform.graphql.graphiql.enabled', $graphiqlEnabled);
2✔
649
        $container->setParameter('api_platform.graphql.graphql_playground.enabled', $graphqlPlayGroundEnabled);
2✔
650
        $container->setParameter('api_platform.graphql.collection.pagination', $config['graphql']['collection']['pagination']);
2✔
651

652
        if (!$enabled) {
2✔
653
            return;
×
654
        }
655

656
        if (!class_exists(Executor::class)) {
2✔
657
            throw new \RuntimeException('Graphql is enabled but not installed, run: composer require "api-platform/graphql".');
×
658
        }
659

660
        $container->setParameter('api_platform.graphql.default_ide', $config['graphql']['default_ide']);
2✔
661
        $container->setParameter('api_platform.graphql.nesting_separator', $config['graphql']['nesting_separator']);
2✔
662

663
        $loader->load('graphql.xml');
2✔
664

665
        // @phpstan-ignore-next-line because PHPStan uses the container of the test env cache and in test the parameter kernel.bundles always contains the key TwigBundle
666
        if (!class_exists(Environment::class) || !isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
2✔
667
            if ($graphiqlEnabled || $graphqlPlayGroundEnabled) {
×
668
                throw new RuntimeException(\sprintf('GraphiQL and GraphQL Playground interfaces depend on Twig. Please activate TwigBundle for the %s environnement or disable GraphiQL and GraphQL Playground.', $container->getParameter('kernel.environment')));
×
669
            }
670
            $container->removeDefinition('api_platform.graphql.action.graphiql');
×
671
            $container->removeDefinition('api_platform.graphql.action.graphql_playground');
×
672
        }
673

674
        $container->registerForAutoconfiguration(QueryItemResolverInterface::class)
2✔
675
            ->addTag('api_platform.graphql.resolver');
2✔
676
        $container->registerForAutoconfiguration(QueryCollectionResolverInterface::class)
2✔
677
            ->addTag('api_platform.graphql.resolver');
2✔
678
        $container->registerForAutoconfiguration(MutationResolverInterface::class)
2✔
679
            ->addTag('api_platform.graphql.resolver');
2✔
680
        $container->registerForAutoconfiguration(GraphQlTypeInterface::class)
2✔
681
            ->addTag('api_platform.graphql.type');
2✔
682
        $container->registerForAutoconfiguration(ErrorHandlerInterface::class)
2✔
683
            ->addTag('api_platform.graphql.error_handler');
2✔
684
    }
685

686
    private function registerCacheConfiguration(ContainerBuilder $container): void
687
    {
688
        if (!$container->hasParameter('kernel.debug') || !$container->getParameter('kernel.debug')) {
2✔
689
            $container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
×
690
        }
691
    }
692

693
    private function registerDoctrineOrmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
694
    {
695
        if (!$this->isConfigEnabled($container, $config['doctrine'])) {
2✔
696
            return;
×
697
        }
698

699
        // For older versions of doctrine bridge this allows autoconfiguration for filters
700
        if (!$container->has(ManagerRegistry::class)) {
2✔
701
            $container->setAlias(ManagerRegistry::class, 'doctrine');
2✔
702
        }
703

704
        $container->registerForAutoconfiguration(QueryItemExtensionInterface::class)
2✔
705
            ->addTag('api_platform.doctrine.orm.query_extension.item');
2✔
706
        $container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
2✔
707
            ->addTag('api_platform.doctrine.orm.query_extension.collection');
2✔
708
        $container->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class);
2✔
709

710
        $container->registerForAutoconfiguration(OrmLinksHandlerInterface::class)
2✔
711
            ->addTag('api_platform.doctrine.orm.links_handler');
2✔
712

713
        $loader->load('doctrine_orm.xml');
2✔
714

715
        if ($this->isConfigEnabled($container, $config['eager_loading'])) {
2✔
716
            return;
2✔
717
        }
718

719
        $container->removeAlias(EagerLoadingExtension::class);
×
720
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading');
×
721
        $container->removeAlias(FilterEagerLoadingExtension::class);
×
722
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.filter_eager_loading');
×
723
    }
724

725
    private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
726
    {
727
        if (!$this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
2✔
728
            return;
2✔
729
        }
730

731
        $container->registerForAutoconfiguration(AggregationItemExtensionInterface::class)
×
732
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.item');
×
733
        $container->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)
×
734
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection');
×
735
        $container->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
×
736
            ->setBindings(['$managerRegistry' => new Reference('doctrine_mongodb')]);
×
737
        $container->registerForAutoconfiguration(OdmLinksHandlerInterface::class)
×
738
            ->addTag('api_platform.doctrine.odm.links_handler');
×
739

740
        $loader->load('doctrine_mongodb_odm.xml');
×
741
    }
742

743
    private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
744
    {
745
        $loader->load('http_cache.xml');
2✔
746

747
        if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
2✔
748
            return;
×
749
        }
750

751
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
2✔
752
            $loader->load('doctrine_orm_http_cache_purger.xml');
2✔
753
        }
754

755
        $loader->load('state/http_cache_purger.xml');
2✔
756
        $loader->load('http_cache_purger.xml');
2✔
757

758
        foreach ($config['http_cache']['invalidation']['scoped_clients'] as $client) {
2✔
759
            $definition = $container->getDefinition($client);
×
760
            $definition->addTag('api_platform.http_cache.http_client');
×
761
        }
762

763
        if (!($urls = $config['http_cache']['invalidation']['urls'])) {
2✔
764
            $urls = $config['http_cache']['invalidation']['varnish_urls'];
2✔
765
        }
766

767
        foreach ($urls as $key => $url) {
2✔
768
            $definition = new Definition(ScopingHttpClient::class, [new Reference('http_client'), $url, ['base_uri' => $url] + $config['http_cache']['invalidation']['request_options']]);
×
769
            $definition->setFactory([ScopingHttpClient::class, 'forBaseUri']);
×
770
            $definition->addTag('api_platform.http_cache.http_client');
×
771
            $container->setDefinition('api_platform.invalidation_http_client.'.$key, $definition);
×
772
        }
773

774
        $serviceName = $config['http_cache']['invalidation']['purger'];
2✔
775

776
        if (!$container->hasDefinition('api_platform.http_cache.purger')) {
2✔
777
            $container->setAlias('api_platform.http_cache.purger', $serviceName);
2✔
778
        }
779
    }
780

781
    /**
782
     * Normalizes the format from config to the one accepted by Symfony HttpFoundation.
783
     */
784
    private function getFormats(array $configFormats): array
785
    {
786
        $formats = [];
2✔
787
        foreach ($configFormats as $format => $value) {
2✔
788
            foreach ($value['mime_types'] as $mimeType) {
2✔
789
                $formats[$format][] = $mimeType;
2✔
790
            }
791
        }
792

793
        return $formats;
2✔
794
    }
795

796
    private function registerValidatorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
797
    {
798
        if (interface_exists(ValidatorInterface::class)) {
2✔
799
            $loader->load('metadata/validator.xml');
2✔
800
            $loader->load('validator/validator.xml');
2✔
801

802
            if ($this->isConfigEnabled($container, $config['graphql'])) {
2✔
803
                $loader->load('graphql/validator.xml');
2✔
804
            }
805

806
            $loader->load($config['use_symfony_listeners'] ? 'validator/events.xml' : 'validator/state.xml');
2✔
807

808
            $container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
2✔
809
                ->addTag('api_platform.validation_groups_generator');
2✔
810
            $container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
2✔
811
                ->addTag('api_platform.metadata.property_schema_restriction');
2✔
812
        }
813

814
        if (!$config['validator']) {
2✔
815
            return;
×
816
        }
817

818
        $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']);
2✔
819
    }
820

821
    private function registerDataCollectorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
822
    {
823
        if (!$config['enable_profiler']) {
2✔
824
            return;
×
825
        }
826

827
        $loader->load('data_collector.xml');
2✔
828

829
        if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
2✔
830
            $loader->load('debug.xml');
2✔
831
        }
832
    }
833

834
    private function registerMercureConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
835
    {
836
        if (!$this->isConfigEnabled($container, $config['mercure'])) {
2✔
837
            return;
×
838
        }
839

840
        $container->setParameter('api_platform.mercure.include_type', $config['mercure']['include_type']);
2✔
841
        $loader->load('state/mercure.xml');
2✔
842

843
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
2✔
844
            $loader->load('doctrine_orm_mercure_publisher.xml');
2✔
845
        }
846
        if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
2✔
847
            $loader->load('doctrine_odm_mercure_publisher.xml');
×
848
        }
849

850
        if ($this->isConfigEnabled($container, $config['graphql'])) {
2✔
851
            $loader->load('graphql_mercure.xml');
2✔
852
        }
853
    }
854

855
    private function registerMessengerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
856
    {
857
        if (!$this->isConfigEnabled($container, $config['messenger'])) {
2✔
858
            return;
×
859
        }
860

861
        $loader->load('messenger.xml');
2✔
862
    }
863

864
    private function registerElasticsearchConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
865
    {
866
        $enabled = $this->isConfigEnabled($container, $config['elasticsearch']);
2✔
867

868
        $container->setParameter('api_platform.elasticsearch.enabled', $enabled);
2✔
869

870
        if (!$enabled) {
2✔
871
            return;
2✔
872
        }
873

874
        $clientClass = !class_exists(\Elasticsearch\Client::class)
×
875
            // ES v7
×
876
            ? \Elastic\Elasticsearch\Client::class
×
877
            // ES v8 and up
×
878
            : \Elasticsearch\Client::class;
×
879

880
        $clientDefinition = new Definition($clientClass);
×
881
        $container->setDefinition('api_platform.elasticsearch.client', $clientDefinition);
×
882
        $container->registerForAutoconfiguration(RequestBodySearchCollectionExtensionInterface::class)
×
883
            ->addTag('api_platform.elasticsearch.request_body_search_extension.collection');
×
884
        $container->setParameter('api_platform.elasticsearch.hosts', $config['elasticsearch']['hosts']);
×
885
        $loader->load('elasticsearch.xml');
×
886
    }
887

888
    private function registerSecurityConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
889
    {
890
        /** @var string[] $bundles */
891
        $bundles = $container->getParameter('kernel.bundles');
2✔
892

893
        if (!isset($bundles['SecurityBundle'])) {
2✔
894
            return;
×
895
        }
896

897
        $loader->load('security.xml');
2✔
898

899
        $loader->load('state/security.xml');
2✔
900

901
        if (interface_exists(ValidatorInterface::class)) {
2✔
902
            $loader->load('state/security_validator.xml');
2✔
903
        }
904

905
        if ($this->isConfigEnabled($container, $config['graphql'])) {
2✔
906
            $loader->load('graphql/security.xml');
2✔
907
        }
908
    }
909

910
    private function registerOpenApiConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
911
    {
912
        $container->setParameter('api_platform.openapi.termsOfService', $config['openapi']['termsOfService']);
2✔
913
        $container->setParameter('api_platform.openapi.contact.name', $config['openapi']['contact']['name']);
2✔
914
        $container->setParameter('api_platform.openapi.contact.url', $config['openapi']['contact']['url']);
2✔
915
        $container->setParameter('api_platform.openapi.contact.email', $config['openapi']['contact']['email']);
2✔
916
        $container->setParameter('api_platform.openapi.license.name', $config['openapi']['license']['name']);
2✔
917
        $container->setParameter('api_platform.openapi.license.url', $config['openapi']['license']['url']);
2✔
918
        $container->setParameter('api_platform.openapi.license.identifier', $config['openapi']['license']['identifier']);
2✔
919
        $container->setParameter('api_platform.openapi.overrideResponses', $config['openapi']['overrideResponses']);
2✔
920

921
        $tags = [];
2✔
922
        foreach ($config['openapi']['tags'] as $tag) {
2✔
923
            $tags[] = new Tag($tag['name'], $tag['description'] ?? null);
×
924
        }
925

926
        $container->setParameter('api_platform.openapi.tags', $tags);
2✔
927

928
        $container->setParameter('api_platform.openapi.errorResourceClass', $config['openapi']['error_resource_class'] ?? null);
2✔
929
        $container->setParameter('api_platform.openapi.validationErrorResourceClass', $config['openapi']['validation_error_resource_class'] ?? null);
2✔
930

931
        $loader->load('json_schema.xml');
2✔
932
    }
933

934
    private function registerMakerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
935
    {
936
        if (!$this->isConfigEnabled($container, $config['maker'])) {
2✔
937
            return;
×
938
        }
939

940
        $loader->load('maker.xml');
2✔
941
    }
942

943
    private function registerArgumentResolverConfiguration(XmlFileLoader $loader): void
944
    {
945
        $loader->load('argument_resolver.xml');
2✔
946
    }
947

948
    private function registerLinkSecurityConfiguration(XmlFileLoader $loader, array $config): void
949
    {
950
        if ($config['enable_link_security']) {
2✔
951
            $loader->load('link_security.xml');
2✔
952
        }
953
    }
954
}
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

© 2025 Coveralls, Inc