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

Open in your IDE?
  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\Core\Bridge\Symfony\Bundle\DependencyInjection;
  12. use ApiPlatform\Core\Annotation\ApiResource;
  13. use ApiPlatform\Core\Bridge\Elasticsearch\Metadata\Document\DocumentMetadata;
  14. use ApiPlatform\Core\Exception\FilterValidationException;
  15. use ApiPlatform\Core\Exception\InvalidArgumentException;
  16. use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
  17. use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
  18. use Doctrine\ORM\EntityManagerInterface;
  19. use Doctrine\ORM\OptimisticLockException;
  20. use Elasticsearch\Client as ElasticsearchClient;
  21. use FOS\UserBundle\FOSUserBundle;
  22. use GraphQL\GraphQL;
  23. use Symfony\Bundle\FullStack;
  24. use Symfony\Bundle\MercureBundle\MercureBundle;
  25. use Symfony\Bundle\TwigBundle\TwigBundle;
  26. use Symfony\Component\Config\Definition\BaseNode;
  27. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  28. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  29. use Symfony\Component\Config\Definition\ConfigurationInterface;
  30. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\Messenger\MessageBusInterface;
  33. use Symfony\Component\Serializer\Exception\ExceptionInterface as SerializerExceptionInterface;
  34. use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
  35. /**
  36.  * The configuration of the bundle.
  37.  *
  38.  * @author Kévin Dunglas <dunglas@gmail.com>
  39.  * @author Baptiste Meyer <baptiste.meyer@gmail.com>
  40.  */
  41. final class Configuration implements ConfigurationInterface
  42. {
  43.     /**
  44.      * {@inheritdoc}
  45.      * @return TreeBuilder
  46.      */
  47.     public function getConfigTreeBuilder(): TreeBuilder
  48.     {
  49.         if (method_exists(TreeBuilder::class, 'getRootNode')) {
  50.             $treeBuilder = new TreeBuilder('api_platform');
  51.             $rootNode $treeBuilder->getRootNode();
  52.         } else {
  53.             $treeBuilder = new TreeBuilder();
  54.             $rootNode $treeBuilder->root('api_platform');
  55.         }
  56.         $rootNode
  57.             ->beforeNormalization()
  58.                 ->ifTrue(static function ($v) {
  59.                     return false === ($v['enable_swagger'] ?? null);
  60.                 })
  61.                 ->then(static function ($v) {
  62.                     $v['swagger']['versions'] = [];
  63.                     return $v;
  64.                 })
  65.             ->end()
  66.             ->children()
  67.                 ->scalarNode('title')
  68.                     ->info('The title of the API.')
  69.                     ->cannotBeEmpty()
  70.                     ->defaultValue('')
  71.                 ->end()
  72.                 ->scalarNode('description')
  73.                     ->info('The description of the API.')
  74.                     ->cannotBeEmpty()
  75.                     ->defaultValue('')
  76.                 ->end()
  77.                 ->scalarNode('version')
  78.                     ->info('The version of the API.')
  79.                     ->cannotBeEmpty()
  80.                     ->defaultValue('0.0.0')
  81.                 ->end()
  82.                 ->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end()
  83.                 ->scalarNode('default_operation_path_resolver')
  84.                     ->defaultValue('api_platform.operation_path_resolver.underscore')
  85.                     ->setDeprecated(...$this->buildDeprecationArgs('2.1''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.'))
  86.                     ->info('Specify the default operation path resolver to use for generating resources operations path.')
  87.                 ->end()
  88.                 ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
  89.                 ->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end()
  90.                 ->scalarNode('path_segment_name_generator')->defaultValue('api_platform.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()
  91.                 ->booleanNode('allow_plain_identifiers')->defaultFalse()->info('Allow plain identifiers, for example "id" instead of "@id" when denormalizing a relation.')->end()
  92.                 ->arrayNode('validator')
  93.                     ->addDefaultsIfNotSet()
  94.                     ->children()
  95.                         ->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()
  96.                     ->end()
  97.                 ->end()
  98.                 ->arrayNode('eager_loading')
  99.                     ->canBeDisabled()
  100.                     ->addDefaultsIfNotSet()
  101.                     ->children()
  102.                         ->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()
  103.                         ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
  104.                         ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
  105.                     ->end()
  106.                 ->end()
  107.                 ->booleanNode('enable_fos_user')
  108.                     ->defaultValue(class_exists(FOSUserBundle::class))
  109.                     ->setDeprecated(...$this->buildDeprecationArgs('2.5''FOSUserBundle is not actively maintained anymore. Enabling the FOSUserBundle integration has been deprecated in 2.5 and will be removed in 3.0.'))
  110.                     ->info('Enable the FOSUserBundle integration.')
  111.                 ->end()
  112.                 ->booleanNode('enable_nelmio_api_doc')
  113.                     ->defaultFalse()
  114.                     ->setDeprecated(...$this->buildDeprecationArgs('2.2''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(...$this->buildDeprecationArgs('2.6''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(...$this->buildDeprecationArgs('2.6''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(...$this->buildDeprecationArgs('2.6''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(...$this->buildDeprecationArgs('2.6''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(...$this->buildDeprecationArgs('2.6''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(...$this->buildDeprecationArgs('2.6''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(...$this->buildDeprecationArgs('2.6''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.         $this->addDoctrineOrmSection($rootNode);
  189.         $this->addDoctrineMongoDbOdmSection($rootNode);
  190.         $this->addOAuthSection($rootNode);
  191.         $this->addGraphQlSection($rootNode);
  192.         $this->addSwaggerSection($rootNode);
  193.         $this->addHttpCacheSection($rootNode);
  194.         $this->addMercureSection($rootNode);
  195.         $this->addMessengerSection($rootNode);
  196.         $this->addElasticsearchSection($rootNode);
  197.         $this->addOpenApiSection($rootNode);
  198.         $this->addExceptionToStatusSection($rootNode);
  199.         $this->addFormatSection($rootNode'formats', [
  200.             'jsonld' => ['mime_types' => ['application/ld+json']],
  201.             'json' => ['mime_types' => ['application/json']], // Swagger support
  202.             'html' => ['mime_types' => ['text/html']], // Swagger UI support
  203.         ]);
  204.         $this->addFormatSection($rootNode'patch_formats', []);
  205.         $this->addFormatSection($rootNode'error_formats', [
  206.             'jsonproblem' => ['mime_types' => ['application/problem+json']],
  207.             'jsonld' => ['mime_types' => ['application/ld+json']],
  208.         ]);
  209.         $this->addDefaultsSection($rootNode);
  210.         return $treeBuilder;
  211.     }
  212.     private function addDoctrineOrmSection(ArrayNodeDefinition $rootNode): void
  213.     {
  214.         $rootNode
  215.             ->children()
  216.                 ->arrayNode('doctrine')
  217.                     ->{class_exists(DoctrineBundle::class) && interface_exists(EntityManagerInterface::class) ? 'canBeDisabled' 'canBeEnabled'}()
  218.                 ->end()
  219.             ->end();
  220.     }
  221.     private function addDoctrineMongoDbOdmSection(ArrayNodeDefinition $rootNode): void
  222.     {
  223.         $rootNode
  224.             ->children()
  225.                 ->arrayNode('doctrine_mongodb_odm')
  226.                     ->{class_exists(DoctrineMongoDBBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  227.                 ->end()
  228.             ->end();
  229.     }
  230.     private function addOAuthSection(ArrayNodeDefinition $rootNode): void
  231.     {
  232.         $rootNode
  233.             ->children()
  234.                 ->arrayNode('oauth')
  235.                     ->canBeEnabled()
  236.                     ->addDefaultsIfNotSet()
  237.                     ->children()
  238.                         ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
  239.                         ->scalarNode('clientSecret')->defaultValue('')->info('The oauth client secret.')->end()
  240.                         ->scalarNode('type')->defaultValue('oauth2')->info('The oauth type.')->end()
  241.                         ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
  242.                         ->scalarNode('tokenUrl')->defaultValue('')->info('The oauth token url.')->end()
  243.                         ->scalarNode('authorizationUrl')->defaultValue('')->info('The oauth authentication url.')->end()
  244.                         ->scalarNode('refreshUrl')->defaultValue('')->info('The oauth refresh url.')->end()
  245.                         ->arrayNode('scopes')
  246.                             ->prototype('scalar')->end()
  247.                         ->end()
  248.                     ->end()
  249.                 ->end()
  250.             ->end();
  251.     }
  252.     private function addGraphQlSection(ArrayNodeDefinition $rootNode): void
  253.     {
  254.         $rootNode
  255.             ->children()
  256.                 ->arrayNode('graphql')
  257.                     ->{class_exists(GraphQL::class) ? 'canBeDisabled' 'canBeEnabled'}()
  258.                     ->addDefaultsIfNotSet()
  259.                     ->children()
  260.                         ->scalarNode('default_ide')->defaultValue('graphiql')->end()
  261.                         ->arrayNode('graphiql')
  262.                             ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  263.                         ->end()
  264.                         ->arrayNode('graphql_playground')
  265.                             ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  266.                         ->end()
  267.                         ->scalarNode('nesting_separator')->defaultValue('_')->info('The separator to use to filter nested fields.')->end()
  268.                         ->arrayNode('collection')
  269.                             ->addDefaultsIfNotSet()
  270.                             ->children()
  271.                                 ->arrayNode('pagination')
  272.                                     ->canBeDisabled()
  273.                                 ->end()
  274.                             ->end()
  275.                         ->end()
  276.                     ->end()
  277.                 ->end()
  278.             ->end();
  279.     }
  280.     private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
  281.     {
  282.         $defaultVersions = [23];
  283.         $rootNode
  284.             ->children()
  285.                 ->arrayNode('swagger')
  286.                     ->addDefaultsIfNotSet()
  287.                     ->children()
  288.                         ->arrayNode('versions')
  289.                             ->info('The active versions of Open API to be exported or used in the swagger_ui. The first value is the default.')
  290.                             ->defaultValue($defaultVersions)
  291.                             ->beforeNormalization()
  292.                                 ->always(static function ($v) {
  293.                                     if (!\is_array($v)) {
  294.                                         $v = [$v];
  295.                                     }
  296.                                     foreach ($v as &$version) {
  297.                                         $version = (int) $version;
  298.                                     }
  299.                                     return $v;
  300.                                 })
  301.                             ->end()
  302.                             ->validate()
  303.                                 ->ifTrue(static function ($v) use ($defaultVersions) {
  304.                                     return $v !== array_intersect($v$defaultVersions);
  305.                                 })
  306.                                 ->thenInvalid(sprintf('Only the versions %s are supported. Got %s.'implode(' and '$defaultVersions), '%s'))
  307.                             ->end()
  308.                             ->prototype('scalar')->end()
  309.                         ->end()
  310.                         ->arrayNode('api_keys')
  311.                             ->prototype('array')
  312.                                 ->children()
  313.                                     ->scalarNode('name')
  314.                                         ->info('The name of the header or query parameter containing the api key.')
  315.                                     ->end()
  316.                                     ->enumNode('type')
  317.                                         ->info('Whether the api key should be a query parameter or a header.')
  318.                                         ->values(['query''header'])
  319.                                     ->end()
  320.                                 ->end()
  321.                             ->end()
  322.                         ->end()
  323.                     ->end()
  324.                 ->end()
  325.             ->end();
  326.     }
  327.     private function addHttpCacheSection(ArrayNodeDefinition $rootNode): void
  328.     {
  329.         $rootNode
  330.             ->children()
  331.                 ->arrayNode('http_cache')
  332.                     ->addDefaultsIfNotSet()
  333.                     ->children()
  334.                         ->booleanNode('etag')
  335.                             ->setDeprecated(...$this->buildDeprecationArgs('2.6''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.'))
  336.                             ->defaultTrue()
  337.                             ->info('Automatically generate etags for API responses.')
  338.                         ->end()
  339.                         ->integerNode('max_age')
  340.                             ->setDeprecated(...$this->buildDeprecationArgs('2.6''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.'))
  341.                             ->defaultNull()
  342.                             ->info('Default value for the response max age.')
  343.                         ->end()
  344.                         ->integerNode('shared_max_age')
  345.                             ->setDeprecated(...$this->buildDeprecationArgs('2.6''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.'))
  346.                             ->defaultNull()
  347.                             ->info('Default value for the response shared (proxy) max age.')
  348.                         ->end()
  349.                         ->arrayNode('vary')
  350.                             ->setDeprecated(...$this->buildDeprecationArgs('2.6''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.'))
  351.                             ->defaultValue(['Accept'])
  352.                             ->prototype('scalar')->end()
  353.                             ->info('Default values of the "Vary" HTTP header.')
  354.                         ->end()
  355.                         ->booleanNode('public')->defaultNull()->info('To make all responses public by default.')->end()
  356.                         ->arrayNode('invalidation')
  357.                             ->info('Enable the tags-based cache invalidation system.')
  358.                             ->canBeEnabled()
  359.                             ->children()
  360.                                 ->arrayNode('varnish_urls')
  361.                                     ->defaultValue([])
  362.                                     ->prototype('scalar')->end()
  363.                                     ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
  364.                                 ->end()
  365.                                 ->integerNode('max_header_length')
  366.                                     ->defaultValue(7500)
  367.                                     ->info('Max header length supported by the server')
  368.                                 ->end()
  369.                                 ->variableNode('request_options')
  370.                                     ->defaultValue([])
  371.                                     ->validate()
  372.                                         ->ifTrue(static function ($v) { return false === \is_array($v); })
  373.                                         ->thenInvalid('The request_options parameter must be an array.')
  374.                                     ->end()
  375.                                     ->info('To pass options to the client charged with the request.')
  376.                                 ->end()
  377.                             ->end()
  378.                         ->end()
  379.                     ->end()
  380.                 ->end()
  381.             ->end();
  382.     }
  383.     private function addMercureSection(ArrayNodeDefinition $rootNode): void
  384.     {
  385.         $rootNode
  386.             ->children()
  387.                 ->arrayNode('mercure')
  388.                     ->{class_exists(MercureBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  389.                     ->children()
  390.                         ->scalarNode('hub_url')
  391.                             ->defaultNull()
  392.                             ->info('The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle\'s default hub.')
  393.                         ->end()
  394.                     ->end()
  395.                 ->end()
  396.             ->end();
  397.     }
  398.     private function addMessengerSection(ArrayNodeDefinition $rootNode): void
  399.     {
  400.         $rootNode
  401.             ->children()
  402.                 ->arrayNode('messenger')
  403.                     ->{!class_exists(FullStack::class) && interface_exists(MessageBusInterface::class) ? 'canBeDisabled' 'canBeEnabled'}()
  404.                 ->end()
  405.             ->end();
  406.     }
  407.     private function addElasticsearchSection(ArrayNodeDefinition $rootNode): void
  408.     {
  409.         $rootNode
  410.             ->children()
  411.                 ->arrayNode('elasticsearch')
  412.                     ->canBeEnabled()
  413.                     ->addDefaultsIfNotSet()
  414.                     ->children()
  415.                         ->booleanNode('enabled')
  416.                             ->defaultFalse()
  417.                             ->validate()
  418.                                 ->ifTrue()
  419.                                 ->then(static function (bool $v): bool {
  420.                                     if (!class_exists(ElasticsearchClient::class)) {
  421.                                         throw new InvalidConfigurationException('The elasticsearch/elasticsearch package is required for Elasticsearch support.');
  422.                                     }
  423.                                     return $v;
  424.                                 })
  425.                             ->end()
  426.                         ->end()
  427.                         ->arrayNode('hosts')
  428.                             ->beforeNormalization()->castToArray()->end()
  429.                             ->defaultValue([])
  430.                             ->prototype('scalar')->end()
  431.                         ->end()
  432.                         ->arrayNode('mapping')
  433.                             ->normalizeKeys(false)
  434.                             ->useAttributeAsKey('resource_class')
  435.                             ->prototype('array')
  436.                                 ->children()
  437.                                     ->scalarNode('index')->defaultNull()->end()
  438.                                     ->scalarNode('type')->defaultValue(DocumentMetadata::DEFAULT_TYPE)->end()
  439.                                 ->end()
  440.                             ->end()
  441.                         ->end()
  442.                     ->end()
  443.                 ->end()
  444.             ->end();
  445.     }
  446.     private function addOpenApiSection(ArrayNodeDefinition $rootNode): void
  447.     {
  448.         $rootNode
  449.             ->children()
  450.                 ->arrayNode('openapi')
  451.                     ->addDefaultsIfNotSet()
  452.                         ->children()
  453.                         ->arrayNode('contact')
  454.                         ->addDefaultsIfNotSet()
  455.                             ->children()
  456.                                 ->scalarNode('name')->defaultNull()->info('The identifying name of the contact person/organization.')->end()
  457.                                 ->scalarNode('url')->defaultNull()->info('The URL pointing to the contact information. MUST be in the format of a URL.')->end()
  458.                                 ->scalarNode('email')->defaultNull()->info('The email address of the contact person/organization. MUST be in the format of an email address.')->end()
  459.                             ->end()
  460.                         ->end()
  461.                         ->booleanNode('backward_compatibility_layer')->defaultTrue()->info('Enable this to decorate the "api_platform.swagger.normalizer.documentation" instead of decorating the OpenAPI factory.')->end()
  462.                         ->scalarNode('termsOfService')->defaultNull()->info('A URL to the Terms of Service for the API. MUST be in the format of a URL.')->end()
  463.                         ->arrayNode('license')
  464.                         ->addDefaultsIfNotSet()
  465.                             ->children()
  466.                                 ->scalarNode('name')->defaultNull()->info('The license name used for the API.')->end()
  467.                                 ->scalarNode('url')->defaultNull()->info('URL to the license used for the API. MUST be in the format of a URL.')->end()
  468.                             ->end()
  469.                         ->end()
  470.                     ->end()
  471.                 ->end()
  472.             ->end();
  473.     }
  474.     /**
  475.      * @throws InvalidConfigurationException
  476.      */
  477.     private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode): void
  478.     {
  479.         $rootNode
  480.             ->children()
  481.                 ->arrayNode('exception_to_status')
  482.                     ->defaultValue([
  483.                         SerializerExceptionInterface::class => Response::HTTP_BAD_REQUEST,
  484.                         InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
  485.                         FilterValidationException::class => Response::HTTP_BAD_REQUEST,
  486.                         OptimisticLockException::class => Response::HTTP_CONFLICT,
  487.                     ])
  488.                     ->info('The list of exceptions mapped to their HTTP status code.')
  489.                     ->normalizeKeys(false)
  490.                     ->useAttributeAsKey('exception_class')
  491.                     ->beforeNormalization()
  492.                         ->ifArray()
  493.                         ->then(static function (array $exceptionToStatus) {
  494.                             foreach ($exceptionToStatus as &$httpStatusCode) {
  495.                                 if (\is_int($httpStatusCode)) {
  496.                                     continue;
  497.                                 }
  498.                                 if (\defined($httpStatusCodeConstant sprintf('%s::%s'Response::class, $httpStatusCode))) {
  499.                                     @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").'$httpStatusCodeResponse::class, $httpStatusCodeConstant), \E_USER_DEPRECATED);
  500.                                     $httpStatusCode = \constant($httpStatusCodeConstant);
  501.                                 }
  502.                             }
  503.                             return $exceptionToStatus;
  504.                         })
  505.                     ->end()
  506.                     ->prototype('integer')->end()
  507.                     ->validate()
  508.                         ->ifArray()
  509.                         ->then(static function (array $exceptionToStatus) {
  510.                             foreach ($exceptionToStatus as $httpStatusCode) {
  511.                                 if ($httpStatusCode 100 || $httpStatusCode >= 600) {
  512.                                     throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.'$httpStatusCode));
  513.                                 }
  514.                             }
  515.                             return $exceptionToStatus;
  516.                         })
  517.                     ->end()
  518.                 ->end()
  519.             ->end();
  520.     }
  521.     private function addFormatSection(ArrayNodeDefinition $rootNodestring $key, array $defaultValue): void
  522.     {
  523.         $rootNode
  524.             ->children()
  525.                 ->arrayNode($key)
  526.                     ->defaultValue($defaultValue)
  527.                     ->info('The list of enabled formats. The first one will be the default.')
  528.                     ->normalizeKeys(false)
  529.                     ->useAttributeAsKey('format')
  530.                     ->beforeNormalization()
  531.                         ->ifArray()
  532.                         ->then(static function ($v) {
  533.                             foreach ($v as $format => $value) {
  534.                                 if (isset($value['mime_types'])) {
  535.                                     continue;
  536.                                 }
  537.                                 $v[$format] = ['mime_types' => $value];
  538.                             }
  539.                             return $v;
  540.                         })
  541.                     ->end()
  542.                     ->prototype('array')
  543.                         ->children()
  544.                             ->arrayNode('mime_types')->prototype('scalar')->end()->end()
  545.                         ->end()
  546.                     ->end()
  547.                 ->end()
  548.             ->end();
  549.     }
  550.     private function addDefaultsSection(ArrayNodeDefinition $rootNode): void
  551.     {
  552.         $nameConverter = new CamelCaseToSnakeCaseNameConverter();
  553.         $defaultsNode $rootNode->children()->arrayNode('defaults');
  554.         $defaultsNode
  555.             ->ignoreExtraKeys()
  556.             ->beforeNormalization()
  557.             ->always(static function (array $defaults) use ($nameConverter) {
  558.                 $normalizedDefaults = [];
  559.                 foreach ($defaults as $option => $value) {
  560.                     $option $nameConverter->normalize($option);
  561.                     $normalizedDefaults[$option] = $value;
  562.                 }
  563.                 return $normalizedDefaults;
  564.             });
  565.         [$publicProperties$configurableAttributes] = ApiResource::getConfigMetadata();
  566.         foreach (array_merge($publicProperties$configurableAttributes) as $attribute => $_) {
  567.             $snakeCased $nameConverter->normalize($attribute);
  568.             $defaultsNode->children()->variableNode($snakeCased);
  569.         }
  570.     }
  571.     private function buildDeprecationArgs(string $versionstring $message): array
  572.     {
  573.         return method_exists(BaseNode::class, 'getDeprecation')
  574.             ? ['api-platform/core'$version$message]
  575.             : [$message];
  576.     }
  577. }