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

api-platform / core / 6665127824

27 Oct 2023 09:01AM UTC coverage: 37.494% (+0.1%) from 37.396%
6665127824

push

github

web-flow
fix: use error normalizers (#5931)

Use defaults.extra_properties.skip_deprecated_exception_normalizers to
skip these normalizers.

fixes #5921

32 of 32 new or added lines in 7 files covered. (100.0%)

10316 of 27514 relevant lines covered (37.49%)

20.62 hits per line

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

87.23
/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\ApiResource\Error;
17
use ApiPlatform\Doctrine\Odm\Extension\AggregationCollectionExtensionInterface;
18
use ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface;
19
use ApiPlatform\Doctrine\Odm\Filter\AbstractFilter as DoctrineMongoDbOdmAbstractFilter;
20
use ApiPlatform\Doctrine\Odm\State\LinksHandlerInterface as OdmLinksHandlerInterface;
21
use ApiPlatform\Doctrine\Orm\Extension\EagerLoadingExtension;
22
use ApiPlatform\Doctrine\Orm\Extension\FilterEagerLoadingExtension;
23
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface as DoctrineQueryCollectionExtensionInterface;
24
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
25
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter as DoctrineOrmAbstractFilter;
26
use ApiPlatform\Doctrine\Orm\State\LinksHandlerInterface as OrmLinksHandlerInterface;
27
use ApiPlatform\Elasticsearch\Extension\RequestBodySearchCollectionExtensionInterface;
28
use ApiPlatform\GraphQl\Error\ErrorHandlerInterface;
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\FilterInterface;
35
use ApiPlatform\Metadata\UrlGeneratorInterface;
36
use ApiPlatform\Metadata\Util\Inflector;
37
use ApiPlatform\State\ProcessorInterface;
38
use ApiPlatform\State\ProviderInterface;
39
use ApiPlatform\Symfony\GraphQl\Resolver\Factory\DataCollectorResolverFactory;
40
use ApiPlatform\Symfony\Validator\Exception\ValidationException;
41
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRestrictionMetadataInterface;
42
use ApiPlatform\Symfony\Validator\ValidationGroupsGeneratorInterface;
43
use Doctrine\Persistence\ManagerRegistry;
44
use phpDocumentor\Reflection\DocBlockFactoryInterface;
45
use PHPStan\PhpDocParser\Parser\PhpDocParser;
46
use Ramsey\Uuid\Uuid;
47
use Symfony\Component\Config\FileLocator;
48
use Symfony\Component\Config\Resource\DirectoryResource;
49
use Symfony\Component\DependencyInjection\ContainerBuilder;
50
use Symfony\Component\DependencyInjection\ContainerInterface;
51
use Symfony\Component\DependencyInjection\Definition;
52
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
53
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
54
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
55
use Symfony\Component\DependencyInjection\Reference;
56
use Symfony\Component\Finder\Finder;
57
use Symfony\Component\HttpClient\ScopingHttpClient;
58
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
59
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
60
use Symfony\Component\Uid\AbstractUid;
61
use Symfony\Component\Validator\Validator\ValidatorInterface;
62
use Symfony\Component\Yaml\Yaml;
63
use Twig\Environment;
64

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

98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function load(array $configs, ContainerBuilder $container): void
102
    {
103
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
108✔
104

105
        $configuration = new Configuration();
108✔
106
        $config = $this->processConfiguration($configuration, $configs);
108✔
107

108
        if (!$config['formats']) {
105✔
109
            trigger_deprecation('api-platform/core', '3.2', 'Setting the "formats" section will be mandatory in API Platform 4.');
×
110
            $config['formats'] = [
×
111
                'jsonld' => ['mime_types' => ['application/ld+json']],
×
112
                // Note that in API Platform 4 this will be removed as it was used for documentation only and are is now present in the docsFormats
113
                'json' => ['mime_types' => ['application/json']], // Swagger support
×
114
            ];
×
115
        }
116

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

122
        if (!isset($errorFormats['html']) && $config['enable_swagger'] && $config['enable_swagger_ui']) {
105✔
123
            $errorFormats['html'] = ['text/html'];
102✔
124
        }
125

126
        if (!isset($errorFormats['json'])) {
105✔
127
            $errorFormats['json'] = ['application/problem+json', 'application/json'];
105✔
128
        }
129

130
        if (!isset($errorFormats['jsonproblem'])) {
105✔
131
            $errorFormats['jsonproblem'] = ['application/problem+json'];
×
132
        }
133

134
        if ($this->isConfigEnabled($container, $config['graphql']) && !isset($formats['json'])) {
105✔
135
            trigger_deprecation('api-platform/core', '3.2', 'Add the "json" format to the configuration to use GraphQL.');
3✔
136
            $formats['json'] = ['application/json'];
3✔
137
        }
138

139
        // Backward Compatibility layer
140
        if (isset($formats['jsonapi']) && !isset($patchFormats['jsonapi'])) {
105✔
141
            $patchFormats['jsonapi'] = ['application/vnd.api+json'];
6✔
142
        }
143

144
        if (isset($docsFormats['json']) && !isset($docsFormats['jsonopenapi'])) {
105✔
145
            trigger_deprecation('api-platform/core', '3.2', 'The "json" format is too broad, use ["jsonopenapi" => ["application/vnd.openapi+json"]] instead.');
×
146
            $docsFormats['jsonopenapi'] = ['application/vnd.openapi+json'];
×
147
        }
148

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

172
        $container->registerForAutoconfiguration(FilterInterface::class)
102✔
173
            ->addTag('api_platform.filter');
102✔
174
        $container->registerForAutoconfiguration(ProviderInterface::class)
102✔
175
            ->addTag('api_platform.state_provider');
102✔
176
        $container->registerForAutoconfiguration(ProcessorInterface::class)
102✔
177
            ->addTag('api_platform.state_processor');
102✔
178

179
        if (!$container->has('api_platform.state.item_provider')) {
102✔
180
            $container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
×
181
        }
182

183
        $this->registerInflectorConfiguration($config);
102✔
184
    }
185

186
    private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats): void
187
    {
188
        $loader->load('symfony/events.xml');
105✔
189
        $loader->load('symfony/controller.xml');
105✔
190
        $loader->load('api.xml');
105✔
191
        $loader->load('state.xml');
105✔
192
        $loader->load('filter.xml');
105✔
193

194
        if (class_exists(Uuid::class)) {
105✔
195
            $loader->load('ramsey_uuid.xml');
105✔
196
        }
197

198
        if (class_exists(AbstractUid::class)) {
105✔
199
            $loader->load('symfony/uid.xml');
105✔
200
        }
201

202
        // TODO: remove in 4.x
203
        $container->setParameter('api_platform.event_listeners_backward_compatibility_layer', $config['event_listeners_backward_compatibility_layer']);
105✔
204
        $loader->load('legacy/events.xml');
105✔
205

206
        $container->setParameter('api_platform.enable_entrypoint', $config['enable_entrypoint']);
105✔
207
        $container->setParameter('api_platform.enable_docs', $config['enable_docs']);
105✔
208
        $container->setParameter('api_platform.keep_legacy_inflector', $config['keep_legacy_inflector']);
105✔
209
        $container->setParameter('api_platform.title', $config['title']);
105✔
210
        $container->setParameter('api_platform.description', $config['description']);
105✔
211
        $container->setParameter('api_platform.version', $config['version']);
105✔
212
        $container->setParameter('api_platform.show_webby', $config['show_webby']);
105✔
213
        $container->setParameter('api_platform.url_generation_strategy', $config['defaults']['url_generation_strategy'] ?? UrlGeneratorInterface::ABS_PATH);
105✔
214
        $container->setParameter('api_platform.exception_to_status', $config['exception_to_status']);
105✔
215
        $container->setParameter('api_platform.formats', $formats);
105✔
216
        $container->setParameter('api_platform.patch_formats', $patchFormats);
105✔
217
        $container->setParameter('api_platform.error_formats', $errorFormats);
105✔
218
        $container->setParameter('api_platform.docs_formats', $docsFormats);
105✔
219
        $container->setParameter('api_platform.eager_loading.enabled', $this->isConfigEnabled($container, $config['eager_loading']));
105✔
220
        $container->setParameter('api_platform.eager_loading.max_joins', $config['eager_loading']['max_joins']);
105✔
221
        $container->setParameter('api_platform.eager_loading.fetch_partial', $config['eager_loading']['fetch_partial']);
105✔
222
        $container->setParameter('api_platform.eager_loading.force_eager', $config['eager_loading']['force_eager']);
105✔
223
        $container->setParameter('api_platform.collection.exists_parameter_name', $config['collection']['exists_parameter_name']);
105✔
224
        $container->setParameter('api_platform.collection.order', $config['collection']['order']);
105✔
225
        $container->setParameter('api_platform.collection.order_parameter_name', $config['collection']['order_parameter_name']);
105✔
226
        $container->setParameter('api_platform.collection.order_nulls_comparison', $config['collection']['order_nulls_comparison']);
105✔
227
        $container->setParameter('api_platform.collection.pagination.enabled', $config['defaults']['pagination_enabled'] ?? true);
105✔
228
        $container->setParameter('api_platform.collection.pagination.partial', $config['defaults']['pagination_partial'] ?? false);
105✔
229
        $container->setParameter('api_platform.collection.pagination.client_enabled', $config['defaults']['pagination_client_enabled'] ?? false);
105✔
230
        $container->setParameter('api_platform.collection.pagination.client_items_per_page', $config['defaults']['pagination_client_items_per_page'] ?? false);
105✔
231
        $container->setParameter('api_platform.collection.pagination.client_partial', $config['defaults']['pagination_client_partial'] ?? false);
105✔
232
        $container->setParameter('api_platform.collection.pagination.items_per_page', $config['defaults']['pagination_items_per_page'] ?? 30);
105✔
233
        $container->setParameter('api_platform.collection.pagination.maximum_items_per_page', $config['defaults']['pagination_maximum_items_per_page'] ?? null);
105✔
234
        $container->setParameter('api_platform.collection.pagination.page_parameter_name', $config['defaults']['pagination_page_parameter_name'] ?? $config['collection']['pagination']['page_parameter_name']);
105✔
235
        $container->setParameter('api_platform.collection.pagination.enabled_parameter_name', $config['defaults']['pagination_enabled_parameter_name'] ?? $config['collection']['pagination']['enabled_parameter_name']);
105✔
236
        $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']);
105✔
237
        $container->setParameter('api_platform.collection.pagination.partial_parameter_name', $config['defaults']['pagination_partial_parameter_name'] ?? $config['collection']['pagination']['partial_parameter_name']);
105✔
238
        $container->setParameter('api_platform.collection.pagination', $this->getPaginationDefaults($config['defaults'] ?? [], $config['collection']['pagination']));
105✔
239
        $container->setParameter('api_platform.http_cache.etag', $config['defaults']['cache_headers']['etag'] ?? true);
105✔
240
        $container->setParameter('api_platform.http_cache.max_age', $config['defaults']['cache_headers']['max_age'] ?? null);
105✔
241
        $container->setParameter('api_platform.http_cache.shared_max_age', $config['defaults']['cache_headers']['shared_max_age'] ?? null);
105✔
242
        $container->setParameter('api_platform.http_cache.vary', $config['defaults']['cache_headers']['vary'] ?? ['Accept']);
105✔
243
        $container->setParameter('api_platform.http_cache.public', $config['defaults']['cache_headers']['public'] ?? $config['http_cache']['public']);
105✔
244
        $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']);
105✔
245
        $container->setParameter('api_platform.http_cache.invalidation.xkey.glue', $config['defaults']['cache_headers']['invalidation']['xkey']['glue'] ?? $config['http_cache']['invalidation']['xkey']['glue']);
105✔
246

247
        $container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
105✔
248

249
        if ($config['name_converter']) {
105✔
250
            $container->setAlias('api_platform.name_converter', $config['name_converter']);
6✔
251
        }
252
        $container->setParameter('api_platform.asset_package', $config['asset_package']);
105✔
253
        $container->setParameter('api_platform.defaults', $this->normalizeDefaults($config['defaults'] ?? []));
105✔
254

255
        if ($container->getParameter('kernel.debug')) {
105✔
256
            $container->removeDefinition('api_platform.serializer.mapping.cache_class_metadata_factory');
12✔
257
        }
258
    }
259

260
    /**
261
     * This method will be removed in 3.0 when "defaults" will be the regular configuration path for the pagination.
262
     */
263
    private function getPaginationDefaults(array $defaults, array $collectionPaginationConfiguration): array
264
    {
265
        $paginationOptions = [];
105✔
266

267
        foreach ($defaults as $key => $value) {
105✔
268
            if (!str_starts_with($key, 'pagination_')) {
105✔
269
                continue;
105✔
270
            }
271

272
            $paginationOptions[str_replace('pagination_', '', $key)] = $value;
3✔
273
        }
274

275
        return array_merge($collectionPaginationConfiguration, $paginationOptions);
105✔
276
    }
277

278
    private function normalizeDefaults(array $defaults): array
279
    {
280
        $normalizedDefaults = ['extra_properties' => $defaults['extra_properties'] ?? []];
105✔
281
        unset($defaults['extra_properties']);
105✔
282

283
        $rc = new \ReflectionClass(ApiResource::class);
105✔
284
        $publicProperties = [];
105✔
285
        foreach ($rc->getConstructor()->getParameters() as $param) {
105✔
286
            $publicProperties[$param->getName()] = true;
105✔
287
        }
288

289
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
105✔
290
        foreach ($defaults as $option => $value) {
105✔
291
            if (isset($publicProperties[$nameConverter->denormalize($option)])) {
105✔
292
                $normalizedDefaults[$option] = $value;
99✔
293

294
                continue;
99✔
295
            }
296

297
            $normalizedDefaults['extra_properties'][$option] = $value;
6✔
298
        }
299

300
        return $normalizedDefaults;
105✔
301
    }
302

303
    private function registerMetadataConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
304
    {
305
        [$xmlResources, $yamlResources] = $this->getResourcesToWatch($container, $config);
105✔
306

307
        $container->setParameter('api_platform.class_name_resources', $this->getClassNameResources());
105✔
308

309
        $loader->load('metadata/resource_name.xml');
105✔
310
        $loader->load('metadata/property_name.xml');
105✔
311

312
        if (!empty($config['resource_class_directories'])) {
105✔
313
            $container->setParameter('api_platform.resource_class_directories', array_merge(
×
314
                $config['resource_class_directories'],
×
315
                $container->getParameter('api_platform.resource_class_directories')
×
316
            ));
×
317
        }
318

319
        // V3 metadata
320
        $loader->load('metadata/xml.xml');
105✔
321
        $loader->load('metadata/links.xml');
105✔
322
        $loader->load('metadata/property.xml');
105✔
323
        $loader->load('metadata/resource.xml');
105✔
324
        $loader->load('metadata/operation.xml');
105✔
325

326
        $container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
105✔
327
        $container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
105✔
328

329
        if (class_exists(PhpDocParser::class) || interface_exists(DocBlockFactoryInterface::class)) {
105✔
330
            $loader->load('metadata/php_doc.xml');
105✔
331
        }
332

333
        if (class_exists(Yaml::class)) {
105✔
334
            $loader->load('metadata/yaml.xml');
105✔
335
            $container->getDefinition('api_platform.metadata.resource_extractor.yaml')->replaceArgument(0, $yamlResources);
105✔
336
            $container->getDefinition('api_platform.metadata.property_extractor.yaml')->replaceArgument(0, $yamlResources);
105✔
337
        }
338
    }
339

340
    private function getClassNameResources(): array
341
    {
342
        return [
105✔
343
            Error::class,
105✔
344
            ValidationException::class,
105✔
345
        ];
105✔
346
    }
347

348
    private function getBundlesResourcesPaths(ContainerBuilder $container, array $config): array
349
    {
350
        $bundlesResourcesPaths = [];
105✔
351

352
        foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
105✔
353
            $dirname = $bundle['path'];
105✔
354
            $paths = [
105✔
355
                "$dirname/ApiResource",
105✔
356
                "$dirname/src/ApiResource",
105✔
357
            ];
105✔
358
            foreach (['.yaml', '.yml', '.xml', ''] as $extension) {
105✔
359
                $paths[] = "$dirname/Resources/config/api_resources$extension";
105✔
360
                $paths[] = "$dirname/config/api_resources$extension";
105✔
361
            }
362
            if ($this->isConfigEnabled($container, $config['doctrine'])) {
105✔
363
                $paths[] = "$dirname/Entity";
105✔
364
                $paths[] = "$dirname/src/Entity";
105✔
365
            }
366
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
105✔
367
                $paths[] = "$dirname/Document";
102✔
368
                $paths[] = "$dirname/src/Document";
102✔
369
            }
370

371
            foreach ($paths as $path) {
105✔
372
                if ($container->fileExists($path, false)) {
105✔
373
                    $bundlesResourcesPaths[] = $path;
105✔
374
                }
375
            }
376
        }
377

378
        return $bundlesResourcesPaths;
105✔
379
    }
380

381
    private function getResourcesToWatch(ContainerBuilder $container, array $config): array
382
    {
383
        $paths = array_unique(array_merge($this->getBundlesResourcesPaths($container, $config), $config['mapping']['paths']));
105✔
384

385
        if (!$config['mapping']['paths']) {
105✔
386
            $projectDir = $container->getParameter('kernel.project_dir');
102✔
387
            foreach (["$projectDir/config/api_platform", "$projectDir/src/ApiResource"] as $dir) {
102✔
388
                if (is_dir($dir)) {
102✔
389
                    $paths[] = $dir;
102✔
390
                }
391
            }
392

393
            if ($this->isConfigEnabled($container, $config['doctrine']) && is_dir($doctrinePath = "$projectDir/src/Entity")) {
102✔
394
                $paths[] = $doctrinePath;
×
395
            }
396

397
            if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm']) && is_dir($documentPath = "$projectDir/src/Document")) {
102✔
398
                $paths[] = $documentPath;
×
399
            }
400
        }
401

402
        $resources = ['yml' => [], 'xml' => [], 'dir' => []];
105✔
403

404
        foreach ($paths as $path) {
105✔
405
            if (is_dir($path)) {
105✔
406
                foreach (Finder::create()->followLinks()->files()->in($path)->name('/\.(xml|ya?ml)$/')->sortByName() as $file) {
105✔
407
                    $resources['yaml' === ($extension = $file->getExtension()) ? 'yml' : $extension][] = $file->getRealPath();
105✔
408
                }
409

410
                $resources['dir'][] = $path;
105✔
411
                $container->addResource(new DirectoryResource($path, '/\.(xml|ya?ml|php)$/'));
105✔
412

413
                continue;
105✔
414
            }
415

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

421
                $resources['yaml' === $matches[1] ? 'yml' : $matches[1]][] = $path;
×
422

423
                continue;
×
424
            }
425

426
            throw new RuntimeException(sprintf('Could not open file or directory "%s".', $path));
×
427
        }
428

429
        $container->setParameter('api_platform.resource_class_directories', $resources['dir']);
105✔
430

431
        return [$resources['xml'], $resources['yml']];
105✔
432
    }
433

434
    private function registerOAuthConfiguration(ContainerBuilder $container, array $config): void
435
    {
436
        if (!$config['oauth']) {
105✔
437
            return;
×
438
        }
439

440
        $container->setParameter('api_platform.oauth.enabled', $this->isConfigEnabled($container, $config['oauth']));
105✔
441
        $container->setParameter('api_platform.oauth.clientId', $config['oauth']['clientId']);
105✔
442
        $container->setParameter('api_platform.oauth.clientSecret', $config['oauth']['clientSecret']);
105✔
443
        $container->setParameter('api_platform.oauth.type', $config['oauth']['type']);
105✔
444
        $container->setParameter('api_platform.oauth.flow', $config['oauth']['flow']);
105✔
445
        $container->setParameter('api_platform.oauth.tokenUrl', $config['oauth']['tokenUrl']);
105✔
446
        $container->setParameter('api_platform.oauth.authorizationUrl', $config['oauth']['authorizationUrl']);
105✔
447
        $container->setParameter('api_platform.oauth.refreshUrl', $config['oauth']['refreshUrl']);
105✔
448
        $container->setParameter('api_platform.oauth.scopes', $config['oauth']['scopes']);
105✔
449
        $container->setParameter('api_platform.oauth.pkce', $config['oauth']['pkce']);
105✔
450

451
        if ($container->hasDefinition('api_platform.swagger_ui.action')) {
105✔
452
            $container->getDefinition('api_platform.swagger_ui.action')->setArgument(10, $config['oauth']['pkce']);
×
453
        }
454
    }
455

456
    /**
457
     * Registers the Swagger, ReDoc and Swagger UI configuration.
458
     */
459
    private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
460
    {
461
        foreach (array_keys($config['swagger']['api_keys']) as $keyName) {
105✔
462
            if (!preg_match('/^[a-zA-Z0-9._-]+$/', $keyName)) {
3✔
463
                trigger_deprecation('api-platform/core', '3.1', sprintf('The swagger api_keys key "%s" is not valid with OpenAPI 3.1 it should match "^[a-zA-Z0-9._-]+$"', $keyName));
×
464
            }
465
        }
466

467
        $container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
105✔
468

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

473
        if (!$config['enable_swagger']) {
105✔
474
            return;
×
475
        }
476

477
        $loader->load('openapi.xml');
105✔
478
        $loader->load('swagger_ui.xml');
105✔
479

480
        $loader->load('legacy/swagger_ui.xml');
105✔
481

482
        if (!$config['enable_swagger_ui'] && !$config['enable_re_doc']) {
105✔
483
            // Remove the listener but keep the controller to allow customizing the path of the UI
484
            $container->removeDefinition('api_platform.swagger.listener.ui');
×
485
        }
486

487
        $container->setParameter('api_platform.enable_swagger_ui', $config['enable_swagger_ui']);
105✔
488
        $container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
105✔
489
        $container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
105✔
490
        if ($config['openapi']['swagger_ui_extra_configuration'] && $config['swagger']['swagger_ui_extra_configuration']) {
105✔
491
            throw new RuntimeException('You can not set "swagger_ui_extra_configuration" twice - in "openapi" and "swagger" section.');
×
492
        }
493
        $container->setParameter('api_platform.swagger_ui.extra_configuration', $config['openapi']['swagger_ui_extra_configuration'] ?: $config['swagger']['swagger_ui_extra_configuration']);
105✔
494
    }
495

496
    private function registerJsonApiConfiguration(array $formats, XmlFileLoader $loader, array $config): void
497
    {
498
        if (!isset($formats['jsonapi'])) {
105✔
499
            return;
99✔
500
        }
501

502
        $loader->load('jsonapi.xml');
6✔
503
        $loader->load('legacy/jsonapi.xml');
6✔
504
    }
505

506
    private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, XmlFileLoader $loader, array $config): void
507
    {
508
        if (!isset($formats['jsonld'])) {
105✔
509
            return;
×
510
        }
511

512
        $loader->load('jsonld.xml');
105✔
513
        $loader->load('legacy/hydra.xml');
105✔
514
        $loader->load('hydra.xml');
105✔
515

516
        if (!$container->has('api_platform.json_schema.schema_factory')) {
105✔
517
            $container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
×
518
        }
519

520
        if (!$config['enable_docs']) {
105✔
521
            $container->removeDefinition('api_platform.hydra.listener.response.add_link_header');
×
522
        }
523
    }
524

525
    private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader): void
526
    {
527
        if (!isset($formats['jsonhal'])) {
105✔
528
            return;
×
529
        }
530

531
        $loader->load('hal.xml');
105✔
532
    }
533

534
    private function registerJsonProblemConfiguration(array $errorFormats, XmlFileLoader $loader): void
535
    {
536
        if (!isset($errorFormats['jsonproblem'])) {
105✔
537
            return;
×
538
        }
539

540
        $loader->load('problem.xml');
105✔
541
    }
542

543
    private function registerGraphQlConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
544
    {
545
        $enabled = $this->isConfigEnabled($container, $config['graphql']);
105✔
546

547
        $graphqlIntrospectionEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['introspection']);
105✔
548

549
        $graphiqlEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']);
105✔
550
        $graphqlPlayGroundEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphql_playground']);
105✔
551
        if ($graphqlPlayGroundEnabled) {
105✔
552
            trigger_deprecation('api-platform/core', '3.1', 'GraphQL Playground is deprecated and will be removed in API Platform 4.0. Only GraphiQL will be available in the future. Set api_platform.graphql.graphql_playground to false in the configuration to remove this deprecation.');
×
553
        }
554

555
        $container->setParameter('api_platform.graphql.enabled', $enabled);
105✔
556
        $container->setParameter('api_platform.graphql.introspection.enabled', $graphqlIntrospectionEnabled);
105✔
557
        $container->setParameter('api_platform.graphql.graphiql.enabled', $graphiqlEnabled);
105✔
558
        $container->setParameter('api_platform.graphql.graphql_playground.enabled', $graphqlPlayGroundEnabled);
105✔
559
        $container->setParameter('api_platform.graphql.collection.pagination', $config['graphql']['collection']['pagination']);
105✔
560

561
        if (!$enabled) {
105✔
562
            return;
×
563
        }
564

565
        $container->setParameter('api_platform.graphql.default_ide', $config['graphql']['default_ide']);
105✔
566
        $container->setParameter('api_platform.graphql.nesting_separator', $config['graphql']['nesting_separator']);
105✔
567

568
        $loader->load('graphql.xml');
105✔
569

570
        // @phpstan-ignore-next-line because PHPStan uses the container of the test env cache and in test the parameter kernel.bundles always contains the key TwigBundle
571
        if (!class_exists(Environment::class) || !isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
105✔
572
            if ($graphiqlEnabled || $graphqlPlayGroundEnabled) {
6✔
573
                throw new RuntimeException(sprintf('GraphiQL and GraphQL Playground interfaces depend on Twig. Please activate TwigBundle for the %s environnement or disable GraphiQL and GraphQL Playground.', $container->getParameter('kernel.environment')));
3✔
574
            }
575
            $container->removeDefinition('api_platform.graphql.action.graphiql');
3✔
576
            $container->removeDefinition('api_platform.graphql.action.graphql_playground');
3✔
577
        }
578

579
        $container->registerForAutoconfiguration(QueryItemResolverInterface::class)
102✔
580
            ->addTag('api_platform.graphql.resolver');
102✔
581
        $container->registerForAutoconfiguration(QueryCollectionResolverInterface::class)
102✔
582
            ->addTag('api_platform.graphql.resolver');
102✔
583
        $container->registerForAutoconfiguration(MutationResolverInterface::class)
102✔
584
            ->addTag('api_platform.graphql.resolver');
102✔
585
        $container->registerForAutoconfiguration(GraphQlTypeInterface::class)
102✔
586
            ->addTag('api_platform.graphql.type');
102✔
587
        $container->registerForAutoconfiguration(ErrorHandlerInterface::class)
102✔
588
            ->addTag('api_platform.graphql.error_handler');
102✔
589

590
        /* TODO: remove these in 4.x only one resolver factory is used and we're using providers/processors */
591
        if ($config['event_listeners_backward_compatibility_layer'] ?? true) {
102✔
592
            // @TODO: API Platform 3.3 trigger_deprecation('api-platform/core', '3.3', 'In API Platform 4 only one factory "api_platform.graphql.resolver.factory.item" will remain. Stages are deprecated in favor of using a provider/processor.');
593
            // + deprecate every service from legacy/graphql.xml
594
            $loader->load('legacy/graphql.xml');
100✔
595

596
            if (!$container->getParameter('kernel.debug')) {
100✔
597
                return;
90✔
598
            }
599

600
            $requestStack = new Reference('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE);
10✔
601
            $collectionDataCollectorResolverFactory = (new Definition(DataCollectorResolverFactory::class))
10✔
602
                ->setDecoratedService('api_platform.graphql.resolver.factory.collection')
10✔
603
                ->setArguments([new Reference('api_platform.graphql.data_collector.resolver.factory.collection.inner'), $requestStack]);
10✔
604

605
            $itemDataCollectorResolverFactory = (new Definition(DataCollectorResolverFactory::class))
10✔
606
                ->setDecoratedService('api_platform.graphql.resolver.factory.item')
10✔
607
                ->setArguments([new Reference('api_platform.graphql.data_collector.resolver.factory.item.inner'), $requestStack]);
10✔
608

609
            $itemMutationDataCollectorResolverFactory = (new Definition(DataCollectorResolverFactory::class))
10✔
610
                ->setDecoratedService('api_platform.graphql.resolver.factory.item_mutation')
10✔
611
                ->setArguments([new Reference('api_platform.graphql.data_collector.resolver.factory.item_mutation.inner'), $requestStack]);
10✔
612

613
            $itemSubscriptionDataCollectorResolverFactory = (new Definition(DataCollectorResolverFactory::class))
10✔
614
                ->setDecoratedService('api_platform.graphql.resolver.factory.item_subscription')
10✔
615
                ->setArguments([new Reference('api_platform.graphql.data_collector.resolver.factory.item_subscription.inner'), $requestStack]);
10✔
616

617
            $container->addDefinitions([
10✔
618
                'api_platform.graphql.data_collector.resolver.factory.collection' => $collectionDataCollectorResolverFactory,
10✔
619
                'api_platform.graphql.data_collector.resolver.factory.item' => $itemDataCollectorResolverFactory,
10✔
620
                'api_platform.graphql.data_collector.resolver.factory.item_mutation' => $itemMutationDataCollectorResolverFactory,
10✔
621
                'api_platform.graphql.data_collector.resolver.factory.item_subscription' => $itemSubscriptionDataCollectorResolverFactory,
10✔
622
            ]);
10✔
623
        }
624
    }
625

626
    private function registerCacheConfiguration(ContainerBuilder $container): void
627
    {
628
        if (!$container->hasParameter('kernel.debug') || !$container->getParameter('kernel.debug')) {
102✔
629
            $container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
90✔
630
        }
631
    }
632

633
    private function registerDoctrineOrmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
634
    {
635
        if (!$this->isConfigEnabled($container, $config['doctrine'])) {
102✔
636
            return;
×
637
        }
638

639
        // For older versions of doctrine bridge this allows autoconfiguration for filters
640
        if (!$container->has(ManagerRegistry::class)) {
102✔
641
            $container->setAlias(ManagerRegistry::class, 'doctrine');
102✔
642
        }
643

644
        $container->registerForAutoconfiguration(QueryItemExtensionInterface::class)
102✔
645
            ->addTag('api_platform.doctrine.orm.query_extension.item');
102✔
646
        $container->registerForAutoconfiguration(DoctrineQueryCollectionExtensionInterface::class)
102✔
647
            ->addTag('api_platform.doctrine.orm.query_extension.collection');
102✔
648
        $container->registerForAutoconfiguration(DoctrineOrmAbstractFilter::class);
102✔
649

650
        $container->registerForAutoconfiguration(OrmLinksHandlerInterface::class)
102✔
651
            ->addTag('api_platform.doctrine.orm.links_handler');
102✔
652

653
        $loader->load('doctrine_orm.xml');
102✔
654

655
        if ($this->isConfigEnabled($container, $config['eager_loading'])) {
102✔
656
            return;
102✔
657
        }
658

659
        $container->removeAlias(EagerLoadingExtension::class);
×
660
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading');
×
661
        $container->removeAlias(FilterEagerLoadingExtension::class);
×
662
        $container->removeDefinition('api_platform.doctrine.orm.query_extension.filter_eager_loading');
×
663
    }
664

665
    private function registerDoctrineMongoDbOdmConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
666
    {
667
        if (!$this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
102✔
668
            return;
3✔
669
        }
670

671
        $container->registerForAutoconfiguration(AggregationItemExtensionInterface::class)
99✔
672
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.item');
99✔
673
        $container->registerForAutoconfiguration(AggregationCollectionExtensionInterface::class)
99✔
674
            ->addTag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection');
99✔
675
        $container->registerForAutoconfiguration(DoctrineMongoDbOdmAbstractFilter::class)
99✔
676
            ->setBindings(['$managerRegistry' => new Reference('doctrine_mongodb')]);
99✔
677
        $container->registerForAutoconfiguration(OdmLinksHandlerInterface::class)
99✔
678
            ->addTag('api_platform.doctrine.odm.links_handler');
99✔
679

680
        $loader->load('doctrine_mongodb_odm.xml');
99✔
681
    }
682

683
    private function registerHttpCacheConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
684
    {
685
        $loader->load('http_cache.xml');
102✔
686
        $loader->load('legacy/http_cache.xml');
102✔
687

688
        if (!$this->isConfigEnabled($container, $config['http_cache']['invalidation'])) {
102✔
689
            return;
×
690
        }
691

692
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
102✔
693
            $loader->load('doctrine_orm_http_cache_purger.xml');
102✔
694
        }
695

696
        $loader->load('http_cache_purger.xml');
102✔
697
        $loader->load('legacy/http_cache_purger.xml');
102✔
698

699
        foreach ($config['http_cache']['invalidation']['scoped_clients'] as $client) {
102✔
700
            $definition = $container->getDefinition($client);
3✔
701
            $definition->addTag('api_platform.http_cache.http_client');
3✔
702
        }
703

704
        if (!($urls = $config['http_cache']['invalidation']['urls'])) {
102✔
705
            $urls = $config['http_cache']['invalidation']['varnish_urls'];
99✔
706
        }
707

708
        foreach ($urls as $key => $url) {
102✔
709
            $definition = new Definition(ScopingHttpClient::class, [new Reference('http_client'), $url, ['base_uri' => $url] + $config['http_cache']['invalidation']['request_options']]);
6✔
710
            $definition->setFactory([ScopingHttpClient::class, 'forBaseUri']);
6✔
711
            $definition->addTag('api_platform.http_cache.http_client');
6✔
712
            $container->setDefinition('api_platform.invalidation_http_client.'.$key, $definition);
6✔
713
        }
714

715
        $serviceName = $config['http_cache']['invalidation']['purger'];
102✔
716

717
        if (!$container->hasDefinition('api_platform.http_cache.purger')) {
102✔
718
            $container->setAlias('api_platform.http_cache.purger', $serviceName);
102✔
719
        }
720
    }
721

722
    /**
723
     * Normalizes the format from config to the one accepted by Symfony HttpFoundation.
724
     */
725
    private function getFormats(array $configFormats): array
726
    {
727
        $formats = [];
105✔
728
        foreach ($configFormats as $format => $value) {
105✔
729
            foreach ($value['mime_types'] as $mimeType) {
105✔
730
                $formats[$format][] = $mimeType;
105✔
731
            }
732
        }
733

734
        return $formats;
105✔
735
    }
736

737
    private function registerValidatorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
738
    {
739
        if (interface_exists(ValidatorInterface::class)) {
102✔
740
            $loader->load('metadata/validator.xml');
102✔
741
            $loader->load('symfony/validator.xml');
102✔
742

743
            if ($this->isConfigEnabled($container, $config['graphql'])) {
102✔
744
                $loader->load('graphql/validator.xml');
102✔
745
            }
746

747
            $container->registerForAutoconfiguration(ValidationGroupsGeneratorInterface::class)
102✔
748
                ->addTag('api_platform.validation_groups_generator');
102✔
749
            $container->registerForAutoconfiguration(PropertySchemaRestrictionMetadataInterface::class)
102✔
750
                ->addTag('api_platform.metadata.property_schema_restriction');
102✔
751

752
            $loader->load('legacy/validator.xml');
102✔
753
        }
754

755
        if (!$config['validator']) {
102✔
756
            return;
×
757
        }
758

759
        $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']);
102✔
760
        $container->setParameter('api_platform.validator.query_parameter_validation', $config['validator']['query_parameter_validation']);
102✔
761

762
        if (!$config['validator']['query_parameter_validation']) {
102✔
763
            $container->removeDefinition('api_platform.listener.view.validate_query_parameters');
×
764
            $container->removeDefinition('api_platform.validator.query_parameter_validator');
×
765
        }
766
    }
767

768
    private function registerDataCollectorConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
769
    {
770
        if (!$config['enable_profiler']) {
102✔
771
            return;
×
772
        }
773

774
        $loader->load('data_collector.xml');
102✔
775

776
        if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
102✔
777
            $loader->load('debug.xml');
12✔
778
        }
779
    }
780

781
    private function registerMercureConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
782
    {
783
        if (!$this->isConfigEnabled($container, $config['mercure'])) {
102✔
784
            return;
×
785
        }
786

787
        $container->setParameter('api_platform.mercure.include_type', $config['mercure']['include_type']);
102✔
788

789
        $loader->load('legacy/mercure.xml');
102✔
790
        $loader->load('mercure.xml');
102✔
791

792
        if ($this->isConfigEnabled($container, $config['doctrine'])) {
102✔
793
            $loader->load('doctrine_orm_mercure_publisher.xml');
102✔
794
        }
795
        if ($this->isConfigEnabled($container, $config['doctrine_mongodb_odm'])) {
102✔
796
            $loader->load('doctrine_odm_mercure_publisher.xml');
99✔
797
        }
798

799
        if ($this->isConfigEnabled($container, $config['graphql'])) {
102✔
800
            $loader->load('graphql_mercure.xml');
102✔
801
        }
802
    }
803

804
    private function registerMessengerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
805
    {
806
        if (!$this->isConfigEnabled($container, $config['messenger'])) {
102✔
807
            return;
×
808
        }
809

810
        $loader->load('messenger.xml');
102✔
811
    }
812

813
    private function registerElasticsearchConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
814
    {
815
        $enabled = $this->isConfigEnabled($container, $config['elasticsearch']);
102✔
816

817
        $container->setParameter('api_platform.elasticsearch.enabled', $enabled);
102✔
818

819
        if (!$enabled) {
102✔
820
            return;
99✔
821
        }
822

823
        $clientClass = class_exists(\Elasticsearch\Client::class) ? \Elasticsearch\Client::class : \Elastic\Elasticsearch\Client::class;
3✔
824

825
        $clientDefinition = new Definition($clientClass);
3✔
826
        $container->setDefinition('api_platform.elasticsearch.client', $clientDefinition);
3✔
827
        $container->registerForAutoconfiguration(RequestBodySearchCollectionExtensionInterface::class)
3✔
828
            ->addTag('api_platform.elasticsearch.request_body_search_extension.collection');
3✔
829
        $container->setParameter('api_platform.elasticsearch.hosts', $config['elasticsearch']['hosts']);
3✔
830
        $loader->load('elasticsearch.xml');
3✔
831

832
        // @phpstan-ignore-next-line
833
        if (\Elasticsearch\Client::class === $clientClass) {
3✔
834
            $loader->load('legacy/elasticsearch.xml');
×
835
            $container->setParameter('api_platform.elasticsearch.mapping', $config['elasticsearch']['mapping']);
×
836
            $container->setDefinition('api_platform.elasticsearch.client_for_metadata', $clientDefinition);
×
837
        }
838
    }
839

840
    private function registerSecurityConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
841
    {
842
        /** @var string[] $bundles */
843
        $bundles = $container->getParameter('kernel.bundles');
102✔
844

845
        if (!isset($bundles['SecurityBundle'])) {
102✔
846
            return;
×
847
        }
848

849
        $loader->load('security.xml');
102✔
850
        $loader->load('legacy/security.xml');
102✔
851

852
        if (interface_exists(ValidatorInterface::class)) {
102✔
853
            $loader->load('symfony/security_validator.xml');
102✔
854
        }
855

856
        if ($this->isConfigEnabled($container, $config['graphql'])) {
102✔
857
            $loader->load('graphql/security.xml');
102✔
858
        }
859
    }
860

861
    private function registerOpenApiConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
862
    {
863
        $container->setParameter('api_platform.openapi.termsOfService', $config['openapi']['termsOfService']);
105✔
864
        $container->setParameter('api_platform.openapi.contact.name', $config['openapi']['contact']['name']);
105✔
865
        $container->setParameter('api_platform.openapi.contact.url', $config['openapi']['contact']['url']);
105✔
866
        $container->setParameter('api_platform.openapi.contact.email', $config['openapi']['contact']['email']);
105✔
867
        $container->setParameter('api_platform.openapi.license.name', $config['openapi']['license']['name']);
105✔
868
        $container->setParameter('api_platform.openapi.license.url', $config['openapi']['license']['url']);
105✔
869

870
        $loader->load('json_schema.xml');
105✔
871
    }
872

873
    private function registerMakerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
874
    {
875
        if (!$this->isConfigEnabled($container, $config['maker'])) {
102✔
876
            return;
×
877
        }
878

879
        $loader->load('maker.xml');
102✔
880
    }
881

882
    private function registerArgumentResolverConfiguration(XmlFileLoader $loader): void
883
    {
884
        $loader->load('argument_resolver.xml');
102✔
885
    }
886

887
    private function registerInflectorConfiguration(array $config): void
888
    {
889
        if ($config['keep_legacy_inflector']) {
102✔
890
            Inflector::keepLegacyInflector(true);
×
891
            trigger_deprecation('api-platform/core', '3.2', 'Using doctrine/inflector is deprecated since API Platform 3.2 and will be removed in API Platform 4. Use symfony/string instead. Run "composer require symfony/string" and set "keep_legacy_inflector" to false in config.');
×
892
        } else {
893
            Inflector::keepLegacyInflector(false);
102✔
894
        }
895
    }
896
}
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