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

api-platform / core / 17581213192

09 Sep 2025 11:31AM UTC coverage: 0.0% (-22.6%) from 22.604%
17581213192

Pull #7374

github

web-flow
Merge 0f1360e1a into 6db55be8c
Pull Request #7374: fix(jsonld): various json streamer fixes

0 of 34 new or added lines in 2 files covered. (0.0%)

12081 existing lines in 401 files now uncovered.

0 of 52792 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/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\XmlFileLoader;
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\Uid\AbstractUid;
70
use Symfony\Component\Validator\Validator\ValidatorInterface;
71
use Symfony\Component\Yaml\Yaml;
72
use Twig\Environment;
73

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

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

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

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

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

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

UNCOV
142
        if (!isset($errorFormats['json'])) {
×
UNCOV
143
            $errorFormats['json'] = ['application/problem+json', 'application/json'];
×
144
        }
145

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

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

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

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

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

208
                $definition->addTag('api_platform.resource_mutator', [
×
209
                    'resourceClass' => $attribute->resourceClass,
×
210
                ]);
×
UNCOV
211
            },
×
UNCOV
212
        );
×
213

UNCOV
214
        $container->registerAttributeForAutoconfiguration(
×
UNCOV
215
            AsOperationMutator::class,
×
UNCOV
216
            static function (ChildDefinition $definition, AsOperationMutator $attribute, \Reflector $reflector): void {
×
217
                if (!$reflector instanceof \ReflectionClass) {
×
218
                    return;
×
219
                }
220

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

225
                $definition->addTag('api_platform.operation_mutator', [
×
226
                    'operationName' => $attribute->operationName,
×
227
                ]);
×
UNCOV
228
            },
×
UNCOV
229
        );
×
230

UNCOV
231
        if (!$container->has('api_platform.state.item_provider')) {
×
232
            $container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
×
233
        }
234

UNCOV
235
        if ($container->getParameter('kernel.debug')) {
×
UNCOV
236
            $this->injectStopwatch($container);
×
237
        }
238
    }
239

240
    private function injectStopwatch(ContainerBuilder $container): void
241
    {
UNCOV
242
        $services = [
×
UNCOV
243
            'api_platform.state_processor.add_link_header',
×
UNCOV
244
            'api_platform.state_processor.respond',
×
UNCOV
245
            'api_platform.state_processor.serialize',
×
UNCOV
246
            'api_platform.state_processor.write',
×
UNCOV
247
            'api_platform.state_provider.content_negotiation',
×
UNCOV
248
            'api_platform.state_provider.deserialize',
×
UNCOV
249
            'api_platform.state_provider.parameter',
×
UNCOV
250
            'api_platform.state_provider.read',
×
UNCOV
251
        ];
×
252

UNCOV
253
        foreach ($services as $id) {
×
UNCOV
254
            if (!$container->hasDefinition($id)) {
×
255
                continue;
×
256
            }
257

UNCOV
258
            $definition = $container->getDefinition($id);
×
UNCOV
259
            $definition->addMethodCall('setStopwatch', [new Reference('debug.stopwatch', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE)]);
×
260
        }
261
    }
262

263
    private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats): void
264
    {
UNCOV
265
        $loader->load('state/state.xml');
×
UNCOV
266
        $loader->load('symfony/symfony.xml');
×
UNCOV
267
        $loader->load('api.xml');
×
UNCOV
268
        $loader->load('filter.xml');
×
269

UNCOV
270
        if (class_exists(UuidDenormalizer::class) && class_exists(Uuid::class)) {
×
UNCOV
271
            $loader->load('ramsey_uuid.xml');
×
272
        }
273

UNCOV
274
        if (class_exists(AbstractUid::class)) {
×
UNCOV
275
            $loader->load('symfony/uid.xml');
×
276
        }
277

UNCOV
278
        $defaultContext = ['hydra_prefix' => $config['serializer']['hydra_prefix']] + ($container->hasParameter('serializer.default_context') ? $container->getParameter('serializer.default_context') : []);
×
279

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

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

UNCOV
335
        $container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
×
UNCOV
336
        $container->setAlias('api_platform.inflector', $config['inflector']);
×
337

UNCOV
338
        if ($config['name_converter']) {
×
UNCOV
339
            $container->setAlias('api_platform.name_converter', $config['name_converter']);
×
340
        }
UNCOV
341
        $container->setParameter('api_platform.asset_package', $config['asset_package']);
×
UNCOV
342
        $container->setParameter('api_platform.defaults', $this->normalizeDefaults($config['defaults'] ?? []));
×
343

UNCOV
344
        if ($container->getParameter('kernel.debug')) {
×
UNCOV
345
            $container->removeDefinition('api_platform.serializer.mapping.cache_class_metadata_factory');
×
346
        }
347
    }
348

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

UNCOV
356
        foreach ($defaults as $key => $value) {
×
UNCOV
357
            if (!str_starts_with($key, 'pagination_')) {
×
UNCOV
358
                continue;
×
359
            }
360

UNCOV
361
            $paginationOptions[str_replace('pagination_', '', $key)] = $value;
×
362
        }
363

UNCOV
364
        return array_merge($collectionPaginationConfiguration, $paginationOptions);
×
365
    }
366

367
    private function normalizeDefaults(array $defaults): array
368
    {
UNCOV
369
        $normalizedDefaults = ['extra_properties' => $defaults['extra_properties'] ?? []];
×
UNCOV
370
        unset($defaults['extra_properties']);
×
371

UNCOV
372
        $rc = new \ReflectionClass(ApiResource::class);
×
UNCOV
373
        $publicProperties = [];
×
UNCOV
374
        foreach ($rc->getConstructor()->getParameters() as $param) {
×
UNCOV
375
            $publicProperties[$param->getName()] = true;
×
376
        }
377

UNCOV
378
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
×
UNCOV
379
        foreach ($defaults as $option => $value) {
×
UNCOV
380
            if (isset($publicProperties[$nameConverter->denormalize($option)])) {
×
UNCOV
381
                $normalizedDefaults[$option] = $value;
×
382

UNCOV
383
                continue;
×
384
            }
385

386
            $normalizedDefaults['extra_properties'][$option] = $value;
×
387
        }
388

UNCOV
389
        return $normalizedDefaults;
×
390
    }
391

392
    private function registerMetadataConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
393
    {
UNCOV
394
        [$xmlResources, $yamlResources, $phpResources] = $this->getResourcesToWatch($container, $config);
×
395

UNCOV
396
        $container->setParameter('api_platform.class_name_resources', $this->getClassNameResources());
×
397

UNCOV
398
        $loader->load('metadata/resource_name.xml');
×
UNCOV
399
        $loader->load('metadata/property_name.xml');
×
400

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

408
        // V3 metadata
UNCOV
409
        $loader->load('metadata/php.xml');
×
UNCOV
410
        $loader->load('metadata/xml.xml');
×
UNCOV
411
        $loader->load('metadata/links.xml');
×
UNCOV
412
        $loader->load('metadata/property.xml');
×
UNCOV
413
        $loader->load('metadata/resource.xml');
×
UNCOV
414
        $loader->load('metadata/operation.xml');
×
UNCOV
415
        $loader->load('metadata/mutator.xml');
×
416

UNCOV
417
        $container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
×
UNCOV
418
        $container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
×
419

UNCOV
420
        if (class_exists(PhpDocParser::class)) {
×
UNCOV
421
            $loader->load('metadata/php_doc.xml');
×
422
        }
423

UNCOV
424
        if (class_exists(Yaml::class)) {
×
UNCOV
425
            $loader->load('metadata/yaml.xml');
×
UNCOV
426
            $container->getDefinition('api_platform.metadata.resource_extractor.yaml')->replaceArgument(0, $yamlResources);
×
UNCOV
427
            $container->getDefinition('api_platform.metadata.property_extractor.yaml')->replaceArgument(0, $yamlResources);
×
428
        }
429

UNCOV
430
        $container->getDefinition('api_platform.metadata.resource_extractor.php_file')->replaceArgument(0, $phpResources);
×
431
    }
432

433
    private function getClassNameResources(): array
434
    {
UNCOV
435
        return [
×
UNCOV
436
            Error::class,
×
UNCOV
437
            ValidationException::class,
×
UNCOV
438
        ];
×
439
    }
440

441
    private function getBundlesResourcesPaths(ContainerBuilder $container, array $config): array
442
    {
UNCOV
443
        $bundlesResourcesPaths = [];
×
444

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

UNCOV
464
            foreach ($paths as $path) {
×
UNCOV
465
                if ($container->fileExists($path, false)) {
×
UNCOV
466
                    $bundlesResourcesPaths[] = $path;
×
467
                }
468
            }
469
        }
470

UNCOV
471
        return $bundlesResourcesPaths;
×
472
    }
473

474
    private function getResourcesToWatch(ContainerBuilder $container, array $config): array
475
    {
UNCOV
476
        $paths = array_unique(array_merge($this->getBundlesResourcesPaths($container, $config), $config['mapping']['paths']));
×
477

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

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

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

UNCOV
495
        $resources = ['yml' => [], 'xml' => [], 'php' => [], 'dir' => []];
×
496

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

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

506
                continue;
×
507
            }
508

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

514
                $resources['php'][] = $path;
×
515

516
                continue;
×
517
            }
518

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

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

UNCOV
528
                $resources['dir'][] = $path;
×
UNCOV
529
                $container->addResource(new DirectoryResource($path, '/\.(xml|ya?ml|php)$/'));
×
530

UNCOV
531
                continue;
×
532
            }
533

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

539
                $resources['yaml' === $matches[1] ? 'yml' : $matches[1]][] = $path;
×
540

541
                continue;
×
542
            }
543

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

UNCOV
547
        $container->setParameter('api_platform.resource_class_directories', $resources['dir']);
×
548

UNCOV
549
        return [$resources['xml'], $resources['yml'], $resources['php']];
×
550
    }
551

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

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

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

UNCOV
581
        $container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
×
582

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

UNCOV
587
        if (!$config['enable_swagger']) {
×
588
            return;
×
589
        }
590

UNCOV
591
        $loader->load('openapi.xml');
×
592

UNCOV
593
        if (class_exists(Yaml::class)) {
×
UNCOV
594
            $loader->load('openapi/yaml.xml');
×
595
        }
596

UNCOV
597
        $loader->load('swagger_ui.xml');
×
598

UNCOV
599
        if ($config['use_symfony_listeners']) {
×
600
            $loader->load('symfony/swagger_ui.xml');
×
601
        }
602

UNCOV
603
        if ($config['enable_swagger_ui']) {
×
UNCOV
604
            $loader->load('state/swagger_ui.xml');
×
605
        }
606

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

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

623
    private function registerJsonApiConfiguration(array $formats, XmlFileLoader $loader, array $config): void
624
    {
UNCOV
625
        if (!isset($formats['jsonapi'])) {
×
626
            return;
×
627
        }
628

UNCOV
629
        $loader->load('jsonapi.xml');
×
UNCOV
630
        $loader->load('state/jsonapi.xml');
×
631
    }
632

633
    private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, XmlFileLoader $loader, array $config): void
634
    {
UNCOV
635
        if (!isset($formats['jsonld'])) {
×
636
            return;
×
637
        }
638

UNCOV
639
        if ($config['use_symfony_listeners']) {
×
640
            $loader->load('symfony/jsonld.xml');
×
641
        } else {
UNCOV
642
            $loader->load('state/jsonld.xml');
×
643
        }
644

UNCOV
645
        $loader->load('state/hydra.xml');
×
UNCOV
646
        $loader->load('jsonld.xml');
×
UNCOV
647
        $loader->load('hydra.xml');
×
648

UNCOV
649
        if (!$container->has('api_platform.json_schema.schema_factory')) {
×
650
            $container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
×
651
        }
652
    }
653

654
    private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader): void
655
    {
UNCOV
656
        if (!isset($formats['jsonhal'])) {
×
657
            return;
×
658
        }
659

UNCOV
660
        $loader->load('hal.xml');
×
661
    }
662

663
    private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLoader $loader): void
664
    {
UNCOV
665
        if (!isset($errorFormats['jsonproblem'])) {
×
666
            return;
×
667
        }
668

UNCOV
669
        $loader->load('problem.xml');
×
670
    }
671

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

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

UNCOV
687
        if (!$enabled) {
×
688
            return;
×
689
        }
690

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

UNCOV
695
        $container->setParameter('api_platform.graphql.default_ide', $config['graphql']['default_ide']);
×
UNCOV
696
        $container->setParameter('api_platform.graphql.nesting_separator', $config['graphql']['nesting_separator']);
×
697

UNCOV
698
        $loader->load('graphql.xml');
×
699

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

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

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

726
    private function registerDoctrineOrmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
727
    {
UNCOV
728
        if (!$this->isConfigEnabled($container, $config['doctrine'])) {
×
729
            return;
×
730
        }
731

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

UNCOV
737
        $container->registerForAutoconfiguration(QueryItemExtensionInterface::class)
×
UNCOV
738
            ->addTag('api_platform.doctrine.orm.query_extension.item');
×
UNCOV
739
        $container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
×
UNCOV
740
            ->addTag('api_platform.doctrine.orm.query_extension.collection');
×
UNCOV
741
        $container->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class);
×
742

UNCOV
743
        $container->registerForAutoconfiguration(OrmLinksHandlerInterface::class)
×
UNCOV
744
            ->addTag('api_platform.doctrine.orm.links_handler');
×
745

UNCOV
746
        $loader->load('doctrine_orm.xml');
×
747

UNCOV
748
        if ($this->isConfigEnabled($container, $config['eager_loading'])) {
×
UNCOV
749
            return;
×
750
        }
751

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

758
    private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
759
    {
UNCOV
760
        if (!$this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
×
UNCOV
761
            return;
×
762
        }
763

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

773
        $loader->load('doctrine_mongodb_odm.xml');
×
774
    }
775

776
    private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
777
    {
UNCOV
778
        $loader->load('http_cache.xml');
×
779

UNCOV
780
        if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
×
781
            return;
×
782
        }
783

UNCOV
784
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
×
UNCOV
785
            $loader->load('doctrine_orm_http_cache_purger.xml');
×
786
        }
787

UNCOV
788
        $loader->load('state/http_cache_purger.xml');
×
UNCOV
789
        $loader->load('http_cache_purger.xml');
×
790

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

UNCOV
796
        if (!($urls = $config['http_cache']['invalidation']['urls'])) {
×
UNCOV
797
            $urls = $config['http_cache']['invalidation']['varnish_urls'];
×
798
        }
799

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

UNCOV
807
        $serviceName = $config['http_cache']['invalidation']['purger'];
×
808

UNCOV
809
        if (!$container->hasDefinition('api_platform.http_cache.purger')) {
×
UNCOV
810
            $container->setAlias('api_platform.http_cache.purger', $serviceName);
×
811
        }
812
    }
813

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

UNCOV
826
        return $formats;
×
827
    }
828

829
    private function registerValidatorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
830
    {
UNCOV
831
        if (interface_exists(ValidatorInterface::class)) {
×
UNCOV
832
            $loader->load('metadata/validator.xml');
×
UNCOV
833
            $loader->load('validator/validator.xml');
×
834

UNCOV
835
            if ($this->isConfigEnabled($container, $config['graphql'])) {
×
UNCOV
836
                $loader->load('graphql/validator.xml');
×
837
            }
838

UNCOV
839
            $loader->load($config['use_symfony_listeners'] ? 'validator/events.xml' : 'validator/state.xml');
×
840

UNCOV
841
            $container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
×
UNCOV
842
                ->addTag('api_platform.validation_groups_generator');
×
UNCOV
843
            $container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
×
UNCOV
844
                ->addTag('api_platform.metadata.property_schema_restriction');
×
845
        }
846

UNCOV
847
        if (!$config['validator']) {
×
848
            return;
×
849
        }
850

UNCOV
851
        $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']);
×
852
    }
853

854
    private function registerDataCollectorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
855
    {
UNCOV
856
        if (!$config['enable_profiler']) {
×
857
            return;
×
858
        }
859

UNCOV
860
        $loader->load('data_collector.xml');
×
861

UNCOV
862
        if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
×
UNCOV
863
            $loader->load('debug.xml');
×
864
        }
865
    }
866

867
    private function registerMercureConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
868
    {
UNCOV
869
        if (!$this->isConfigEnabled($container, $config['mercure'])) {
×
870
            return;
×
871
        }
872

UNCOV
873
        $container->setParameter('api_platform.mercure.include_type', $config['mercure']['include_type']);
×
UNCOV
874
        $loader->load('state/mercure.xml');
×
875

UNCOV
876
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
×
UNCOV
877
            $loader->load('doctrine_orm_mercure_publisher.xml');
×
878
        }
UNCOV
879
        if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
×
880
            $loader->load('doctrine_odm_mercure_publisher.xml');
×
881
        }
882

UNCOV
883
        if ($this->isConfigEnabled($container, $config['graphql'])) {
×
UNCOV
884
            $loader->load('graphql_mercure.xml');
×
885
        }
886
    }
887

888
    private function registerMessengerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
889
    {
UNCOV
890
        if (!$this->isConfigEnabled($container, $config['messenger'])) {
×
891
            return;
×
892
        }
893

UNCOV
894
        $loader->load('messenger.xml');
×
895
    }
896

897
    private function registerElasticsearchConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
898
    {
UNCOV
899
        $enabled = $this->isConfigEnabled($container, $config['elasticsearch']);
×
900

UNCOV
901
        $container->setParameter('api_platform.elasticsearch.enabled', $enabled);
×
902

UNCOV
903
        if (!$enabled) {
×
UNCOV
904
            return;
×
905
        }
906

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

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

921
    private function registerSecurityConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
922
    {
923
        /** @var string[] $bundles */
UNCOV
924
        $bundles = $container->getParameter('kernel.bundles');
×
925

UNCOV
926
        if (!isset($bundles['SecurityBundle'])) {
×
927
            return;
×
928
        }
929

UNCOV
930
        $loader->load('security.xml');
×
931

UNCOV
932
        $loader->load('state/security.xml');
×
933

UNCOV
934
        if (interface_exists(ValidatorInterface::class)) {
×
UNCOV
935
            $loader->load('state/security_validator.xml');
×
936
        }
937

UNCOV
938
        if ($this->isConfigEnabled($container, $config['graphql'])) {
×
UNCOV
939
            $loader->load('graphql/security.xml');
×
940
        }
941
    }
942

943
    private function registerOpenApiConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
944
    {
UNCOV
945
        $container->setParameter('api_platform.openapi.termsOfService', $config['openapi']['termsOfService']);
×
UNCOV
946
        $container->setParameter('api_platform.openapi.contact.name', $config['openapi']['contact']['name']);
×
UNCOV
947
        $container->setParameter('api_platform.openapi.contact.url', $config['openapi']['contact']['url']);
×
UNCOV
948
        $container->setParameter('api_platform.openapi.contact.email', $config['openapi']['contact']['email']);
×
UNCOV
949
        $container->setParameter('api_platform.openapi.license.name', $config['openapi']['license']['name']);
×
UNCOV
950
        $container->setParameter('api_platform.openapi.license.url', $config['openapi']['license']['url']);
×
UNCOV
951
        $container->setParameter('api_platform.openapi.license.identifier', $config['openapi']['license']['identifier']);
×
UNCOV
952
        $container->setParameter('api_platform.openapi.overrideResponses', $config['openapi']['overrideResponses']);
×
953

UNCOV
954
        $tags = [];
×
UNCOV
955
        foreach ($config['openapi']['tags'] as $tag) {
×
956
            $tags[] = new Tag($tag['name'], $tag['description'] ?? null);
×
957
        }
958

UNCOV
959
        $container->setParameter('api_platform.openapi.tags', $tags);
×
960

UNCOV
961
        $container->setParameter('api_platform.openapi.errorResourceClass', $config['openapi']['error_resource_class'] ?? null);
×
UNCOV
962
        $container->setParameter('api_platform.openapi.validationErrorResourceClass', $config['openapi']['validation_error_resource_class'] ?? null);
×
963

UNCOV
964
        $loader->load('json_schema.xml');
×
965
    }
966

967
    private function registerMakerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
968
    {
UNCOV
969
        if (!$this->isConfigEnabled($container, $config['maker'])) {
×
970
            return;
×
971
        }
972

UNCOV
973
        $loader->load('maker.xml');
×
974
    }
975

976
    private function registerArgumentResolverConfiguration(XmlFileLoader $loader): void
977
    {
UNCOV
978
        $loader->load('argument_resolver.xml');
×
979
    }
980

981
    private function registerLinkSecurityConfiguration(XmlFileLoader $loader, array $config): void
982
    {
UNCOV
983
        if ($config['enable_link_security']) {
×
UNCOV
984
            $loader->load('link_security.xml');
×
985
        }
986
    }
987

988
    private function registerJsonStreamerConfiguration(ContainerBuilder $container, XmlFileLoader $loader, array $formats, array $config): void
989
    {
UNCOV
990
        if (!$config['enable_json_streamer']) {
×
991
            return;
×
992
        }
993

UNCOV
994
        if (!class_exists(JsonStreamWriter::class)) {
×
995
            throw new RuntimeException('symfony/json-streamer is not installed.');
×
996
        }
997

998
        // @TODO symfony/json-streamer:>=7.4.1 add composer conflict
UNCOV
999
        if (!class_exists(ControllerHelper::class)) {
×
1000
            throw new RuntimeException('Symfony symfony/json-stream:^7.4 is needed.');
×
1001
        }
1002

UNCOV
1003
        if (isset($formats['jsonld'])) {
×
UNCOV
1004
            $container->setParameter('.json_streamer.stream_writers_dir.jsonld', '%kernel.cache_dir%/json_streamer/stream_writer/jsonld');
×
UNCOV
1005
            $container->setParameter('.json_streamer.stream_readers_dir.jsonld', '%kernel.cache_dir%/json_streamer/stream_reader/jsonld');
×
UNCOV
1006
            $container->setParameter('.json_streamer.lazy_ghosts_dir.jsonld', '%kernel.cache_dir%/json_streamer/lazy_ghost/jsonld');
×
1007
        }
1008

UNCOV
1009
        $loader->load('json_streamer/common.xml');
×
1010

UNCOV
1011
        if ($config['use_symfony_listeners']) {
×
1012
            $loader->load('json_streamer/events.xml');
×
1013
        } else {
UNCOV
1014
            if (isset($formats['jsonld'])) {
×
UNCOV
1015
                $loader->load('json_streamer/hydra.xml');
×
1016
            }
1017

UNCOV
1018
            if (isset($formats['json'])) {
×
UNCOV
1019
                $loader->load('json_streamer/json.xml');
×
1020
            }
1021
        }
1022
    }
1023
}
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