vendor/api-platform/core/src/Symfony/Bundle/DependencyInjection/Configuration.php line 545

  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace ApiPlatform\Symfony\Bundle\DependencyInjection;
  12. use ApiPlatform\Doctrine\Common\Filter\OrderFilterInterface;
  13. use ApiPlatform\Elasticsearch\Metadata\Document\DocumentMetadata;
  14. use ApiPlatform\Elasticsearch\State\Options;
  15. use ApiPlatform\Exception\FilterValidationException;
  16. use ApiPlatform\Exception\InvalidArgumentException;
  17. use ApiPlatform\Metadata\ApiResource;
  18. use ApiPlatform\Metadata\Post;
  19. use ApiPlatform\Metadata\Put;
  20. use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
  21. use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
  22. use Doctrine\ORM\EntityManagerInterface;
  23. use Doctrine\ORM\OptimisticLockException;
  24. use Elasticsearch\Client as ElasticsearchClient;
  25. use GraphQL\GraphQL;
  26. use Symfony\Bundle\FullStack;
  27. use Symfony\Bundle\MakerBundle\MakerBundle;
  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.  * The configuration of the bundle.
  40.  *
  41.  * @author Kévin Dunglas <dunglas@gmail.com>
  42.  * @author Baptiste Meyer <baptiste.meyer@gmail.com>
  43.  */
  44. final class Configuration implements ConfigurationInterface
  45. {
  46.     /**
  47.      * {@inheritdoc}
  48.      */
  49.     public function getConfigTreeBuilder(): TreeBuilder
  50.     {
  51.         $treeBuilder = new TreeBuilder('api_platform');
  52.         $rootNode $treeBuilder->getRootNode();
  53.         $rootNode
  54.             ->beforeNormalization()
  55.                 ->ifTrue(static function ($v) {
  56.                     return false === ($v['enable_swagger'] ?? null);
  57.                 })
  58.                 ->then(static function ($v) {
  59.                     $v['swagger']['versions'] = [];
  60.                     return $v;
  61.                 })
  62.             ->end()
  63.             ->children()
  64.                 ->scalarNode('title')
  65.                     ->info('The title of the API.')
  66.                     ->cannotBeEmpty()
  67.                     ->defaultValue('')
  68.                 ->end()
  69.                 ->scalarNode('description')
  70.                     ->info('The description of the API.')
  71.                     ->cannotBeEmpty()
  72.                     ->defaultValue('')
  73.                 ->end()
  74.                 ->scalarNode('version')
  75.                     ->info('The version of the API.')
  76.                     ->cannotBeEmpty()
  77.                     ->defaultValue('0.0.0')
  78.                 ->end()
  79.                 ->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end()
  80.                 ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
  81.                 ->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end()
  82.                 ->scalarNode('path_segment_name_generator')->defaultValue('api_platform.metadata.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()
  83.                 ->arrayNode('validator')
  84.                     ->addDefaultsIfNotSet()
  85.                     ->children()
  86.                         ->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()
  87.                         ->booleanNode('query_parameter_validation')->defaultValue(true)->end()
  88.                     ->end()
  89.                 ->end()
  90.                 ->arrayNode('eager_loading')
  91.                     ->canBeDisabled()
  92.                     ->addDefaultsIfNotSet()
  93.                     ->children()
  94.                         ->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()
  95.                         ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
  96.                         ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
  97.                     ->end()
  98.                 ->end()
  99.                 ->booleanNode('enable_swagger')->defaultTrue()->info('Enable the Swagger documentation and export.')->end()
  100.                 ->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger UI')->end()
  101.                 ->booleanNode('enable_re_doc')->defaultValue(class_exists(TwigBundle::class))->info('Enable ReDoc')->end()
  102.                 ->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
  103.                 ->booleanNode('enable_docs')->defaultTrue()->info('Enable the docs')->end()
  104.                 ->booleanNode('enable_profiler')->defaultTrue()->info('Enable the data collector and the WebProfilerBundle integration.')->end()
  105.                 ->arrayNode('collection')
  106.                     ->addDefaultsIfNotSet()
  107.                     ->children()
  108.                         ->scalarNode('exists_parameter_name')->defaultValue('exists')->cannotBeEmpty()->info('The name of the query parameter to filter on nullable field values.')->end()
  109.                         ->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
  110.                         ->scalarNode('order_parameter_name')->defaultValue('order')->cannotBeEmpty()->info('The name of the query parameter to order results.')->end()
  111.                         ->enumNode('order_nulls_comparison')->defaultNull()->values(array_merge(array_keys(OrderFilterInterface::NULLS_DIRECTION_MAP), [null]))->info('The nulls comparison strategy.')->end()
  112.                         ->arrayNode('pagination')
  113.                             ->canBeDisabled()
  114.                             ->addDefaultsIfNotSet()
  115.                             ->children()
  116.                                 ->scalarNode('page_parameter_name')->defaultValue('page')->cannotBeEmpty()->info('The default name of the parameter handling the page number.')->end()
  117.                                 ->scalarNode('enabled_parameter_name')->defaultValue('pagination')->cannotBeEmpty()->info('The name of the query parameter to enable or disable pagination.')->end()
  118.                                 ->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()
  119.                                 ->scalarNode('partial_parameter_name')->defaultValue('partial')->cannotBeEmpty()->info('The name of the query parameter to enable or disable partial pagination.')->end()
  120.                             ->end()
  121.                         ->end()
  122.                     ->end()
  123.                 ->end()
  124.                 ->arrayNode('mapping')
  125.                     ->addDefaultsIfNotSet()
  126.                     ->children()
  127.                         ->arrayNode('paths')
  128.                             ->prototype('scalar')->end()
  129.                         ->end()
  130.                     ->end()
  131.                 ->end()
  132.                 ->arrayNode('resource_class_directories')
  133.                     ->prototype('scalar')->end()
  134.                 ->end()
  135.             ->end();
  136.         $this->addDoctrineOrmSection($rootNode);
  137.         $this->addDoctrineMongoDbOdmSection($rootNode);
  138.         $this->addOAuthSection($rootNode);
  139.         $this->addGraphQlSection($rootNode);
  140.         $this->addSwaggerSection($rootNode);
  141.         $this->addHttpCacheSection($rootNode);
  142.         $this->addMercureSection($rootNode);
  143.         $this->addMessengerSection($rootNode);
  144.         $this->addElasticsearchSection($rootNode);
  145.         $this->addOpenApiSection($rootNode);
  146.         $this->addMakerSection($rootNode);
  147.         $this->addExceptionToStatusSection($rootNode);
  148.         $this->addFormatSection($rootNode'formats', [
  149.             'jsonld' => ['mime_types' => ['application/ld+json']],
  150.             'json' => ['mime_types' => ['application/json']], // Swagger support
  151.             'html' => ['mime_types' => ['text/html']], // Swagger UI support
  152.         ]);
  153.         $this->addFormatSection($rootNode'patch_formats', [
  154.             'json' => ['mime_types' => ['application/merge-patch+json']],
  155.         ]);
  156.         $this->addFormatSection($rootNode'error_formats', [
  157.             'jsonproblem' => ['mime_types' => ['application/problem+json']],
  158.             'jsonld' => ['mime_types' => ['application/ld+json']],
  159.         ]);
  160.         $this->addDefaultsSection($rootNode);
  161.         return $treeBuilder;
  162.     }
  163.     private function addDoctrineOrmSection(ArrayNodeDefinition $rootNode): void
  164.     {
  165.         $rootNode
  166.             ->children()
  167.                 ->arrayNode('doctrine')
  168.                     ->{class_exists(DoctrineBundle::class) && interface_exists(EntityManagerInterface::class) ? 'canBeDisabled' 'canBeEnabled'}()
  169.                 ->end()
  170.             ->end();
  171.     }
  172.     private function addDoctrineMongoDbOdmSection(ArrayNodeDefinition $rootNode): void
  173.     {
  174.         $rootNode
  175.             ->children()
  176.                 ->arrayNode('doctrine_mongodb_odm')
  177.                     ->{class_exists(DoctrineMongoDBBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  178.                 ->end()
  179.             ->end();
  180.     }
  181.     private function addOAuthSection(ArrayNodeDefinition $rootNode): void
  182.     {
  183.         $rootNode
  184.             ->children()
  185.                 ->arrayNode('oauth')
  186.                     ->canBeEnabled()
  187.                     ->addDefaultsIfNotSet()
  188.                     ->children()
  189.                         ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
  190.                         ->scalarNode('clientSecret')
  191.                             ->defaultValue('')
  192.                             ->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')
  193.                         ->end()
  194.                         ->booleanNode('pkce')->defaultFalse()->info('Enable the oauth PKCE.')->end()
  195.                         ->scalarNode('type')->defaultValue('oauth2')->info('The oauth type.')->end()
  196.                         ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
  197.                         ->scalarNode('tokenUrl')->defaultValue('')->info('The oauth token url.')->end()
  198.                         ->scalarNode('authorizationUrl')->defaultValue('')->info('The oauth authentication url.')->end()
  199.                         ->scalarNode('refreshUrl')->defaultValue('')->info('The oauth refresh url.')->end()
  200.                         ->arrayNode('scopes')
  201.                             ->prototype('scalar')->end()
  202.                         ->end()
  203.                     ->end()
  204.                 ->end()
  205.             ->end();
  206.     }
  207.     private function addGraphQlSection(ArrayNodeDefinition $rootNode): void
  208.     {
  209.         $rootNode
  210.             ->children()
  211.                 ->arrayNode('graphql')
  212.                     ->{class_exists(GraphQL::class) ? 'canBeDisabled' 'canBeEnabled'}()
  213.                     ->addDefaultsIfNotSet()
  214.                     ->children()
  215.                         ->scalarNode('default_ide')->defaultValue('graphiql')->end()
  216.                         ->arrayNode('graphiql')
  217.                             ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  218.                         ->end()
  219.                         ->arrayNode('graphql_playground')
  220.                             ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  221.                         ->end()
  222.                         ->scalarNode('nesting_separator')->defaultValue('_')->info('The separator to use to filter nested fields.')->end()
  223.                         ->arrayNode('collection')
  224.                             ->addDefaultsIfNotSet()
  225.                             ->children()
  226.                                 ->arrayNode('pagination')
  227.                                     ->canBeDisabled()
  228.                                 ->end()
  229.                             ->end()
  230.                         ->end()
  231.                     ->end()
  232.                 ->end()
  233.             ->end();
  234.     }
  235.     private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
  236.     {
  237.         $supportedVersions = [3];
  238.         $rootNode
  239.             ->children()
  240.                 ->arrayNode('swagger')
  241.                     ->addDefaultsIfNotSet()
  242.                     ->children()
  243.                         ->arrayNode('versions')
  244.                             ->info('The active versions of OpenAPI to be exported or used in Swagger UI. The first value is the default.')
  245.                             ->defaultValue($supportedVersions)
  246.                             ->beforeNormalization()
  247.                                 ->always(static function ($v): array {
  248.                                     if (!\is_array($v)) {
  249.                                         $v = [$v];
  250.                                     }
  251.                                     foreach ($v as &$version) {
  252.                                         $version = (int) $version;
  253.                                     }
  254.                                     return $v;
  255.                                 })
  256.                             ->end()
  257.                             ->validate()
  258.                                 ->ifTrue(static fn($v): bool => $v !== array_intersect($v$supportedVersions))
  259.                                 ->thenInvalid(sprintf('Only the versions %s are supported. Got %s.'implode(' and '$supportedVersions), '%s'))
  260.                             ->end()
  261.                             ->prototype('scalar')->end()
  262.                         ->end()
  263.                         ->arrayNode('api_keys')
  264.                             ->useAttributeAsKey('key')
  265.                             ->prototype('array')
  266.                                 ->children()
  267.                                     ->scalarNode('name')
  268.                                         ->info('The name of the header or query parameter containing the api key.')
  269.                                     ->end()
  270.                                     ->enumNode('type')
  271.                                         ->info('Whether the api key should be a query parameter or a header.')
  272.                                         ->values(['query''header'])
  273.                                     ->end()
  274.                                 ->end()
  275.                             ->end()
  276.                         ->end()
  277.                         ->variableNode('swagger_ui_extra_configuration')
  278.                             ->defaultValue([])
  279.                             ->validate()
  280.                                 ->ifTrue(static fn($v): bool => false === \is_array($v))
  281.                                 ->thenInvalid('The swagger_ui_extra_configuration parameter must be an array.')
  282.                             ->end()
  283.                             ->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
  284.                         ->end()
  285.                     ->end()
  286.                 ->end()
  287.             ->end();
  288.     }
  289.     private function addHttpCacheSection(ArrayNodeDefinition $rootNode): void
  290.     {
  291.         $rootNode
  292.             ->children()
  293.                 ->arrayNode('http_cache')
  294.                     ->addDefaultsIfNotSet()
  295.                     ->children()
  296.                         ->booleanNode('public')->defaultNull()->info('To make all responses public by default.')->end()
  297.                         ->arrayNode('invalidation')
  298.                             ->info('Enable the tags-based cache invalidation system.')
  299.                             ->canBeEnabled()
  300.                             ->children()
  301.                                 ->arrayNode('varnish_urls')
  302.                                     ->setDeprecated('api-platform/core''3.0''The "varnish_urls" configuration is deprecated, use "urls" or "scoped_clients".')
  303.                                     ->defaultValue([])
  304.                                     ->prototype('scalar')->end()
  305.                                     ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
  306.                                 ->end()
  307.                                 ->arrayNode('urls')
  308.                                     ->defaultValue([])
  309.                                     ->prototype('scalar')->end()
  310.                                     ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
  311.                                 ->end()
  312.                                 ->arrayNode('scoped_clients')
  313.                                     ->defaultValue([])
  314.                                     ->prototype('scalar')->end()
  315.                                     ->info('Service names of scoped client to use by the cache purger.')
  316.                                 ->end()
  317.                                 ->integerNode('max_header_length')
  318.                                     ->defaultValue(7500)
  319.                                     ->info('Max header length supported by the cache server.')
  320.                                 ->end()
  321.                                 ->variableNode('request_options')
  322.                                     ->defaultValue([])
  323.                                     ->validate()
  324.                                         ->ifTrue(static fn($v): bool => false === \is_array($v))
  325.                                         ->thenInvalid('The request_options parameter must be an array.')
  326.                                     ->end()
  327.                                     ->info('To pass options to the client charged with the request.')
  328.                                 ->end()
  329.                                 ->scalarNode('purger')
  330.                                     ->defaultValue('api_platform.http_cache.purger.varnish')
  331.                                     ->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").')
  332.                                 ->end()
  333.                                 ->arrayNode('xkey')
  334.                                     ->setDeprecated('api-platform/core''3.0''The "xkey" configuration is deprecated, use your own purger to customize surrogate keys or the appropriate paramters.')
  335.                                     ->addDefaultsIfNotSet()
  336.                                     ->children()
  337.                                         ->scalarNode('glue')
  338.                                         ->defaultValue(' ')
  339.                                         ->info('xkey glue between keys')
  340.                                         ->end()
  341.                                     ->end()
  342.                                 ->end()
  343.                             ->end()
  344.                         ->end()
  345.                     ->end()
  346.                 ->end()
  347.             ->end();
  348.     }
  349.     private function addMercureSection(ArrayNodeDefinition $rootNode): void
  350.     {
  351.         $rootNode
  352.             ->children()
  353.                 ->arrayNode('mercure')
  354.                     ->{class_exists(MercureBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  355.                     ->children()
  356.                         ->scalarNode('hub_url')
  357.                             ->defaultNull()
  358.                             ->info('The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle\'s default hub.')
  359.                         ->end()
  360.                         ->booleanNode('include_type')
  361.                             ->defaultFalse()
  362.                             ->info('Always include @type in updates (including delete ones).')
  363.                         ->end()
  364.                     ->end()
  365.                 ->end()
  366.             ->end();
  367.     }
  368.     private function addMessengerSection(ArrayNodeDefinition $rootNode): void
  369.     {
  370.         $rootNode
  371.             ->children()
  372.                 ->arrayNode('messenger')
  373.                     ->{!class_exists(FullStack::class) && interface_exists(MessageBusInterface::class) ? 'canBeDisabled' 'canBeEnabled'}()
  374.                 ->end()
  375.             ->end();
  376.     }
  377.     private function addElasticsearchSection(ArrayNodeDefinition $rootNode): void
  378.     {
  379.         $rootNode
  380.             ->children()
  381.                 ->arrayNode('elasticsearch')
  382.                     ->canBeEnabled()
  383.                     ->addDefaultsIfNotSet()
  384.                     ->children()
  385.                         ->booleanNode('enabled')
  386.                             ->defaultFalse()
  387.                             ->validate()
  388.                                 ->ifTrue()
  389.                                 ->then(static function (bool $v): bool {
  390.                                     if (!class_exists(ElasticsearchClient::class)) {
  391.                                         throw new InvalidConfigurationException('The elasticsearch/elasticsearch package is required for Elasticsearch support.');
  392.                                     }
  393.                                     return $v;
  394.                                 })
  395.                             ->end()
  396.                         ->end()
  397.                         ->arrayNode('hosts')
  398.                             ->beforeNormalization()->castToArray()->end()
  399.                             ->defaultValue([])
  400.                             ->prototype('scalar')->end()
  401.                         ->end()
  402.                         ->arrayNode('mapping')
  403.                             ->setDeprecated('api-platform/core''3.1'sprintf('The "%%node%%" option is deprecated. Configure an %s as $stateOptions.'Options::class))
  404.                             ->normalizeKeys(false)
  405.                             ->useAttributeAsKey('resource_class')
  406.                             ->prototype('array')
  407.                                 ->children()
  408.                                     ->scalarNode('index')->defaultNull()->end()
  409.                                     ->scalarNode('type')->defaultValue(DocumentMetadata::DEFAULT_TYPE)->end()
  410.                                 ->end()
  411.                             ->end()
  412.                         ->end()
  413.                     ->end()
  414.                 ->end()
  415.             ->end();
  416.     }
  417.     private function addOpenApiSection(ArrayNodeDefinition $rootNode): void
  418.     {
  419.         $rootNode
  420.             ->children()
  421.                 ->arrayNode('openapi')
  422.                     ->addDefaultsIfNotSet()
  423.                         ->children()
  424.                         ->arrayNode('contact')
  425.                         ->addDefaultsIfNotSet()
  426.                             ->children()
  427.                                 ->scalarNode('name')->defaultNull()->info('The identifying name of the contact person/organization.')->end()
  428.                                 ->scalarNode('url')->defaultNull()->info('The URL pointing to the contact information. MUST be in the format of a URL.')->end()
  429.                                 ->scalarNode('email')->defaultNull()->info('The email address of the contact person/organization. MUST be in the format of an email address.')->end()
  430.                             ->end()
  431.                         ->end()
  432.                         ->scalarNode('termsOfService')->defaultNull()->info('A URL to the Terms of Service for the API. MUST be in the format of a URL.')->end()
  433.                         ->arrayNode('license')
  434.                         ->addDefaultsIfNotSet()
  435.                             ->children()
  436.                                 ->scalarNode('name')->defaultNull()->info('The license name used for the API.')->end()
  437.                                 ->scalarNode('url')->defaultNull()->info('URL to the license used for the API. MUST be in the format of a URL.')->end()
  438.                             ->end()
  439.                         ->end()
  440.                         ->variableNode('swagger_ui_extra_configuration')
  441.                             ->defaultValue([])
  442.                             ->validate()
  443.                                 ->ifTrue(static fn($v): bool => false === \is_array($v))
  444.                                 ->thenInvalid('The swagger_ui_extra_configuration parameter must be an array.')
  445.                             ->end()
  446.                             ->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
  447.                         ->end()
  448.                     ->end()
  449.                 ->end()
  450.             ->end();
  451.     }
  452.     /**
  453.      * @throws InvalidConfigurationException
  454.      */
  455.     private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode): void
  456.     {
  457.         $rootNode
  458.             ->children()
  459.                 ->arrayNode('exception_to_status')
  460.                     ->defaultValue([
  461.                         SerializerExceptionInterface::class => Response::HTTP_BAD_REQUEST,
  462.                         InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
  463.                         FilterValidationException::class => Response::HTTP_BAD_REQUEST,
  464.                         OptimisticLockException::class => Response::HTTP_CONFLICT,
  465.                     ])
  466.                     ->info('The list of exceptions mapped to their HTTP status code.')
  467.                     ->normalizeKeys(false)
  468.                     ->useAttributeAsKey('exception_class')
  469.                     ->prototype('integer')->end()
  470.                     ->validate()
  471.                         ->ifArray()
  472.                         ->then(static function (array $exceptionToStatus): array {
  473.                             foreach ($exceptionToStatus as $httpStatusCode) {
  474.                                 if ($httpStatusCode 100 || $httpStatusCode >= 600) {
  475.                                     throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.'$httpStatusCode));
  476.                                 }
  477.                             }
  478.                             return $exceptionToStatus;
  479.                         })
  480.                     ->end()
  481.                 ->end()
  482.             ->end();
  483.     }
  484.     private function addFormatSection(ArrayNodeDefinition $rootNodestring $key, array $defaultValue): void
  485.     {
  486.         $rootNode
  487.             ->children()
  488.                 ->arrayNode($key)
  489.                     ->defaultValue($defaultValue)
  490.                     ->info('The list of enabled formats. The first one will be the default.')
  491.                     ->normalizeKeys(false)
  492.                     ->useAttributeAsKey('format')
  493.                     ->beforeNormalization()
  494.                         ->ifArray()
  495.                         ->then(static function ($v) {
  496.                             foreach ($v as $format => $value) {
  497.                                 if (isset($value['mime_types'])) {
  498.                                     continue;
  499.                                 }
  500.                                 $v[$format] = ['mime_types' => $value];
  501.                             }
  502.                             return $v;
  503.                         })
  504.                     ->end()
  505.                     ->prototype('array')
  506.                         ->children()
  507.                             ->arrayNode('mime_types')->prototype('scalar')->end()->end()
  508.                         ->end()
  509.                     ->end()
  510.                 ->end()
  511.             ->end();
  512.     }
  513.     private function addDefaultsSection(ArrayNodeDefinition $rootNode): void
  514.     {
  515.         $nameConverter = new CamelCaseToSnakeCaseNameConverter();
  516.         $defaultsNode $rootNode->children()->arrayNode('defaults');
  517.         $defaultsNode
  518.             ->ignoreExtraKeys(false)
  519.             ->beforeNormalization()
  520.             ->always(static function (array $defaults) use ($nameConverter): array {
  521.                 $normalizedDefaults = [];
  522.                 foreach ($defaults as $option => $value) {
  523.                     $option $nameConverter->normalize($option);
  524.                     $normalizedDefaults[$option] = $value;
  525.                 }
  526.                 return $normalizedDefaults;
  527.             });
  528.         $this->defineDefault($defaultsNode, new \ReflectionClass(ApiResource::class), $nameConverter);
  529.         $this->defineDefault($defaultsNode, new \ReflectionClass(Put::class), $nameConverter);
  530.         $this->defineDefault($defaultsNode, new \ReflectionClass(Post::class), $nameConverter);
  531.     }
  532.     private function addMakerSection(ArrayNodeDefinition $rootNode): void
  533.     {
  534.         $rootNode
  535.             ->children()
  536.                 ->arrayNode('maker')
  537.                     ->{class_exists(MakerBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  538.                 ->end()
  539.             ->end();
  540.     }
  541.     private function defineDefault(ArrayNodeDefinition $defaultsNode\ReflectionClass $reflectionClassCamelCaseToSnakeCaseNameConverter $nameConverter)
  542.     {
  543.         foreach ($reflectionClass->getConstructor()->getParameters() as $parameter) {
  544.             $defaultsNode->children()->variableNode($nameConverter->normalize($parameter->getName()));
  545.         }
  546.     }
  547. }