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

api-platform / core / 20001323174

07 Dec 2025 08:10AM UTC coverage: 25.292% (+0.001%) from 25.291%
20001323174

push

github

soyuka
chore: bump metadata to 4.3.x-dev

14642 of 57891 relevant lines covered (25.29%)

28.94 hits per line

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

77.9
/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\Bundle\FrameworkBundle\Controller\ControllerHelper;
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\PhpFileLoader;
63
use Symfony\Component\DependencyInjection\Reference;
64
use Symfony\Component\Finder\Finder;
65
use Symfony\Component\HttpClient\ScopingHttpClient;
66
use Symfony\Component\JsonStreamer\JsonStreamWriter;
67
use Symfony\Component\ObjectMapper\ObjectMapper;
68
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
69
use Symfony\Component\Serializer\Normalizer\NumberNormalizer;
70
use Symfony\Component\Uid\AbstractUid;
71
use Symfony\Component\Validator\Validator\ValidatorInterface;
72
use Symfony\Component\Yaml\Yaml;
73
use Twig\Environment;
74

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

108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function load(array $configs, ContainerBuilder $container): void
112
    {
113
        $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
8✔
114

115
        $configuration = new Configuration();
8✔
116
        $config = $this->processConfiguration($configuration, $configs);
8✔
117
        $container->setParameter('api_platform.use_symfony_listeners', $config['use_symfony_listeners']);
8✔
118

119
        $formats = $this->getFormats($config['formats']);
8✔
120
        $patchFormats = $this->getFormats($config['patch_formats']);
8✔
121
        $errorFormats = $this->getFormats($config['error_formats']);
8✔
122
        $docsFormats = $this->getFormats($config['docs_formats']);
8✔
123

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

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

143
        if (!isset($errorFormats['json'])) {
8✔
144
            $errorFormats['json'] = ['application/problem+json', 'application/json'];
8✔
145
        }
146

147
        if (!isset($errorFormats['jsonproblem'])) {
8✔
148
            $errorFormats['jsonproblem'] = ['application/problem+json'];
×
149
        }
150

151
        if (isset($formats['jsonapi']) && !isset($patchFormats['jsonapi'])) {
8✔
152
            $patchFormats['jsonapi'] = ['application/vnd.api+json'];
8✔
153
        }
154

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

180
        if (class_exists(ObjectMapper::class)) {
8✔
181
            $loader->load('state/object_mapper.php');
8✔
182
        }
183
        $container->registerForAutoconfiguration(FilterInterface::class)
8✔
184
            ->addTag('api_platform.filter');
8✔
185
        $container->registerForAutoconfiguration(ProviderInterface::class)
8✔
186
            ->addTag('api_platform.state_provider');
8✔
187
        $container->registerForAutoconfiguration(ProcessorInterface::class)
8✔
188
            ->addTag('api_platform.state_processor');
8✔
189
        $container->registerForAutoconfiguration(UriVariableTransformerInterface::class)
8✔
190
            ->addTag('api_platform.uri_variables.transformer');
8✔
191
        $container->registerForAutoconfiguration(ParameterProviderInterface::class)
8✔
192
            ->addTag('api_platform.parameter_provider');
8✔
193
        $container->registerAttributeForAutoconfiguration(ApiResource::class, static function (ChildDefinition $definition): void {
8✔
194
            $definition->setAbstract(true)
×
195
                ->addTag('api_platform.resource')
×
196
                ->addTag('container.excluded', ['source' => 'by #[ApiResource] attribute']);
×
197
        });
8✔
198
        $container->registerAttributeForAutoconfiguration(
8✔
199
            AsResourceMutator::class,
8✔
200
            static function (ChildDefinition $definition, AsResourceMutator $attribute, \ReflectionClass $reflector): void { // @phpstan-ignore-line
8✔
201
                if (!is_a($reflector->name, ResourceMutatorInterface::class, true)) {
×
202
                    throw new RuntimeException(\sprintf('Resource mutator "%s" should implement %s', $reflector->name, ResourceMutatorInterface::class));
×
203
                }
204

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

211
        $container->registerAttributeForAutoconfiguration(
8✔
212
            AsOperationMutator::class,
8✔
213
            static function (ChildDefinition $definition, AsOperationMutator $attribute, \ReflectionClass $reflector): void { // @phpstan-ignore-line
8✔
214
                if (!is_a($reflector->name, OperationMutatorInterface::class, true)) {
×
215
                    throw new RuntimeException(\sprintf('Operation mutator "%s" should implement %s', $reflector->name, OperationMutatorInterface::class));
×
216
                }
217

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

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

228
        if ($container->getParameter('kernel.debug')) {
8✔
229
            $this->injectStopwatch($container);
8✔
230
        }
231
    }
232

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

246
        foreach ($services as $id) {
8✔
247
            if (!$container->hasDefinition($id)) {
8✔
248
                continue;
×
249
            }
250

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

256
    private function registerCommonConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats): void
257
    {
258
        $loader->load('state/state.php');
8✔
259
        $loader->load('symfony/symfony.php');
8✔
260
        $loader->load('api.php');
8✔
261
        $loader->load('filter.php');
8✔
262

263
        if (class_exists(UuidDenormalizer::class) && class_exists(Uuid::class)) {
8✔
264
            $loader->load('ramsey_uuid.php');
8✔
265
        }
266

267
        if (class_exists(AbstractUid::class)) {
8✔
268
            $loader->load('symfony/uid.php');
8✔
269
        }
270

271
        // symfony/serializer:7.3 added the NumberNormalizer
272
        // symfony/framework-bundle:7.3 added the serializer.normalizer.number` service
273
        // if symfony/serializer >= 7.3 and symfony/framework-bundle < 7.3, the service is registred
274
        if (class_exists(NumberNormalizer::class) && !$container->has('serializer.normalizer.number')) {
8✔
275
            $numberNormalizerDefinition = new Definition(NumberNormalizer::class);
8✔
276
            $numberNormalizerDefinition->addTag('serializer.normalizer', ['built_in' => true, 'priority' => -915]);
8✔
277
            $container->setDefinition('serializer.normalizer.number', $numberNormalizerDefinition);
8✔
278
        }
279

280
        $defaultContext = ['hydra_prefix' => $config['serializer']['hydra_prefix']] + ($container->hasParameter('serializer.default_context') ? $container->getParameter('serializer.default_context') : []);
8✔
281

282
        $container->setParameter('api_platform.serializer.default_context', $defaultContext);
8✔
283
        if (!$container->hasParameter('serializer.default_context')) {
8✔
284
            $container->setParameter('serializer.default_context', $container->getParameter('api_platform.serializer.default_context'));
8✔
285
        }
286
        if ($config['use_symfony_listeners']) {
8✔
287
            $loader->load('symfony/events.php');
4✔
288
        } else {
289
            $loader->load('symfony/controller.php');
4✔
290
            $loader->load('state/provider.php');
4✔
291
            $loader->load('state/processor.php');
4✔
292
        }
293
        $loader->load('state/parameter_provider.php');
8✔
294

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

337
        $container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
8✔
338
        $container->setAlias('api_platform.inflector', $config['inflector']);
8✔
339

340
        if ($config['name_converter']) {
8✔
341
            $container->setAlias('api_platform.name_converter', $config['name_converter']);
8✔
342
        }
343
        $container->setParameter('api_platform.asset_package', $config['asset_package']);
8✔
344
        $container->setParameter('api_platform.defaults', $this->normalizeDefaults($config['defaults'] ?? []));
8✔
345

346
        if ($container->getParameter('kernel.debug')) {
8✔
347
            $container->removeDefinition('api_platform.serializer.mapping.cache_class_metadata_factory');
8✔
348
        }
349
    }
350

351
    /**
352
     * This method will be removed in 3.0 when "defaults" will be the regular configuration path for the pagination.
353
     */
354
    private function getPaginationDefaults(array $defaults, array $collectionPaginationConfiguration): array
355
    {
356
        $paginationOptions = [];
8✔
357

358
        foreach ($defaults as $key => $value) {
8✔
359
            if (!str_starts_with($key, 'pagination_')) {
8✔
360
                continue;
8✔
361
            }
362

363
            $paginationOptions[str_replace('pagination_', '', $key)] = $value;
8✔
364
        }
365

366
        return array_merge($collectionPaginationConfiguration, $paginationOptions);
8✔
367
    }
368

369
    private function normalizeDefaults(array $defaults): array
370
    {
371
        $normalizedDefaults = ['extra_properties' => $defaults['extra_properties'] ?? []];
8✔
372
        unset($defaults['extra_properties']);
8✔
373

374
        $rc = new \ReflectionClass(ApiResource::class);
8✔
375
        $publicProperties = [];
8✔
376
        foreach ($rc->getConstructor()->getParameters() as $param) {
8✔
377
            $publicProperties[$param->getName()] = true;
8✔
378
        }
379

380
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
8✔
381
        foreach ($defaults as $option => $value) {
8✔
382
            if (isset($publicProperties[$nameConverter->denormalize($option)])) {
8✔
383
                $normalizedDefaults[$option] = $value;
8✔
384

385
                continue;
8✔
386
            }
387

388
            $normalizedDefaults['extra_properties'][$option] = $value;
×
389
        }
390

391
        return $normalizedDefaults;
8✔
392
    }
393

394
    private function registerMetadataConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
395
    {
396
        [$xmlResources, $yamlResources, $phpResources] = $this->getResourcesToWatch($container, $config);
8✔
397

398
        $container->setParameter('api_platform.class_name_resources', $this->getClassNameResources());
8✔
399

400
        $loader->load('metadata/resource_name.php');
8✔
401
        $loader->load('metadata/property_name.php');
8✔
402

403
        if (!empty($config['resource_class_directories'])) {
8✔
404
            $container->setParameter('api_platform.resource_class_directories', array_merge(
×
405
                $config['resource_class_directories'],
×
406
                $container->getParameter('api_platform.resource_class_directories')
×
407
            ));
×
408
        }
409

410
        // V3 metadata
411
        $loader->load('metadata/php.php');
8✔
412
        $loader->load('metadata/xml.php');
8✔
413
        $loader->load('metadata/links.php');
8✔
414
        $loader->load('metadata/property.php');
8✔
415
        $loader->load('metadata/resource.php');
8✔
416
        $loader->load('metadata/operation.php');
8✔
417
        $loader->load('metadata/mutator.php');
8✔
418

419
        $container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
8✔
420
        $container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
8✔
421

422
        if ($config['enable_phpdoc_parser'] && class_exists(PhpDocParser::class)) {
8✔
423
            $loader->load('metadata/php_doc.php');
8✔
424
        }
425

426
        if (class_exists(Yaml::class)) {
8✔
427
            $loader->load('metadata/yaml.php');
8✔
428
            $container->getDefinition('api_platform.metadata.resource_extractor.yaml')->replaceArgument(0, $yamlResources);
8✔
429
            $container->getDefinition('api_platform.metadata.property_extractor.yaml')->replaceArgument(0, $yamlResources);
8✔
430
        }
431

432
        $container->getDefinition('api_platform.metadata.resource_extractor.php_file')->replaceArgument(0, $phpResources);
8✔
433
    }
434

435
    private function getClassNameResources(): array
436
    {
437
        return [
8✔
438
            Error::class,
8✔
439
            ValidationException::class,
8✔
440
        ];
8✔
441
    }
442

443
    private function getBundlesResourcesPaths(ContainerBuilder $container, array $config): array
444
    {
445
        $bundlesResourcesPaths = [];
8✔
446

447
        foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
8✔
448
            $dirname = $bundle['path'];
8✔
449
            $paths = [
8✔
450
                "$dirname/ApiResource",
8✔
451
                "$dirname/src/ApiResource",
8✔
452
            ];
8✔
453
            foreach (['.yaml', '.yml', '.xml', ''] as $extension) {
8✔
454
                $paths[] = "$dirname/Resources/config/api_resources$extension";
8✔
455
                $paths[] = "$dirname/config/api_resources$extension";
8✔
456
            }
457
            if ($this->isConfigEnabled($container, $config['doctrine'])) {
8✔
458
                $paths[] = "$dirname/Entity";
8✔
459
                $paths[] = "$dirname/src/Entity";
8✔
460
            }
461
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
8✔
462
                $paths[] = "$dirname/Document";
×
463
                $paths[] = "$dirname/src/Document";
×
464
            }
465

466
            foreach ($paths as $path) {
8✔
467
                if ($container->fileExists($path, false)) {
8✔
468
                    $bundlesResourcesPaths[] = $path;
8✔
469
                }
470
            }
471
        }
472

473
        return $bundlesResourcesPaths;
8✔
474
    }
475

476
    private function getResourcesToWatch(ContainerBuilder $container, array $config): array
477
    {
478
        $paths = array_unique(array_merge($this->getBundlesResourcesPaths($container, $config), $config['mapping']['paths']));
8✔
479

480
        if (!$config['mapping']['paths']) {
8✔
481
            $projectDir = $container->getParameter('kernel.project_dir');
×
482
            foreach (["$projectDir/config/api_platform", "$projectDir/src/ApiResource"] as $dir) {
×
483
                if (is_dir($dir)) {
×
484
                    $paths[] = $dir;
×
485
                }
486
            }
487

488
            if ($this->isConfigEnabled($container, $config['doctrine']) && is_dir($doctrinePath = "$projectDir/src/Entity")) {
×
489
                $paths[] = $doctrinePath;
×
490
            }
491

492
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm']) && is_dir($documentPath = "$projectDir/src/Document")) {
×
493
                $paths[] = $documentPath;
×
494
            }
495
        }
496

497
        $resources = ['yml' => [], 'xml' => [], 'php' => [], 'dir' => []];
8✔
498

499
        foreach ($config['mapping']['imports'] ?? [] as $path) {
8✔
500
            if (is_dir($path)) {
×
501
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.php$/')->sortByName() as $file) {
×
502
                    $resources[$file->getExtension()][] = $file->getRealPath();
×
503
                }
504

505
                $resources['dir'][] = $path;
×
506
                $container->addResource(new DirectoryResource($path, '/\.php$/'));
×
507

508
                continue;
×
509
            }
510

511
            if ($container->fileExists($path, false)) {
×
512
                if (!str_ends_with($path, '.php')) {
×
513
                    throw new RuntimeException(\sprintf('Unsupported mapping type in "%s", supported type is PHP.', $path));
×
514
                }
515

516
                $resources['php'][] = $path;
×
517

518
                continue;
×
519
            }
520

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

524
        foreach ($paths as $path) {
8✔
525
            if (is_dir($path)) {
8✔
526
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.(xml|ya?ml)$/')->sortByName() as $file) {
8✔
527
                    $resources['yaml' === ($extension = $file->getExtension()) ? 'yml' : $extension][] = $file->getRealPath();
8✔
528
                }
529

530
                $resources['dir'][] = $path;
8✔
531
                $container->addResource(new DirectoryResource($path, '/\.(xml|ya?ml|php)$/'));
8✔
532

533
                continue;
8✔
534
            }
535

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

541
                $resources['yaml' === $matches[1] ? 'yml' : $matches[1]][] = $path;
×
542

543
                continue;
×
544
            }
545

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

549
        $container->setParameter('api_platform.resource_class_directories', $resources['dir']);
8✔
550

551
        return [$resources['xml'], $resources['yml'], $resources['php']];
8✔
552
    }
553

554
    private function registerOAuthConfiguration(ContainerBuilder $container, array $config): void
555
    {
556
        if (!$config['oauth']) {
8✔
557
            return;
×
558
        }
559

560
        $container->setParameter('api_platform.oauth.enabled', $this->isConfigEnabled($container, $config['oauth']));
8✔
561
        $container->setParameter('api_platform.oauth.clientId', $config['oauth']['clientId']);
8✔
562
        $container->setParameter('api_platform.oauth.clientSecret', $config['oauth']['clientSecret']);
8✔
563
        $container->setParameter('api_platform.oauth.type', $config['oauth']['type']);
8✔
564
        $container->setParameter('api_platform.oauth.flow', $config['oauth']['flow']);
8✔
565
        $container->setParameter('api_platform.oauth.tokenUrl', $config['oauth']['tokenUrl']);
8✔
566
        $container->setParameter('api_platform.oauth.authorizationUrl', $config['oauth']['authorizationUrl']);
8✔
567
        $container->setParameter('api_platform.oauth.refreshUrl', $config['oauth']['refreshUrl']);
8✔
568
        $container->setParameter('api_platform.oauth.scopes', $config['oauth']['scopes']);
8✔
569
        $container->setParameter('api_platform.oauth.pkce', $config['oauth']['pkce']);
8✔
570
    }
571

572
    /**
573
     * Registers the Swagger, ReDoc and Swagger UI configuration.
574
     */
575
    private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
576
    {
577
        foreach (array_keys($config['swagger']['api_keys']) as $keyName) {
8✔
578
            if (!preg_match('/^[a-zA-Z0-9._-]+$/', $keyName)) {
8✔
579
                throw new RuntimeException(\sprintf('The swagger api_keys key "%s" is not valid, it should match "^[a-zA-Z0-9._-]+$"', $keyName));
×
580
            }
581
        }
582

583
        $container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
8✔
584

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

589
        if (!$config['enable_swagger']) {
8✔
590
            return;
×
591
        }
592

593
        $loader->load('openapi.php');
8✔
594

595
        if (class_exists(Yaml::class)) {
8✔
596
            $loader->load('openapi/yaml.php');
8✔
597
        }
598

599
        if ($config['enable_swagger_ui']) {
8✔
600
            $loader->load('swagger_ui.php');
6✔
601

602
            if ($config['use_symfony_listeners']) {
6✔
603
                $loader->load('symfony/swagger_ui.php');
3✔
604
            }
605

606
            $loader->load('state/swagger_ui.php');
6✔
607
        }
608

609
        if (!$config['enable_swagger_ui'] && !$config['enable_re_doc']) {
8✔
610
            // Remove the listener but keep the controller to allow customizing the path of the UI
611
            $container->removeDefinition('api_platform.swagger.listener.ui');
×
612
        }
613

614
        $container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']);
8✔
615
        $container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
8✔
616
        $container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
8✔
617
        $container->setParameter('api_platform.swagger.persist_authorization', $config['swagger']['persist_authorization']);
8✔
618
        $container->setParameter('api_platform.swagger.http_auth', $config['swagger']['http_auth']);
8✔
619
        if ($config['openapi']['swagger_ui_extra_configuration'] && $config['swagger']['swagger_ui_extra_configuration']) {
8✔
620
            throw new RuntimeException('You can not set "swagger_ui_extra_configuration" twice - in "openapi" and "swagger" section.');
×
621
        }
622
        $container->setParameter('api_platform.swagger_ui.extra_configuration', $config['openapi']['swagger_ui_extra_configuration'] ?: $config['swagger']['swagger_ui_extra_configuration']);
8✔
623
    }
624

625
    private function registerJsonApiConfiguration(array $formats, PhpFileLoader $loader, array $config): void
626
    {
627
        if (!isset($formats['jsonapi'])) {
8✔
628
            return;
×
629
        }
630

631
        $loader->load('jsonapi.php');
8✔
632
        $loader->load('state/jsonapi.php');
8✔
633
    }
634

635
    private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, PhpFileLoader $loader, array $config): void
636
    {
637
        if (!isset($formats['jsonld'])) {
8✔
638
            return;
×
639
        }
640

641
        if ($config['use_symfony_listeners']) {
8✔
642
            $loader->load('symfony/jsonld.php');
4✔
643
        } else {
644
            $loader->load('state/jsonld.php');
4✔
645
        }
646

647
        $loader->load('state/hydra.php');
8✔
648
        $loader->load('jsonld.php');
8✔
649
        $loader->load('hydra.php');
8✔
650

651
        if (!$container->has('api_platform.json_schema.schema_factory')) {
8✔
652
            $container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
×
653
        }
654
    }
655

656
    private function registerJsonHalConfiguration(array $formats, PhpFileLoader $loader): void
657
    {
658
        if (!isset($formats['jsonhal'])) {
8✔
659
            return;
×
660
        }
661

662
        $loader->load('hal.php');
8✔
663
    }
664

665
    private function registerJsonProblemConfiguration(array $errorFormats, PhpFileLoader $loader): void
666
    {
667
        if (!isset($errorFormats['jsonproblem'])) {
8✔
668
            return;
×
669
        }
670

671
        $loader->load('problem.php');
8✔
672
    }
673

674
    private function registerGraphQlConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
675
    {
676
        $enabled = $this->isConfigEnabled($container, $config['graphql']);
8✔
677
        $graphqlIntrospectionEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['introspection']);
8✔
678
        $graphiqlEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']);
8✔
679
        $maxQueryDepth = (int) $config['graphql']['max_query_depth'];
8✔
680
        $maxQueryComplexity = (int) $config['graphql']['max_query_complexity'];
8✔
681

682
        $container->setParameter('api_platform.graphql.enabled', $enabled);
8✔
683
        $container->setParameter('api_platform.graphql.max_query_depth', $maxQueryDepth);
8✔
684
        $container->setParameter('api_platform.graphql.max_query_complexity', $maxQueryComplexity);
8✔
685
        $container->setParameter('api_platform.graphql.introspection.enabled', $graphqlIntrospectionEnabled);
8✔
686
        $container->setParameter('api_platform.graphql.graphiql.enabled', $graphiqlEnabled);
8✔
687
        $container->setParameter('api_platform.graphql.collection.pagination', $config['graphql']['collection']['pagination']);
8✔
688

689
        if (!$enabled) {
8✔
690
            return;
×
691
        }
692

693
        if (!class_exists(Executor::class)) {
8✔
694
            throw new \RuntimeException('Graphql is enabled but not installed, run: composer require "api-platform/graphql".');
×
695
        }
696

697
        $container->setParameter('api_platform.graphql.default_ide', $config['graphql']['default_ide']);
8✔
698
        $container->setParameter('api_platform.graphql.nesting_separator', $config['graphql']['nesting_separator']);
8✔
699

700
        $loader->load('graphql.php');
8✔
701

702
        if (!class_exists(Environment::class) || !isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
8✔
703
            if ($graphiqlEnabled) {
×
704
                throw new RuntimeException(\sprintf('GraphiQL interfaces depend on Twig. Please activate TwigBundle for the %s environnement or disable GraphiQL.', $container->getParameter('kernel.environment')));
×
705
            }
706
            $container->removeDefinition('api_platform.graphql.action.graphiql');
×
707
        }
708

709
        $container->registerForAutoconfiguration(QueryItemResolverInterface::class)
8✔
710
            ->addTag('api_platform.graphql.resolver');
8✔
711
        $container->registerForAutoconfiguration(QueryCollectionResolverInterface::class)
8✔
712
            ->addTag('api_platform.graphql.resolver');
8✔
713
        $container->registerForAutoconfiguration(MutationResolverInterface::class)
8✔
714
            ->addTag('api_platform.graphql.resolver');
8✔
715
        $container->registerForAutoconfiguration(GraphQlTypeInterface::class)
8✔
716
            ->addTag('api_platform.graphql.type');
8✔
717
        $container->registerForAutoconfiguration(ErrorHandlerInterface::class)
8✔
718
            ->addTag('api_platform.graphql.error_handler');
8✔
719
    }
720

721
    private function registerCacheConfiguration(ContainerBuilder $container): void
722
    {
723
        if (!$container->hasParameter('kernel.debug') || !$container->getParameter('kernel.debug')) {
8✔
724
            $container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
×
725
        }
726
    }
727

728
    private function registerDoctrineOrmConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
729
    {
730
        if (!$this->isConfigEnabled($container, $config['doctrine'])) {
8✔
731
            return;
×
732
        }
733

734
        // For older versions of doctrine bridge this allows autoconfiguration for filters
735
        if (!$container->has(ManagerRegistry::class)) {
8✔
736
            $container->setAlias(ManagerRegistry::class, 'doctrine');
8✔
737
        }
738

739
        $container->registerForAutoconfiguration(QueryItemExtensionInterface::class)
8✔
740
            ->addTag('api_platform.doctrine.orm.query_extension.item');
8✔
741
        $container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
8✔
742
            ->addTag('api_platform.doctrine.orm.query_extension.collection');
8✔
743
        $container->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class);
8✔
744

745
        $container->registerForAutoconfiguration(OrmLinksHandlerInterface::class)
8✔
746
            ->addTag('api_platform.doctrine.orm.links_handler');
8✔
747

748
        $loader->load('doctrine_orm.php');
8✔
749

750
        if ($this->isConfigEnabled($container, $config['eager_loading'])) {
8✔
751
            return;
8✔
752
        }
753

754
        $container->removeAlias(EagerLoadingExtension::class);
×
755
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading');
×
756
        $container->removeAlias(FilterEagerLoadingExtension::class);
×
757
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.filter_eager_loading');
×
758
    }
759

760
    private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
761
    {
762
        if (!$this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
8✔
763
            return;
8✔
764
        }
765

766
        $container->registerForAutoconfiguration(AggregationItemExtensionInterface::class)
×
767
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.item');
×
768
        $container->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)
×
769
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection');
×
770
        $container->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
×
771
            ->setBindings(['$managerRegistry' => new Reference('doctrine_mongodb')]);
×
772
        $container->registerForAutoconfiguration(OdmLinksHandlerInterface::class)
×
773
            ->addTag('api_platform.doctrine.odm.links_handler');
×
774

775
        $loader->load('doctrine_mongodb_odm.php');
×
776
    }
777

778
    private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
779
    {
780
        $loader->load('http_cache.php');
8✔
781

782
        if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
8✔
783
            return;
×
784
        }
785

786
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
8✔
787
            $loader->load('doctrine_orm_http_cache_purger.php');
8✔
788
        }
789

790
        $loader->load('state/http_cache_purger.php');
8✔
791
        $loader->load('http_cache_purger.php');
8✔
792

793
        foreach ($config['http_cache']['invalidation']['scoped_clients'] as $client) {
8✔
794
            $definition = $container->getDefinition($client);
×
795
            $definition->addTag('api_platform.http_cache.http_client');
×
796
        }
797

798
        if (!($urls = $config['http_cache']['invalidation']['urls'])) {
8✔
799
            $urls = $config['http_cache']['invalidation']['varnish_urls'];
8✔
800
        }
801

802
        foreach ($urls as $key => $url) {
8✔
803
            $definition = new Definition(ScopingHttpClient::class, [new Reference('http_client'), $url, ['base_uri' => $url] + $config['http_cache']['invalidation']['request_options']]);
×
804
            $definition->setFactory([ScopingHttpClient::class, 'forBaseUri']);
×
805
            $definition->addTag('api_platform.http_cache.http_client');
×
806
            $container->setDefinition('api_platform.invalidation_http_client.'.$key, $definition);
×
807
        }
808

809
        $serviceName = $config['http_cache']['invalidation']['purger'];
8✔
810

811
        if (!$container->hasDefinition('api_platform.http_cache.purger')) {
8✔
812
            $container->setAlias('api_platform.http_cache.purger', $serviceName);
8✔
813
        }
814
    }
815

816
    /**
817
     * Normalizes the format from config to the one accepted by Symfony HttpFoundation.
818
     */
819
    private function getFormats(array $configFormats): array
820
    {
821
        $formats = [];
8✔
822
        foreach ($configFormats as $format => $value) {
8✔
823
            foreach ($value['mime_types'] as $mimeType) {
8✔
824
                $formats[$format][] = $mimeType;
8✔
825
            }
826
        }
827

828
        return $formats;
8✔
829
    }
830

831
    private function registerValidatorConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
832
    {
833
        if (interface_exists(ValidatorInterface::class)) {
8✔
834
            $loader->load('metadata/validator.php');
8✔
835
            $loader->load('validator/validator.php');
8✔
836

837
            if ($this->isConfigEnabled($container, $config['graphql'])) {
8✔
838
                $loader->load('graphql/validator.php');
8✔
839
            }
840

841
            $loader->load($config['use_symfony_listeners'] ? 'validator/events.php' : 'validator/state.php');
8✔
842

843
            $container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
8✔
844
                ->addTag('api_platform.validation_groups_generator');
8✔
845
            $container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
8✔
846
                ->addTag('api_platform.metadata.property_schema_restriction');
8✔
847
        }
848

849
        if (!$config['validator']) {
8✔
850
            return;
×
851
        }
852

853
        $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']);
8✔
854
    }
855

856
    private function registerDataCollectorConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
857
    {
858
        if (!$config['enable_profiler']) {
8✔
859
            return;
×
860
        }
861

862
        $loader->load('data_collector.php');
8✔
863

864
        if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
8✔
865
            $loader->load('debug.php');
8✔
866
        }
867
    }
868

869
    private function registerMercureConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
870
    {
871
        if (!$this->isConfigEnabled($container, $config['mercure'])) {
8✔
872
            return;
×
873
        }
874

875
        $container->setParameter('api_platform.mercure.include_type', $config['mercure']['include_type']);
8✔
876
        $loader->load('state/mercure.php');
8✔
877

878
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
8✔
879
            $loader->load('doctrine_orm_mercure_publisher.php');
8✔
880
        }
881
        if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
8✔
882
            $loader->load('doctrine_odm_mercure_publisher.php');
×
883
        }
884

885
        if ($this->isConfigEnabled($container, $config['graphql'])) {
8✔
886
            $loader->load('graphql_mercure.php');
8✔
887
        }
888
    }
889

890
    private function registerMessengerConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
891
    {
892
        if (!$this->isConfigEnabled($container, $config['messenger'])) {
8✔
893
            return;
×
894
        }
895

896
        $loader->load('messenger.php');
8✔
897
    }
898

899
    private function registerElasticsearchConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
900
    {
901
        $enabled = $this->isConfigEnabled($container, $config['elasticsearch']);
8✔
902

903
        $container->setParameter('api_platform.elasticsearch.enabled', $enabled);
8✔
904

905
        if (!$enabled) {
8✔
906
            return;
8✔
907
        }
908

909
        $clientClass = !class_exists(\Elasticsearch\Client::class)
×
910
            // ES v7
×
911
            ? \Elastic\Elasticsearch\Client::class
×
912
            // ES v8 and up
×
913
            : \Elasticsearch\Client::class;
×
914

915
        $clientDefinition = new Definition($clientClass);
×
916
        $container->setDefinition('api_platform.elasticsearch.client', $clientDefinition);
×
917
        $container->registerForAutoconfiguration(RequestBodySearchCollectionExtensionInterface::class)
×
918
            ->addTag('api_platform.elasticsearch.request_body_search_extension.collection');
×
919
        $container->setParameter('api_platform.elasticsearch.hosts', $config['elasticsearch']['hosts']);
×
920
        $container->setParameter('api_platform.elasticsearch.ssl_ca_bundle', $config['elasticsearch']['ssl_ca_bundle']);
×
921
        $container->setParameter('api_platform.elasticsearch.ssl_verification', $config['elasticsearch']['ssl_verification']);
×
922
        $loader->load('elasticsearch.php');
×
923
    }
924

925
    private function registerSecurityConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
926
    {
927
        /** @var string[] $bundles */
928
        $bundles = $container->getParameter('kernel.bundles');
8✔
929

930
        if (!isset($bundles['SecurityBundle'])) {
8✔
931
            return;
×
932
        }
933

934
        $loader->load('security.php');
8✔
935

936
        $loader->load('state/security.php');
8✔
937

938
        if (interface_exists(ValidatorInterface::class)) {
8✔
939
            $loader->load('state/security_validator.php');
8✔
940
        }
941

942
        if ($this->isConfigEnabled($container, $config['graphql'])) {
8✔
943
            $loader->load('graphql/security.php');
8✔
944
        }
945
    }
946

947
    private function registerOpenApiConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
948
    {
949
        $container->setParameter('api_platform.openapi.termsOfService', $config['openapi']['termsOfService']);
8✔
950
        $container->setParameter('api_platform.openapi.contact.name', $config['openapi']['contact']['name']);
8✔
951
        $container->setParameter('api_platform.openapi.contact.url', $config['openapi']['contact']['url']);
8✔
952
        $container->setParameter('api_platform.openapi.contact.email', $config['openapi']['contact']['email']);
8✔
953
        $container->setParameter('api_platform.openapi.license.name', $config['openapi']['license']['name']);
8✔
954
        $container->setParameter('api_platform.openapi.license.url', $config['openapi']['license']['url']);
8✔
955
        $container->setParameter('api_platform.openapi.license.identifier', $config['openapi']['license']['identifier']);
8✔
956
        $container->setParameter('api_platform.openapi.overrideResponses', $config['openapi']['overrideResponses']);
8✔
957

958
        $tags = [];
8✔
959
        foreach ($config['openapi']['tags'] as $tag) {
8✔
960
            $tags[] = new Tag($tag['name'], $tag['description'] ?? null);
×
961
        }
962

963
        $container->setParameter('api_platform.openapi.tags', $tags);
8✔
964

965
        $container->setParameter('api_platform.openapi.errorResourceClass', $config['openapi']['error_resource_class'] ?? null);
8✔
966
        $container->setParameter('api_platform.openapi.validationErrorResourceClass', $config['openapi']['validation_error_resource_class'] ?? null);
8✔
967

968
        $loader->load('json_schema.php');
8✔
969
    }
970

971
    private function registerMakerConfiguration(ContainerBuilder $container, array $config, PhpFileLoader $loader): void
972
    {
973
        if (!$this->isConfigEnabled($container, $config['maker'])) {
8✔
974
            return;
×
975
        }
976

977
        $namespaceprefix = $config['maker']['namespace_prefix'] ?? '';
8✔
978
        if ('' !== $namespaceprefix) {
8✔
979
            $namespaceprefix = trim($namespaceprefix, '\\').'\\';
×
980
        }
981
        $container->setParameter('api_platform.maker.namespace_prefix', $namespaceprefix);
8✔
982

983
        $loader->load('maker.php');
8✔
984
    }
985

986
    private function registerArgumentResolverConfiguration(PhpFileLoader $loader): void
987
    {
988
        $loader->load('argument_resolver.php');
8✔
989
    }
990

991
    private function registerLinkSecurityConfiguration(PhpFileLoader $loader, array $config): void
992
    {
993
        if ($config['enable_link_security']) {
8✔
994
            $loader->load('link_security.php');
8✔
995
        }
996
    }
997

998
    private function registerJsonStreamerConfiguration(ContainerBuilder $container, PhpFileLoader $loader, array $formats, array $config): void
999
    {
1000
        if (!$config['enable_json_streamer']) {
8✔
1001
            return;
×
1002
        }
1003

1004
        if (!class_exists(JsonStreamWriter::class)) {
8✔
1005
            throw new RuntimeException('symfony/json-streamer is not installed.');
×
1006
        }
1007

1008
        // @TODO symfony/json-streamer:>=7.4.1 add composer conflict
1009
        if (!class_exists(ControllerHelper::class)) {
8✔
1010
            throw new RuntimeException('Symfony symfony/json-stream:^7.4 is needed.');
×
1011
        }
1012

1013
        if (isset($formats['jsonld'])) {
8✔
1014
            $container->setParameter('.json_streamer.stream_writers_dir.jsonld', '%kernel.cache_dir%/json_streamer/stream_writer/jsonld');
8✔
1015
            $container->setParameter('.json_streamer.stream_readers_dir.jsonld', '%kernel.cache_dir%/json_streamer/stream_reader/jsonld');
8✔
1016
            $container->setParameter('.json_streamer.lazy_ghosts_dir.jsonld', '%kernel.cache_dir%/json_streamer/lazy_ghost/jsonld');
8✔
1017
        }
1018

1019
        $loader->load('json_streamer/common.php');
8✔
1020

1021
        if ($config['use_symfony_listeners']) {
8✔
1022
            $loader->load('json_streamer/events.php');
4✔
1023
        } else {
1024
            if (isset($formats['jsonld'])) {
4✔
1025
                $loader->load('json_streamer/hydra.php');
4✔
1026
            }
1027

1028
            if (isset($formats['json'])) {
4✔
1029
                $loader->load('json_streamer/json.php');
4✔
1030
            }
1031
        }
1032
    }
1033
}
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