Configuration   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 520
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 419
dl 0
loc 520
rs 9.36
c 0
b 0
f 0
wmc 38

13 Methods

Rating   Name   Duplication   Size   Complexity  
A addDoctrineMongoDbOdmSection() 0 8 2
A addOAuthSection() 0 20 1
B addExceptionToStatusSection() 0 47 7
B addGraphQlSection() 0 27 6
A addDoctrineOrmSection() 0 8 3
A addMessengerSection() 0 8 3
A addMercureSection() 0 14 2
A addElasticsearchSection() 0 39 2
A addFormatSection() 0 30 3
A addSwaggerSection() 0 49 3
A addHttpCacheSection() 0 52 1
A addDefaultsSection() 0 21 3
B getConfigTreeBuilder() 0 165 2
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
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\Core\Bridge\Symfony\Bundle\DependencyInjection;
15
16
use ApiPlatform\Core\Annotation\ApiResource;
17
use ApiPlatform\Core\Bridge\Elasticsearch\Metadata\Document\DocumentMetadata;
18
use ApiPlatform\Core\Exception\FilterValidationException;
19
use ApiPlatform\Core\Exception\InvalidArgumentException;
20
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
21
use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
22
use Doctrine\ORM\OptimisticLockException;
23
use Doctrine\ORM\Version as DoctrineOrmVersion;
24
use Elasticsearch\Client as ElasticsearchClient;
25
use FOS\UserBundle\FOSUserBundle;
26
use GraphQL\GraphQL;
27
use Symfony\Bundle\FullStack;
0 ignored issues
show
Bug introduced by
The type Symfony\Bundle\FullStack was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use Symfony\Bundle\MercureBundle\MercureBundle;
29
use Symfony\Bundle\TwigBundle\TwigBundle;
30
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
31
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
32
use Symfony\Component\Config\Definition\ConfigurationInterface;
33
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
34
use Symfony\Component\HttpFoundation\Response;
35
use Symfony\Component\Messenger\MessageBusInterface;
36
use Symfony\Component\Serializer\Exception\ExceptionInterface as SerializerExceptionInterface;
37
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
38
39
/**
40
 * The configuration of the bundle.
41
 *
42
 * @author Kévin Dunglas <[email protected]>
43
 * @author Baptiste Meyer <[email protected]>
44
 */
45
final class Configuration implements ConfigurationInterface
46
{
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function getConfigTreeBuilder()
51
    {
52
        if (method_exists(TreeBuilder::class, 'getRootNode')) {
53
            $treeBuilder = new TreeBuilder('api_platform');
54
            $rootNode = $treeBuilder->getRootNode();
55
        } else {
56
            $treeBuilder = new TreeBuilder();
57
            $rootNode = $treeBuilder->root('api_platform');
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Component\Config...der\TreeBuilder::root() has been deprecated: since Symfony 4.3, pass the root name to the constructor instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

57
            $rootNode = /** @scrutinizer ignore-deprecated */ $treeBuilder->root('api_platform');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
58
        }
59
60
        $rootNode
61
            ->beforeNormalization()
62
                ->ifTrue(static function ($v) {
63
                    return false === ($v['enable_swagger'] ?? null);
64
                })
65
                ->then(static function ($v) {
66
                    $v['swagger']['versions'] = [];
67
68
                    return $v;
69
                })
70
            ->end()
71
            ->children()
72
                ->scalarNode('title')
73
                    ->info('The title of the API.')
74
                    ->cannotBeEmpty()
75
                    ->defaultValue('')
76
                ->end()
77
                ->scalarNode('description')
78
                    ->info('The description of the API.')
79
                    ->cannotBeEmpty()
80
                    ->defaultValue('')
81
                ->end()
82
                ->scalarNode('version')
83
                    ->info('The version of the API.')
84
                    ->cannotBeEmpty()
85
                    ->defaultValue('0.0.0')
86
                ->end()
87
                ->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end()
88
                ->scalarNode('default_operation_path_resolver')
89
                    ->defaultValue('api_platform.operation_path_resolver.underscore')
90
                    ->setDeprecated('The use of the `default_operation_path_resolver` has been deprecated in 2.1 and will be removed in 3.0. Use `path_segment_name_generator` instead.')
91
                    ->info('Specify the default operation path resolver to use for generating resources operations path.')
92
                ->end()
93
                ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
94
                ->scalarNode('path_segment_name_generator')->defaultValue('api_platform.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()
95
                ->booleanNode('allow_plain_identifiers')->defaultFalse()->info('Allow plain identifiers, for example "id" instead of "@id" when denormalizing a relation.')->end()
96
                ->arrayNode('validator')
97
                    ->addDefaultsIfNotSet()
98
                    ->children()
99
                        ->variableNode('serialize_payload_fields')->defaultValue([])->info('Enable the serialization of payload fields when a validation error is thrown.')->end()
100
                    ->end()
101
                ->end()
102
                ->arrayNode('eager_loading')
103
                    ->canBeDisabled()
104
                    ->addDefaultsIfNotSet()
105
                    ->children()
106
                        ->booleanNode('fetch_partial')->defaultFalse()->info('Fetch only partial data according to serialization groups. If enabled, Doctrine ORM entities will not work as expected if any of the other fields are used.')->end()
107
                        ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
108
                        ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
109
                    ->end()
110
                ->end()
111
                ->booleanNode('enable_fos_user')->defaultValue(class_exists(FOSUserBundle::class))->info('Enable the FOSUserBundle integration.')->end()
112
                ->booleanNode('enable_nelmio_api_doc')
113
                    ->defaultFalse()
114
                    ->setDeprecated('Enabling the NelmioApiDocBundle integration has been deprecated in 2.2 and will be removed in 3.0. NelmioApiDocBundle 3 has native support for API Platform.')
115
                    ->info('Enable the NelmioApiDocBundle integration.')
116
                ->end()
117
                ->booleanNode('enable_swagger')->defaultTrue()->info('Enable the Swagger documentation and export.')->end()
118
                ->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger UI')->end()
119
                ->booleanNode('enable_re_doc')->defaultValue(class_exists(TwigBundle::class))->info('Enable ReDoc')->end()
120
                ->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
121
                ->booleanNode('enable_docs')->defaultTrue()->info('Enable the docs')->end()
122
                ->booleanNode('enable_profiler')->defaultTrue()->info('Enable the data collector and the WebProfilerBundle integration.')->end()
123
                ->arrayNode('collection')
124
                    ->addDefaultsIfNotSet()
125
                    ->children()
126
                        ->scalarNode('exists_parameter_name')->defaultValue('exists')->cannotBeEmpty()->info('The name of the query parameter to filter on nullable field values.')->end()
127
                        ->scalarNode('order')->defaultValue('ASC')->info('The default order of results.')->end() // Default ORDER is required for postgresql and mysql >= 5.7 when using LIMIT/OFFSET request
128
                        ->scalarNode('order_parameter_name')->defaultValue('order')->cannotBeEmpty()->info('The name of the query parameter to order results.')->end()
129
                        ->arrayNode('pagination')
130
                            ->canBeDisabled()
131
                            ->addDefaultsIfNotSet()
132
                            ->children()
133
                                ->booleanNode('enabled')
134
                                    ->setDeprecated('The use of the `collection.pagination.enabled` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_enabled` instead.')
135
                                    ->defaultTrue()
136
                                    ->info('To enable or disable pagination for all resource collections by default.')
137
                                ->end()
138
                                ->booleanNode('partial')
139
                                    ->setDeprecated('The use of the `collection.pagination.partial` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_partial` instead.')
140
                                    ->defaultFalse()
141
                                    ->info('To enable or disable partial pagination for all resource collections by default when pagination is enabled.')
142
                                ->end()
143
                                ->booleanNode('client_enabled')
144
                                    ->setDeprecated('The use of the `collection.pagination.client_enabled` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_client_enabled` instead.')
145
                                    ->defaultFalse()
146
                                    ->info('To allow the client to enable or disable the pagination.')
147
                                ->end()
148
                                ->booleanNode('client_items_per_page')
149
                                    ->setDeprecated('The use of the `collection.pagination.client_items_per_page` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_client_items_per_page` instead.')
150
                                    ->defaultFalse()
151
                                    ->info('To allow the client to set the number of items per page.')
152
                                ->end()
153
                                ->booleanNode('client_partial')
154
                                    ->setDeprecated('The use of the `collection.pagination.client_partial` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_client_partial` instead.')
155
                                    ->defaultFalse()
156
                                    ->info('To allow the client to enable or disable partial pagination.')
157
                                ->end()
158
                                ->integerNode('items_per_page')
159
                                    ->setDeprecated('The use of the `collection.pagination.items_per_page` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_items_per_page` instead.')
160
                                    ->defaultValue(30)
161
                                    ->info('The default number of items per page.')
162
                                ->end()
163
                                ->integerNode('maximum_items_per_page')
164
                                    ->setDeprecated('The use of the `collection.pagination.maximum_items_per_page` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.pagination_maximum_items_per_page` instead.')
165
                                    ->defaultNull()
166
                                    ->info('The maximum number of items per page.')
167
                                ->end()
168
                                ->scalarNode('page_parameter_name')->defaultValue('page')->cannotBeEmpty()->info('The default name of the parameter handling the page number.')->end()
169
                                ->scalarNode('enabled_parameter_name')->defaultValue('pagination')->cannotBeEmpty()->info('The name of the query parameter to enable or disable pagination.')->end()
170
                                ->scalarNode('items_per_page_parameter_name')->defaultValue('itemsPerPage')->cannotBeEmpty()->info('The name of the query parameter to set the number of items per page.')->end()
171
                                ->scalarNode('partial_parameter_name')->defaultValue('partial')->cannotBeEmpty()->info('The name of the query parameter to enable or disable partial pagination.')->end()
172
                            ->end()
173
                        ->end()
174
                    ->end()
175
                ->end()
176
                ->arrayNode('mapping')
177
                    ->addDefaultsIfNotSet()
178
                    ->children()
179
                        ->arrayNode('paths')
180
                            ->prototype('scalar')->end()
181
                        ->end()
182
                    ->end()
183
                ->end()
184
                ->arrayNode('resource_class_directories')
185
                    ->prototype('scalar')->end()
186
                ->end()
187
            ->end();
188
189
        $this->addDoctrineOrmSection($rootNode);
190
        $this->addDoctrineMongoDbOdmSection($rootNode);
191
        $this->addOAuthSection($rootNode);
192
        $this->addGraphQlSection($rootNode);
193
        $this->addSwaggerSection($rootNode);
194
        $this->addHttpCacheSection($rootNode);
195
        $this->addMercureSection($rootNode);
196
        $this->addMessengerSection($rootNode);
197
        $this->addElasticsearchSection($rootNode);
198
199
        $this->addExceptionToStatusSection($rootNode);
200
201
        $this->addFormatSection($rootNode, 'formats', [
202
            'jsonld' => ['mime_types' => ['application/ld+json']],
203
            'json' => ['mime_types' => ['application/json']], // Swagger support
204
            'html' => ['mime_types' => ['text/html']], // Swagger UI support
205
        ]);
206
        $this->addFormatSection($rootNode, 'patch_formats', []);
207
        $this->addFormatSection($rootNode, 'error_formats', [
208
            'jsonproblem' => ['mime_types' => ['application/problem+json']],
209
            'jsonld' => ['mime_types' => ['application/ld+json']],
210
        ]);
211
212
        $this->addDefaultsSection($rootNode);
213
214
        return $treeBuilder;
215
    }
216
217
    private function addDoctrineOrmSection(ArrayNodeDefinition $rootNode): void
218
    {
219
        $rootNode
220
            ->children()
221
                ->arrayNode('doctrine')
222
                    ->{class_exists(DoctrineBundle::class) && class_exists(DoctrineOrmVersion::class) ? 'canBeDisabled' : 'canBeEnabled'}()
223
                ->end()
224
            ->end();
225
    }
226
227
    private function addDoctrineMongoDbOdmSection(ArrayNodeDefinition $rootNode): void
228
    {
229
        $rootNode
230
            ->children()
231
                ->arrayNode('doctrine_mongodb_odm')
232
                    ->{class_exists(DoctrineMongoDBBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
233
                ->end()
234
            ->end();
235
    }
236
237
    private function addOAuthSection(ArrayNodeDefinition $rootNode): void
238
    {
239
        $rootNode
240
            ->children()
241
                ->arrayNode('oauth')
242
                    ->canBeEnabled()
243
                    ->addDefaultsIfNotSet()
244
                    ->children()
245
                        ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
246
                        ->scalarNode('clientSecret')->defaultValue('')->info('The oauth client secret.')->end()
0 ignored issues
show
Bug introduced by
The method scalarNode() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

246
                        ->/** @scrutinizer ignore-call */ scalarNode('clientSecret')->defaultValue('')->info('The oauth client secret.')->end()
Loading history...
247
                        ->scalarNode('type')->defaultValue('oauth2')->info('The oauth client secret.')->end()
248
                        ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
249
                        ->scalarNode('tokenUrl')->defaultValue('/oauth/v2/token')->info('The oauth token url.')->end()
250
                        ->scalarNode('authorizationUrl')->defaultValue('/oauth/v2/auth')->info('The oauth authentication url.')->end()
251
                        ->arrayNode('scopes')
252
                            ->prototype('scalar')->end()
253
                        ->end()
254
                    ->end()
255
                ->end()
256
            ->end();
257
    }
258
259
    private function addGraphQlSection(ArrayNodeDefinition $rootNode): void
260
    {
261
        $rootNode
262
            ->children()
263
                ->arrayNode('graphql')
264
                    ->{class_exists(GraphQL::class) ? 'canBeDisabled' : 'canBeEnabled'}()
265
                    ->addDefaultsIfNotSet()
266
                    ->children()
267
                        ->scalarNode('default_ide')->defaultValue('graphiql')->end()
268
                        ->arrayNode('graphiql')
269
                            ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
270
                        ->end()
271
                        ->arrayNode('graphql_playground')
272
                            ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
273
                        ->end()
274
                        ->scalarNode('nesting_separator')->defaultValue('_')->info('The separator to use to filter nested fields.')->end()
275
                        ->arrayNode('collection')
276
                            ->addDefaultsIfNotSet()
277
                            ->children()
278
                                ->arrayNode('pagination')
279
                                    ->canBeDisabled()
280
                                ->end()
281
                            ->end()
282
                        ->end()
283
                    ->end()
284
                ->end()
285
            ->end();
286
    }
287
288
    private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
289
    {
290
        $defaultVersions = [2, 3];
291
292
        $rootNode
293
            ->children()
294
                ->arrayNode('swagger')
295
                    ->addDefaultsIfNotSet()
296
                    ->children()
297
                        ->arrayNode('versions')
298
                            ->info('The active versions of OpenAPI to be exported or used in the swagger_ui. The first value is the default.')
299
                            ->defaultValue($defaultVersions)
300
                            ->beforeNormalization()
301
                                ->always(static function ($v) {
302
                                    if (!\is_array($v)) {
303
                                        $v = [$v];
304
                                    }
305
306
                                    foreach ($v as &$version) {
307
                                        $version = (int) $version;
308
                                    }
309
310
                                    return $v;
311
                                })
312
                            ->end()
313
                            ->validate()
314
                                ->ifTrue(function ($v) use ($defaultVersions) {
315
                                    return $v !== array_intersect($v, $defaultVersions);
316
                                })
317
                                ->thenInvalid(sprintf('Only the versions %s are supported. Got %s.', implode(' and ', $defaultVersions), '%s'))
318
                            ->end()
319
                            ->prototype('scalar')->end()
0 ignored issues
show
Bug introduced by
The method prototype() does not exist on Symfony\Component\Config...\Builder\NodeDefinition. It seems like you code against a sub-type of Symfony\Component\Config...\Builder\NodeDefinition such as Symfony\Component\Config...der\ArrayNodeDefinition. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

319
                            ->/** @scrutinizer ignore-call */ prototype('scalar')->end()
Loading history...
320
                        ->end()
321
                        ->arrayNode('api_keys')
322
                            ->prototype('array')
323
                                ->children()
324
                                    ->scalarNode('name')
325
                                        ->info('The name of the header or query parameter containing the api key.')
326
                                    ->end()
327
                                    ->enumNode('type')
328
                                        ->info('Whether the api key should be a query parameter or a header.')
329
                                        ->values(['query', 'header'])
330
                                    ->end()
331
                                ->end()
332
                            ->end()
333
                        ->end()
334
                    ->end()
335
                ->end()
336
            ->end();
337
    }
338
339
    private function addHttpCacheSection(ArrayNodeDefinition $rootNode): void
340
    {
341
        $rootNode
342
            ->children()
343
                ->arrayNode('http_cache')
344
                    ->addDefaultsIfNotSet()
345
                    ->children()
346
                        ->booleanNode('etag')
347
                            ->setDeprecated('The use of the `http_cache.etag` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.cache_headers.etag` instead.')
348
                            ->defaultTrue()
349
                            ->info('Automatically generate etags for API responses.')
350
                        ->end()
351
                        ->integerNode('max_age')
0 ignored issues
show
Bug introduced by
The method integerNode() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

351
                        ->/** @scrutinizer ignore-call */ integerNode('max_age')
Loading history...
352
                            ->setDeprecated('The use of the `http_cache.max_age` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.cache_headers.max_age` instead.')
353
                            ->defaultNull()
354
                            ->info('Default value for the response max age.')
355
                        ->end()
356
                        ->integerNode('shared_max_age')
357
                            ->setDeprecated('The use of the `http_cache.shared_max_age` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.cache_headers.shared_max_age` instead.')
358
                            ->defaultNull()
359
                            ->info('Default value for the response shared (proxy) max age.')
360
                        ->end()
361
                        ->arrayNode('vary')
362
                            ->setDeprecated('The use of the `http_cache.vary` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.cache_headers.vary` instead.')
363
                            ->defaultValue(['Accept'])
364
                            ->prototype('scalar')->end()
365
                            ->info('Default values of the "Vary" HTTP header.')
366
                        ->end()
367
                        ->booleanNode('public')->defaultNull()->info('To make all responses public by default.')->end()
368
                        ->arrayNode('invalidation')
369
                            ->setDeprecated('The use of the `http_cache.invalidation` has been deprecated in 2.6 and will be removed in 3.0. Use `defaults.cache_headers.invalidation` instead.')
370
                            ->info('Enable the tags-based cache invalidation system.')
371
                            ->canBeEnabled()
372
                            ->children()
373
                                ->arrayNode('varnish_urls')
374
                                    ->defaultValue([])
375
                                    ->prototype('scalar')->end()
376
                                    ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
377
                                ->end()
378
                                ->variableNode('request_options')
379
                                    ->defaultValue([])
380
                                    ->validate()
381
                                        ->ifTrue(function ($v) { return false === \is_array($v); })
382
                                        ->thenInvalid('The request_options parameter must be an array.')
383
                                    ->end()
384
                                    ->info('To pass options to the client charged with the request.')
385
                                ->end()
386
                            ->end()
387
                        ->end()
388
                    ->end()
389
                ->end()
390
            ->end();
391
    }
392
393
    private function addMercureSection(ArrayNodeDefinition $rootNode): void
394
    {
395
        $rootNode
396
            ->children()
397
                ->arrayNode('mercure')
398
                    ->{class_exists(MercureBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
399
                    ->children()
400
                        ->scalarNode('hub_url')
401
                            ->defaultNull()
402
                            ->info('The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle\'s default hub.')
403
                        ->end()
404
                    ->end()
405
                ->end()
406
            ->end();
407
    }
408
409
    private function addMessengerSection(ArrayNodeDefinition $rootNode): void
410
    {
411
        $rootNode
412
            ->children()
413
                ->arrayNode('messenger')
414
                    ->{!class_exists(FullStack::class) && interface_exists(MessageBusInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
415
                ->end()
416
            ->end();
417
    }
418
419
    private function addElasticsearchSection(ArrayNodeDefinition $rootNode): void
420
    {
421
        $rootNode
422
            ->children()
423
                ->arrayNode('elasticsearch')
424
                    ->canBeEnabled()
425
                    ->addDefaultsIfNotSet()
426
                    ->children()
427
                        ->booleanNode('enabled')
428
                            ->defaultFalse()
429
                            ->validate()
430
                                ->ifTrue()
431
                                ->then(static function (bool $v): bool {
432
                                    if (!class_exists(ElasticsearchClient::class)) {
433
                                        throw new InvalidConfigurationException('The elasticsearch/elasticsearch package is required for Elasticsearch support.');
434
                                    }
435
436
                                    return $v;
437
                                })
438
                            ->end()
439
                        ->end()
440
                        ->arrayNode('hosts')
0 ignored issues
show
Bug introduced by
The method arrayNode() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

440
                        ->/** @scrutinizer ignore-call */ arrayNode('hosts')
Loading history...
441
                            ->beforeNormalization()->castToArray()->end()
442
                            ->defaultValue([])
443
                            ->prototype('scalar')->end()
444
                        ->end()
445
                        ->arrayNode('mapping')
446
                            ->normalizeKeys(false)
447
                            ->useAttributeAsKey('resource_class')
448
                            ->prototype('array')
449
                                ->children()
450
                                    ->scalarNode('index')->defaultNull()->end()
451
                                    ->scalarNode('type')->defaultValue(DocumentMetadata::DEFAULT_TYPE)->end()
452
                                ->end()
453
                            ->end()
454
                        ->end()
455
                    ->end()
456
                ->end()
457
            ->end();
458
    }
459
460
    /**
461
     * @throws InvalidConfigurationException
462
     */
463
    private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode): void
464
    {
465
        $rootNode
466
            ->children()
467
                ->arrayNode('exception_to_status')
468
                    ->defaultValue([
469
                        SerializerExceptionInterface::class => Response::HTTP_BAD_REQUEST,
470
                        InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
471
                        FilterValidationException::class => Response::HTTP_BAD_REQUEST,
472
                        OptimisticLockException::class => Response::HTTP_CONFLICT,
473
                    ])
474
                    ->info('The list of exceptions mapped to their HTTP status code.')
475
                    ->normalizeKeys(false)
476
                    ->useAttributeAsKey('exception_class')
477
                    ->beforeNormalization()
478
                        ->ifArray()
479
                        ->then(function (array $exceptionToStatus) {
480
                            foreach ($exceptionToStatus as &$httpStatusCode) {
481
                                if (\is_int($httpStatusCode)) {
482
                                    continue;
483
                                }
484
485
                                if (\defined($httpStatusCodeConstant = sprintf('%s::%s', Response::class, $httpStatusCode))) {
486
                                    @trigger_error(sprintf('Using a string "%s" as a constant of the "%s" class is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3. Use the Symfony\'s custom YAML extension for PHP constants instead (i.e. "!php/const %s").', $httpStatusCode, Response::class, $httpStatusCodeConstant), E_USER_DEPRECATED);
487
488
                                    $httpStatusCode = \constant($httpStatusCodeConstant);
489
                                }
490
                            }
491
492
                            return $exceptionToStatus;
493
                        })
494
                    ->end()
495
                    ->prototype('integer')->end()
496
                    ->validate()
497
                        ->ifArray()
498
                        ->then(function (array $exceptionToStatus) {
499
                            foreach ($exceptionToStatus as $httpStatusCode) {
500
                                if ($httpStatusCode < 100 || $httpStatusCode >= 600) {
501
                                    throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.', $httpStatusCode));
502
                                }
503
                            }
504
505
                            return $exceptionToStatus;
506
                        })
507
                    ->end()
508
                ->end()
509
            ->end();
510
    }
511
512
    private function addFormatSection(ArrayNodeDefinition $rootNode, string $key, array $defaultValue): void
513
    {
514
        $rootNode
515
            ->children()
516
                ->arrayNode($key)
517
                    ->defaultValue($defaultValue)
518
                    ->info('The list of enabled formats. The first one will be the default.')
519
                    ->normalizeKeys(false)
520
                    ->useAttributeAsKey('format')
521
                    ->beforeNormalization()
522
                        ->ifArray()
523
                        ->then(function ($v) {
524
                            foreach ($v as $format => $value) {
525
                                if (isset($value['mime_types'])) {
526
                                    continue;
527
                                }
528
529
                                $v[$format] = ['mime_types' => $value];
530
                            }
531
532
                            return $v;
533
                        })
534
                    ->end()
535
                    ->prototype('array')
536
                        ->children()
537
                            ->arrayNode('mime_types')->prototype('scalar')->end()->end()
538
                        ->end()
539
                    ->end()
540
                ->end()
541
            ->end();
542
    }
543
544
    private function addDefaultsSection(ArrayNodeDefinition $rootNode): void
545
    {
546
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
547
        $defaultsNode = $rootNode->children()->arrayNode('defaults');
548
549
        $defaultsNode
550
            ->ignoreExtraKeys()
551
            ->beforeNormalization()
552
            ->always(function (array $defaults) use ($nameConverter) {
553
                $normalizedDefaults = [];
554
                foreach ($defaults as $option => $value) {
555
                    $option = $nameConverter->normalize($option);
556
                    $normalizedDefaults[$option] = $value;
557
                }
558
559
                return $normalizedDefaults;
560
            });
561
562
        foreach (ApiResource::CONFIGURABLE_DEFAULTS as $attribute) {
563
            $snakeCased = $nameConverter->normalize($attribute);
564
            $defaultsNode->children()->variableNode($snakeCased);
565
        }
566
    }
567
}
568