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

api-platform / core / 7142557150

08 Dec 2023 02:28PM UTC coverage: 36.003% (-1.4%) from 37.36%
7142557150

push

github

web-flow
fix(jsonld): remove link to ApiDocumentation when doc is disabled (#6029)

0 of 1 new or added line in 1 file covered. (0.0%)

2297 existing lines in 182 files now uncovered.

9992 of 27753 relevant lines covered (36.0%)

147.09 hits per line

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

0.0
/src/Symfony/Bundle/DependencyInjection/Configuration.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\Common\Filter\OrderFilterInterface;
17
use ApiPlatform\Elasticsearch\Metadata\Document\DocumentMetadata;
18
use ApiPlatform\Elasticsearch\State\Options;
19
use ApiPlatform\Exception\FilterValidationException;
20
use ApiPlatform\Exception\InvalidArgumentException;
21
use ApiPlatform\Metadata\ApiResource;
22
use ApiPlatform\Metadata\Post;
23
use ApiPlatform\Metadata\Put;
24
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
25
use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
26
use Doctrine\ORM\EntityManagerInterface;
27
use Doctrine\ORM\OptimisticLockException;
28
use GraphQL\GraphQL;
29
use Symfony\Bundle\FullStack;
30
use Symfony\Bundle\MakerBundle\MakerBundle;
31
use Symfony\Bundle\MercureBundle\MercureBundle;
32
use Symfony\Bundle\TwigBundle\TwigBundle;
33
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
34
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
35
use Symfony\Component\Config\Definition\ConfigurationInterface;
36
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
37
use Symfony\Component\HttpFoundation\Response;
38
use Symfony\Component\Messenger\MessageBusInterface;
39
use Symfony\Component\Serializer\Exception\ExceptionInterface as SerializerExceptionInterface;
40
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
41

42
/**
43
 * The configuration of the bundle.
44
 *
45
 * @author Kévin Dunglas <dunglas@gmail.com>
46
 * @author Baptiste Meyer <baptiste.meyer@gmail.com>
47
 */
48
final class Configuration implements ConfigurationInterface
49
{
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function getConfigTreeBuilder(): TreeBuilder
54
    {
UNCOV
55
        $treeBuilder = new TreeBuilder('api_platform');
×
UNCOV
56
        $rootNode = $treeBuilder->getRootNode();
×
57

UNCOV
58
        $rootNode
×
UNCOV
59
            ->beforeNormalization()
×
UNCOV
60
                ->ifTrue(static function ($v) {
×
UNCOV
61
                    return false === ($v['enable_swagger'] ?? null);
×
UNCOV
62
                })
×
UNCOV
63
                ->then(static function ($v) {
×
UNCOV
64
                    $v['swagger']['versions'] = [];
×
65

UNCOV
66
                    return $v;
×
UNCOV
67
                })
×
UNCOV
68
            ->end()
×
UNCOV
69
            ->children()
×
UNCOV
70
                ->scalarNode('title')
×
UNCOV
71
                    ->info('The title of the API.')
×
UNCOV
72
                    ->cannotBeEmpty()
×
UNCOV
73
                    ->defaultValue('')
×
UNCOV
74
                ->end()
×
UNCOV
75
                ->scalarNode('description')
×
UNCOV
76
                    ->info('The description of the API.')
×
UNCOV
77
                    ->cannotBeEmpty()
×
UNCOV
78
                    ->defaultValue('')
×
UNCOV
79
                ->end()
×
UNCOV
80
                ->scalarNode('version')
×
UNCOV
81
                    ->info('The version of the API.')
×
UNCOV
82
                    ->cannotBeEmpty()
×
UNCOV
83
                    ->defaultValue('0.0.0')
×
UNCOV
84
                ->end()
×
UNCOV
85
                ->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end()
×
UNCOV
86
                ->booleanNode('event_listeners_backward_compatibility_layer')->defaultTrue()->info('If true API Platform uses Symfony event listeners instead of providers and processors.')->end() // TODO: Add link to the documentation
×
UNCOV
87
                ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
×
UNCOV
88
                ->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end()
×
UNCOV
89
                ->scalarNode('path_segment_name_generator')->defaultValue('api_platform.metadata.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()
×
UNCOV
90
                ->arrayNode('validator')
×
UNCOV
91
                    ->addDefaultsIfNotSet()
×
UNCOV
92
                    ->children()
×
UNCOV
93
                        ->variableNode('serialize_payload_fields')->defaultValue([])->info('Set to null to serialize all payload fields when a validation error is thrown, or set the fields you want to include explicitly.')->end()
×
UNCOV
94
                        ->booleanNode('query_parameter_validation')->defaultValue(true)->end()
×
UNCOV
95
                    ->end()
×
UNCOV
96
                ->end()
×
UNCOV
97
                ->arrayNode('eager_loading')
×
UNCOV
98
                    ->canBeDisabled()
×
UNCOV
99
                    ->addDefaultsIfNotSet()
×
UNCOV
100
                    ->children()
×
UNCOV
101
                        ->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()
×
UNCOV
102
                        ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
×
UNCOV
103
                        ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
×
UNCOV
104
                    ->end()
×
UNCOV
105
                ->end()
×
UNCOV
106
                ->booleanNode('enable_swagger')->defaultTrue()->info('Enable the Swagger documentation and export.')->end()
×
UNCOV
107
                ->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger UI')->end()
×
UNCOV
108
                ->booleanNode('enable_re_doc')->defaultValue(class_exists(TwigBundle::class))->info('Enable ReDoc')->end()
×
UNCOV
109
                ->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
×
UNCOV
110
                ->booleanNode('enable_docs')->defaultTrue()->info('Enable the docs')->end()
×
UNCOV
111
                ->booleanNode('enable_profiler')->defaultTrue()->info('Enable the data collector and the WebProfilerBundle integration.')->end()
×
UNCOV
112
                ->booleanNode('keep_legacy_inflector')->defaultTrue()->info('Keep doctrine/inflector instead of symfony/string to generate plurals for routes.')->end()
×
UNCOV
113
                ->arrayNode('collection')
×
UNCOV
114
                    ->addDefaultsIfNotSet()
×
UNCOV
115
                    ->children()
×
UNCOV
116
                        ->scalarNode('exists_parameter_name')->defaultValue('exists')->cannotBeEmpty()->info('The name of the query parameter to filter on nullable field values.')->end()
×
UNCOV
117
                        ->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
×
UNCOV
118
                        ->scalarNode('order_parameter_name')->defaultValue('order')->cannotBeEmpty()->info('The name of the query parameter to order results.')->end()
×
UNCOV
119
                        ->enumNode('order_nulls_comparison')->defaultNull()->values(array_merge(array_keys(OrderFilterInterface::NULLS_DIRECTION_MAP), [null]))->info('The nulls comparison strategy.')->end()
×
UNCOV
120
                        ->arrayNode('pagination')
×
UNCOV
121
                            ->canBeDisabled()
×
UNCOV
122
                            ->addDefaultsIfNotSet()
×
UNCOV
123
                            ->children()
×
UNCOV
124
                                ->scalarNode('page_parameter_name')->defaultValue('page')->cannotBeEmpty()->info('The default name of the parameter handling the page number.')->end()
×
UNCOV
125
                                ->scalarNode('enabled_parameter_name')->defaultValue('pagination')->cannotBeEmpty()->info('The name of the query parameter to enable or disable pagination.')->end()
×
UNCOV
126
                                ->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()
×
UNCOV
127
                                ->scalarNode('partial_parameter_name')->defaultValue('partial')->cannotBeEmpty()->info('The name of the query parameter to enable or disable partial pagination.')->end()
×
UNCOV
128
                            ->end()
×
UNCOV
129
                        ->end()
×
UNCOV
130
                    ->end()
×
UNCOV
131
                ->end()
×
UNCOV
132
                ->arrayNode('mapping')
×
UNCOV
133
                    ->addDefaultsIfNotSet()
×
UNCOV
134
                    ->children()
×
UNCOV
135
                        ->arrayNode('paths')
×
UNCOV
136
                            ->prototype('scalar')->end()
×
UNCOV
137
                        ->end()
×
UNCOV
138
                    ->end()
×
UNCOV
139
                ->end()
×
UNCOV
140
                ->arrayNode('resource_class_directories')
×
UNCOV
141
                    ->prototype('scalar')->end()
×
UNCOV
142
                ->end()
×
UNCOV
143
            ->end();
×
144

UNCOV
145
        $this->addDoctrineOrmSection($rootNode);
×
UNCOV
146
        $this->addDoctrineMongoDbOdmSection($rootNode);
×
UNCOV
147
        $this->addOAuthSection($rootNode);
×
UNCOV
148
        $this->addGraphQlSection($rootNode);
×
UNCOV
149
        $this->addSwaggerSection($rootNode);
×
UNCOV
150
        $this->addHttpCacheSection($rootNode);
×
UNCOV
151
        $this->addMercureSection($rootNode);
×
UNCOV
152
        $this->addMessengerSection($rootNode);
×
UNCOV
153
        $this->addElasticsearchSection($rootNode);
×
UNCOV
154
        $this->addOpenApiSection($rootNode);
×
UNCOV
155
        $this->addMakerSection($rootNode);
×
156

UNCOV
157
        $this->addExceptionToStatusSection($rootNode);
×
158

UNCOV
159
        $this->addFormatSection($rootNode, 'formats', [
×
UNCOV
160
        ]);
×
UNCOV
161
        $this->addFormatSection($rootNode, 'patch_formats', [
×
UNCOV
162
            'json' => ['mime_types' => ['application/merge-patch+json']],
×
UNCOV
163
        ]);
×
UNCOV
164
        $this->addFormatSection($rootNode, 'docs_formats', [
×
UNCOV
165
            'jsonopenapi' => ['mime_types' => ['application/vnd.openapi+json']],
×
UNCOV
166
            'yamlopenapi' => ['mime_types' => ['application/vnd.openapi+yaml']],
×
UNCOV
167
            'json' => ['mime_types' => ['application/json']], // this is only for legacy reasons, use jsonopenapi instead
×
UNCOV
168
            'jsonld' => ['mime_types' => ['application/ld+json']],
×
UNCOV
169
            'html' => ['mime_types' => ['text/html']],
×
UNCOV
170
        ]);
×
UNCOV
171
        $this->addFormatSection($rootNode, 'error_formats', [
×
UNCOV
172
            'jsonld' => ['mime_types' => ['application/ld+json']],
×
UNCOV
173
            'jsonproblem' => ['mime_types' => ['application/problem+json']],
×
UNCOV
174
            'json' => ['mime_types' => ['application/problem+json', 'application/json']],
×
UNCOV
175
        ]);
×
176

UNCOV
177
        $this->addDefaultsSection($rootNode);
×
178

UNCOV
179
        return $treeBuilder;
×
180
    }
181

182
    private function addDoctrineOrmSection(ArrayNodeDefinition $rootNode): void
183
    {
UNCOV
184
        $rootNode
×
UNCOV
185
            ->children()
×
UNCOV
186
                ->arrayNode('doctrine')
×
UNCOV
187
                    ->{class_exists(DoctrineBundle::class) && interface_exists(EntityManagerInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
188
                ->end()
×
UNCOV
189
            ->end();
×
190
    }
191

192
    private function addDoctrineMongoDbOdmSection(ArrayNodeDefinition $rootNode): void
193
    {
UNCOV
194
        $rootNode
×
UNCOV
195
            ->children()
×
UNCOV
196
                ->arrayNode('doctrine_mongodb_odm')
×
UNCOV
197
                    ->{class_exists(DoctrineMongoDBBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
198
                ->end()
×
UNCOV
199
            ->end();
×
200
    }
201

202
    private function addOAuthSection(ArrayNodeDefinition $rootNode): void
203
    {
UNCOV
204
        $rootNode
×
UNCOV
205
            ->children()
×
UNCOV
206
                ->arrayNode('oauth')
×
UNCOV
207
                    ->canBeEnabled()
×
UNCOV
208
                    ->addDefaultsIfNotSet()
×
UNCOV
209
                    ->children()
×
UNCOV
210
                        ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
×
UNCOV
211
                        ->scalarNode('clientSecret')
×
UNCOV
212
                            ->defaultValue('')
×
UNCOV
213
                            ->info('The OAuth client secret. Never use this parameter in your production environment. It exposes crucial security information. This feature is intended for dev/test environments only. Enable "oauth.pkce" instead')
×
UNCOV
214
                        ->end()
×
UNCOV
215
                        ->booleanNode('pkce')->defaultFalse()->info('Enable the oauth PKCE.')->end()
×
UNCOV
216
                        ->scalarNode('type')->defaultValue('oauth2')->info('The oauth type.')->end()
×
UNCOV
217
                        ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
×
UNCOV
218
                        ->scalarNode('tokenUrl')->defaultValue('')->info('The oauth token url.')->end()
×
UNCOV
219
                        ->scalarNode('authorizationUrl')->defaultValue('')->info('The oauth authentication url.')->end()
×
UNCOV
220
                        ->scalarNode('refreshUrl')->defaultValue('')->info('The oauth refresh url.')->end()
×
UNCOV
221
                        ->arrayNode('scopes')
×
UNCOV
222
                            ->prototype('scalar')->end()
×
UNCOV
223
                        ->end()
×
UNCOV
224
                    ->end()
×
UNCOV
225
                ->end()
×
UNCOV
226
            ->end();
×
227
    }
228

229
    private function addGraphQlSection(ArrayNodeDefinition $rootNode): void
230
    {
UNCOV
231
        $rootNode
×
UNCOV
232
            ->children()
×
UNCOV
233
                ->arrayNode('graphql')
×
UNCOV
234
                    ->{class_exists(GraphQL::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
235
                    ->addDefaultsIfNotSet()
×
UNCOV
236
                    ->children()
×
UNCOV
237
                        ->scalarNode('default_ide')->defaultValue('graphiql')->end()
×
UNCOV
238
                        ->arrayNode('graphiql')
×
UNCOV
239
                            ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
240
                        ->end()
×
UNCOV
241
                        ->arrayNode('graphql_playground')
×
UNCOV
242
                            ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
243
                        ->end()
×
UNCOV
244
                        ->arrayNode('introspection')
×
UNCOV
245
                            ->canBeDisabled()
×
UNCOV
246
                        ->end()
×
UNCOV
247
                        ->scalarNode('nesting_separator')->defaultValue('_')->info('The separator to use to filter nested fields.')->end()
×
UNCOV
248
                        ->arrayNode('collection')
×
UNCOV
249
                            ->addDefaultsIfNotSet()
×
UNCOV
250
                            ->children()
×
UNCOV
251
                                ->arrayNode('pagination')
×
UNCOV
252
                                    ->canBeDisabled()
×
UNCOV
253
                                ->end()
×
UNCOV
254
                            ->end()
×
UNCOV
255
                        ->end()
×
UNCOV
256
                    ->end()
×
UNCOV
257
                ->end()
×
UNCOV
258
            ->end();
×
259
    }
260

261
    private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
262
    {
UNCOV
263
        $supportedVersions = [3];
×
264

UNCOV
265
        $rootNode
×
UNCOV
266
            ->children()
×
UNCOV
267
                ->arrayNode('swagger')
×
UNCOV
268
                    ->addDefaultsIfNotSet()
×
UNCOV
269
                    ->children()
×
UNCOV
270
                        ->arrayNode('versions')
×
UNCOV
271
                            ->info('The active versions of OpenAPI to be exported or used in Swagger UI. The first value is the default.')
×
UNCOV
272
                            ->defaultValue($supportedVersions)
×
UNCOV
273
                            ->beforeNormalization()
×
UNCOV
274
                                ->always(static function ($v): array {
×
UNCOV
275
                                    if (!\is_array($v)) {
×
276
                                        $v = [$v];
×
277
                                    }
278

UNCOV
279
                                    foreach ($v as &$version) {
×
UNCOV
280
                                        $version = (int) $version;
×
281
                                    }
282

UNCOV
283
                                    return $v;
×
UNCOV
284
                                })
×
UNCOV
285
                            ->end()
×
UNCOV
286
                            ->validate()
×
UNCOV
287
                                ->ifTrue(static fn($v): bool => $v !== array_intersect($v, $supportedVersions))
×
UNCOV
288
                                ->thenInvalid(sprintf('Only the versions %s are supported. Got %s.', implode(' and ', $supportedVersions), '%s'))
×
UNCOV
289
                            ->end()
×
UNCOV
290
                            ->prototype('scalar')->end()
×
UNCOV
291
                        ->end()
×
UNCOV
292
                        ->arrayNode('api_keys')
×
UNCOV
293
                            ->useAttributeAsKey('key')
×
UNCOV
294
                            ->validate()
×
UNCOV
295
                                ->ifTrue(static fn($v): bool => (bool) array_filter(array_keys($v), fn($item) => !preg_match('/^[a-zA-Z0-9._-]+$/', $item)))
×
UNCOV
296
                                ->thenInvalid('The api keys "key" is not valid according to the pattern enforced by OpenAPI 3.1 ^[a-zA-Z0-9._-]+$.')
×
UNCOV
297
                            ->end()
×
UNCOV
298
                            ->prototype('array')
×
UNCOV
299
                                ->children()
×
UNCOV
300
                                    ->scalarNode('name')
×
UNCOV
301
                                        ->info('The name of the header or query parameter containing the api key.')
×
UNCOV
302
                                    ->end()
×
UNCOV
303
                                    ->enumNode('type')
×
UNCOV
304
                                        ->info('Whether the api key should be a query parameter or a header.')
×
UNCOV
305
                                        ->values(['query', 'header'])
×
UNCOV
306
                                    ->end()
×
UNCOV
307
                                ->end()
×
UNCOV
308
                            ->end()
×
UNCOV
309
                        ->end()
×
UNCOV
310
                        ->variableNode('swagger_ui_extra_configuration')
×
UNCOV
311
                            ->defaultValue([])
×
UNCOV
312
                            ->validate()
×
UNCOV
313
                                ->ifTrue(static fn($v): bool => false === \is_array($v))
×
UNCOV
314
                                ->thenInvalid('The swagger_ui_extra_configuration parameter must be an array.')
×
UNCOV
315
                            ->end()
×
UNCOV
316
                            ->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
×
UNCOV
317
                        ->end()
×
UNCOV
318
                    ->end()
×
UNCOV
319
                ->end()
×
UNCOV
320
            ->end();
×
321
    }
322

323
    private function addHttpCacheSection(ArrayNodeDefinition $rootNode): void
324
    {
UNCOV
325
        $rootNode
×
UNCOV
326
            ->children()
×
UNCOV
327
                ->arrayNode('http_cache')
×
UNCOV
328
                    ->addDefaultsIfNotSet()
×
UNCOV
329
                    ->children()
×
UNCOV
330
                        ->booleanNode('public')->defaultNull()->info('To make all responses public by default.')->end()
×
UNCOV
331
                        ->arrayNode('invalidation')
×
UNCOV
332
                            ->info('Enable the tags-based cache invalidation system.')
×
UNCOV
333
                            ->canBeEnabled()
×
UNCOV
334
                            ->children()
×
UNCOV
335
                                ->arrayNode('varnish_urls')
×
UNCOV
336
                                    ->setDeprecated('api-platform/core', '3.0', 'The "varnish_urls" configuration is deprecated, use "urls" or "scoped_clients".')
×
UNCOV
337
                                    ->defaultValue([])
×
UNCOV
338
                                    ->prototype('scalar')->end()
×
UNCOV
339
                                    ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
×
UNCOV
340
                                ->end()
×
UNCOV
341
                                ->arrayNode('urls')
×
UNCOV
342
                                    ->defaultValue([])
×
UNCOV
343
                                    ->prototype('scalar')->end()
×
UNCOV
344
                                    ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
×
UNCOV
345
                                ->end()
×
UNCOV
346
                                ->arrayNode('scoped_clients')
×
UNCOV
347
                                    ->defaultValue([])
×
UNCOV
348
                                    ->prototype('scalar')->end()
×
UNCOV
349
                                    ->info('Service names of scoped client to use by the cache purger.')
×
UNCOV
350
                                ->end()
×
UNCOV
351
                                ->integerNode('max_header_length')
×
UNCOV
352
                                    ->defaultValue(7500)
×
UNCOV
353
                                    ->info('Max header length supported by the cache server.')
×
UNCOV
354
                                ->end()
×
UNCOV
355
                                ->variableNode('request_options')
×
UNCOV
356
                                    ->defaultValue([])
×
UNCOV
357
                                    ->validate()
×
UNCOV
358
                                        ->ifTrue(static fn($v): bool => false === \is_array($v))
×
UNCOV
359
                                        ->thenInvalid('The request_options parameter must be an array.')
×
UNCOV
360
                                    ->end()
×
UNCOV
361
                                    ->info('To pass options to the client charged with the request.')
×
UNCOV
362
                                ->end()
×
UNCOV
363
                                ->scalarNode('purger')
×
UNCOV
364
                                    ->defaultValue('api_platform.http_cache.purger.varnish')
×
UNCOV
365
                                    ->info('Specify a purger to use (available values: "api_platform.http_cache.purger.varnish.ban", "api_platform.http_cache.purger.varnish.xkey", "api_platform.http_cache.purger.souin").')
×
UNCOV
366
                                ->end()
×
UNCOV
367
                                ->arrayNode('xkey')
×
UNCOV
368
                                    ->setDeprecated('api-platform/core', '3.0', 'The "xkey" configuration is deprecated, use your own purger to customize surrogate keys or the appropriate paramters.')
×
UNCOV
369
                                    ->addDefaultsIfNotSet()
×
UNCOV
370
                                    ->children()
×
UNCOV
371
                                        ->scalarNode('glue')
×
UNCOV
372
                                        ->defaultValue(' ')
×
UNCOV
373
                                        ->info('xkey glue between keys')
×
UNCOV
374
                                        ->end()
×
UNCOV
375
                                    ->end()
×
UNCOV
376
                                ->end()
×
UNCOV
377
                            ->end()
×
UNCOV
378
                        ->end()
×
UNCOV
379
                    ->end()
×
UNCOV
380
                ->end()
×
UNCOV
381
            ->end();
×
382
    }
383

384
    private function addMercureSection(ArrayNodeDefinition $rootNode): void
385
    {
UNCOV
386
        $rootNode
×
UNCOV
387
            ->children()
×
UNCOV
388
                ->arrayNode('mercure')
×
UNCOV
389
                    ->{class_exists(MercureBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
390
                    ->children()
×
UNCOV
391
                        ->scalarNode('hub_url')
×
UNCOV
392
                            ->defaultNull()
×
UNCOV
393
                            ->info('The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle\'s default hub.')
×
UNCOV
394
                        ->end()
×
UNCOV
395
                        ->booleanNode('include_type')
×
UNCOV
396
                            ->defaultFalse()
×
UNCOV
397
                            ->info('Always include @type in updates (including delete ones).')
×
UNCOV
398
                        ->end()
×
UNCOV
399
                    ->end()
×
UNCOV
400
                ->end()
×
UNCOV
401
            ->end();
×
402
    }
403

404
    private function addMessengerSection(ArrayNodeDefinition $rootNode): void
405
    {
UNCOV
406
        $rootNode
×
UNCOV
407
            ->children()
×
UNCOV
408
                ->arrayNode('messenger')
×
UNCOV
409
                    ->{!class_exists(FullStack::class) && interface_exists(MessageBusInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
410
                ->end()
×
UNCOV
411
            ->end();
×
412
    }
413

414
    private function addElasticsearchSection(ArrayNodeDefinition $rootNode): void
415
    {
UNCOV
416
        $rootNode
×
UNCOV
417
            ->children()
×
UNCOV
418
                ->arrayNode('elasticsearch')
×
UNCOV
419
                    ->canBeEnabled()
×
UNCOV
420
                    ->addDefaultsIfNotSet()
×
UNCOV
421
                    ->children()
×
UNCOV
422
                        ->booleanNode('enabled')
×
UNCOV
423
                            ->defaultFalse()
×
UNCOV
424
                            ->validate()
×
UNCOV
425
                                ->ifTrue()
×
UNCOV
426
                                ->then(static function (bool $v): bool {
×
UNCOV
427
                                    if (!(class_exists(\Elasticsearch\Client::class) || class_exists(\Elastic\Elasticsearch\Client::class))) {
×
428
                                        throw new InvalidConfigurationException('The elasticsearch/elasticsearch package is required for Elasticsearch support.');
×
429
                                    }
430

UNCOV
431
                                    return $v;
×
UNCOV
432
                                })
×
UNCOV
433
                            ->end()
×
UNCOV
434
                        ->end()
×
UNCOV
435
                        ->arrayNode('hosts')
×
UNCOV
436
                            ->beforeNormalization()->castToArray()->end()
×
UNCOV
437
                            ->defaultValue([])
×
UNCOV
438
                            ->prototype('scalar')->end()
×
UNCOV
439
                        ->end()
×
UNCOV
440
                        ->arrayNode('mapping')
×
UNCOV
441
                            ->setDeprecated('api-platform/core', '3.1', sprintf('The "%%node%%" option is deprecated. Configure an %s as $stateOptions.', Options::class))
×
UNCOV
442
                            ->normalizeKeys(false)
×
UNCOV
443
                            ->useAttributeAsKey('resource_class')
×
UNCOV
444
                            ->prototype('array')
×
UNCOV
445
                                ->children()
×
UNCOV
446
                                    ->scalarNode('index')->defaultNull()->end()
×
UNCOV
447
                                    ->scalarNode('type')->defaultValue(DocumentMetadata::DEFAULT_TYPE)->end()
×
UNCOV
448
                                ->end()
×
UNCOV
449
                            ->end()
×
UNCOV
450
                        ->end()
×
UNCOV
451
                    ->end()
×
UNCOV
452
                ->end()
×
UNCOV
453
            ->end();
×
454
    }
455

456
    private function addOpenApiSection(ArrayNodeDefinition $rootNode): void
457
    {
UNCOV
458
        $rootNode
×
UNCOV
459
            ->children()
×
UNCOV
460
                ->arrayNode('openapi')
×
UNCOV
461
                    ->addDefaultsIfNotSet()
×
UNCOV
462
                        ->children()
×
UNCOV
463
                        ->arrayNode('contact')
×
UNCOV
464
                        ->addDefaultsIfNotSet()
×
UNCOV
465
                            ->children()
×
UNCOV
466
                                ->scalarNode('name')->defaultNull()->info('The identifying name of the contact person/organization.')->end()
×
UNCOV
467
                                ->scalarNode('url')->defaultNull()->info('The URL pointing to the contact information. MUST be in the format of a URL.')->end()
×
UNCOV
468
                                ->scalarNode('email')->defaultNull()->info('The email address of the contact person/organization. MUST be in the format of an email address.')->end()
×
UNCOV
469
                            ->end()
×
UNCOV
470
                        ->end()
×
UNCOV
471
                        ->scalarNode('termsOfService')->defaultNull()->info('A URL to the Terms of Service for the API. MUST be in the format of a URL.')->end()
×
UNCOV
472
                        ->arrayNode('license')
×
UNCOV
473
                        ->addDefaultsIfNotSet()
×
UNCOV
474
                            ->children()
×
UNCOV
475
                                ->scalarNode('name')->defaultNull()->info('The license name used for the API.')->end()
×
UNCOV
476
                                ->scalarNode('url')->defaultNull()->info('URL to the license used for the API. MUST be in the format of a URL.')->end()
×
UNCOV
477
                            ->end()
×
UNCOV
478
                        ->end()
×
UNCOV
479
                        ->variableNode('swagger_ui_extra_configuration')
×
UNCOV
480
                            ->defaultValue([])
×
UNCOV
481
                            ->validate()
×
UNCOV
482
                                ->ifTrue(static fn($v): bool => false === \is_array($v))
×
UNCOV
483
                                ->thenInvalid('The swagger_ui_extra_configuration parameter must be an array.')
×
UNCOV
484
                            ->end()
×
UNCOV
485
                            ->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
×
UNCOV
486
                        ->end()
×
UNCOV
487
                    ->end()
×
UNCOV
488
                ->end()
×
UNCOV
489
            ->end();
×
490
    }
491

492
    /**
493
     * @throws InvalidConfigurationException
494
     */
495
    private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode): void
496
    {
UNCOV
497
        $rootNode
×
UNCOV
498
            ->children()
×
UNCOV
499
                ->arrayNode('exception_to_status')
×
UNCOV
500
                    ->defaultValue([
×
UNCOV
501
                        SerializerExceptionInterface::class => Response::HTTP_BAD_REQUEST,
×
UNCOV
502
                        InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
×
UNCOV
503
                        FilterValidationException::class => Response::HTTP_BAD_REQUEST,
×
UNCOV
504
                        OptimisticLockException::class => Response::HTTP_CONFLICT,
×
UNCOV
505
                    ])
×
UNCOV
506
                    ->info('The list of exceptions mapped to their HTTP status code.')
×
UNCOV
507
                    ->normalizeKeys(false)
×
UNCOV
508
                    ->useAttributeAsKey('exception_class')
×
UNCOV
509
                    ->prototype('integer')->end()
×
UNCOV
510
                    ->validate()
×
UNCOV
511
                        ->ifArray()
×
UNCOV
512
                        ->then(static function (array $exceptionToStatus): array {
×
UNCOV
513
                            foreach ($exceptionToStatus as $httpStatusCode) {
×
UNCOV
514
                                if ($httpStatusCode < 100 || $httpStatusCode >= 600) {
×
UNCOV
515
                                    throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.', $httpStatusCode));
×
516
                                }
517
                            }
518

UNCOV
519
                            return $exceptionToStatus;
×
UNCOV
520
                        })
×
UNCOV
521
                    ->end()
×
UNCOV
522
                ->end()
×
UNCOV
523
            ->end();
×
524
    }
525

526
    private function addFormatSection(ArrayNodeDefinition $rootNode, string $key, array $defaultValue): void
527
    {
UNCOV
528
        $rootNode
×
UNCOV
529
            ->children()
×
UNCOV
530
                ->arrayNode($key)
×
UNCOV
531
                    ->defaultValue($defaultValue)
×
UNCOV
532
                    ->info('The list of enabled formats. The first one will be the default.')
×
UNCOV
533
                    ->normalizeKeys(false)
×
UNCOV
534
                    ->useAttributeAsKey('format')
×
UNCOV
535
                    ->beforeNormalization()
×
UNCOV
536
                        ->ifArray()
×
UNCOV
537
                        ->then(static function ($v) {
×
UNCOV
538
                            foreach ($v as $format => $value) {
×
UNCOV
539
                                if (isset($value['mime_types'])) {
×
UNCOV
540
                                    continue;
×
541
                                }
542

UNCOV
543
                                $v[$format] = ['mime_types' => $value];
×
544
                            }
545

UNCOV
546
                            return $v;
×
UNCOV
547
                        })
×
UNCOV
548
                    ->end()
×
UNCOV
549
                    ->prototype('array')
×
UNCOV
550
                        ->children()
×
UNCOV
551
                            ->arrayNode('mime_types')->prototype('scalar')->end()->end()
×
UNCOV
552
                        ->end()
×
UNCOV
553
                    ->end()
×
UNCOV
554
                ->end()
×
UNCOV
555
            ->end();
×
556
    }
557

558
    private function addDefaultsSection(ArrayNodeDefinition $rootNode): void
559
    {
UNCOV
560
        $nameConverter = new CamelCaseToSnakeCaseNameConverter();
×
UNCOV
561
        $defaultsNode = $rootNode->children()->arrayNode('defaults');
×
562

UNCOV
563
        $defaultsNode
×
UNCOV
564
            ->ignoreExtraKeys(false)
×
UNCOV
565
            ->beforeNormalization()
×
UNCOV
566
            ->always(static function (array $defaults) use ($nameConverter): array {
×
UNCOV
567
                $normalizedDefaults = [];
×
UNCOV
568
                foreach ($defaults as $option => $value) {
×
UNCOV
569
                    $option = $nameConverter->normalize($option);
×
UNCOV
570
                    $normalizedDefaults[$option] = $value;
×
571
                }
572

UNCOV
573
                return $normalizedDefaults;
×
UNCOV
574
            });
×
575

UNCOV
576
        $this->defineDefault($defaultsNode, new \ReflectionClass(ApiResource::class), $nameConverter);
×
UNCOV
577
        $this->defineDefault($defaultsNode, new \ReflectionClass(Put::class), $nameConverter);
×
UNCOV
578
        $this->defineDefault($defaultsNode, new \ReflectionClass(Post::class), $nameConverter);
×
579
    }
580

581
    private function addMakerSection(ArrayNodeDefinition $rootNode): void
582
    {
UNCOV
583
        $rootNode
×
UNCOV
584
            ->children()
×
UNCOV
585
                ->arrayNode('maker')
×
UNCOV
586
                    ->{class_exists(MakerBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
×
UNCOV
587
                ->end()
×
UNCOV
588
            ->end();
×
589
    }
590

591
    private function defineDefault(ArrayNodeDefinition $defaultsNode, \ReflectionClass $reflectionClass, CamelCaseToSnakeCaseNameConverter $nameConverter)
592
    {
UNCOV
593
        foreach ($reflectionClass->getConstructor()->getParameters() as $parameter) {
×
UNCOV
594
            $defaultsNode->children()->variableNode($nameConverter->normalize($parameter->getName()));
×
595
        }
596
    }
597
}
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