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

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <[email protected]>
  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\Core\Annotation\ApiResource as LegacyApiResource;
  13. use ApiPlatform\Doctrine\Common\Filter\OrderFilterInterface;
  14. use ApiPlatform\Elasticsearch\Metadata\Document\DocumentMetadata;
  15. use ApiPlatform\Exception\FilterValidationException;
  16. use ApiPlatform\Exception\InvalidArgumentException;
  17. use ApiPlatform\Metadata\ApiResource;
  18. use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
  19. use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
  20. use Doctrine\ORM\EntityManagerInterface;
  21. use Doctrine\ORM\OptimisticLockException;
  22. use Elasticsearch\Client as ElasticsearchClient;
  23. use FOS\UserBundle\FOSUserBundle;
  24. use GraphQL\GraphQL;
  25. use Symfony\Bundle\FullStack;
  26. use Symfony\Bundle\MakerBundle\MakerBundle;
  27. use Symfony\Bundle\MercureBundle\MercureBundle;
  28. use Symfony\Bundle\TwigBundle\TwigBundle;
  29. use Symfony\Component\Config\Definition\BaseNode;
  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 <[email protected]>
  42.  * @author Baptiste Meyer <[email protected]>
  43.  */
  44. final class Configuration implements ConfigurationInterface
  45. {
  46.     /**
  47.      * {@inheritdoc}
  48.      */
  49.     public function getConfigTreeBuilder(): TreeBuilder
  50.     {
  51.         if (method_exists(TreeBuilder::class, 'getRootNode')) {
  52.             $treeBuilder = new TreeBuilder('api_platform');
  53.             $rootNode $treeBuilder->getRootNode();
  54.         } else {
  55.             $treeBuilder = new TreeBuilder();
  56.             $rootNode $treeBuilder->root('api_platform');
  57.         }
  58.         $rootNode
  59.             ->beforeNormalization()
  60.                 ->ifTrue(static function ($v) {
  61.                     return false === ($v['enable_swagger'] ?? null);
  62.                 })
  63.                 ->then(static function ($v) {
  64.                     $v['swagger']['versions'] = [];
  65.                     return $v;
  66.                 })
  67.             ->end()
  68.             ->children()
  69.                 ->scalarNode('title')
  70.                     ->info('The title of the API.')
  71.                     ->cannotBeEmpty()
  72.                     ->defaultValue('')
  73.                 ->end()
  74.                 ->scalarNode('description')
  75.                     ->info('The description of the API.')
  76.                     ->cannotBeEmpty()
  77.                     ->defaultValue('')
  78.                 ->end()
  79.                 ->scalarNode('version')
  80.                     ->info('The version of the API.')
  81.                     ->cannotBeEmpty()
  82.                     ->defaultValue('0.0.0')
  83.                 ->end()
  84.                 ->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end()
  85.                 ->booleanNode('metadata_backward_compatibility_layer')->defaultTrue()->info('If true, declared services are using legacy interfaces for the following services: "api_platform.iri_converter", "api_platform.openapi.factory", "api_platform.identifiers_extractor".')->end()
  86.                 ->scalarNode('default_operation_path_resolver')
  87.                     ->defaultValue('api_platform.operation_path_resolver.underscore')
  88.                     ->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.'))
  89.                     ->info('Specify the default operation path resolver to use for generating resources operations path.')
  90.                 ->end()
  91.                 ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
  92.                 ->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end()
  93.                 ->scalarNode('path_segment_name_generator')->defaultValue('api_platform.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()
  94.                 ->booleanNode('allow_plain_identifiers')
  95.                     ->defaultFalse()
  96.                     ->info('Allow plain identifiers, for example "id" instead of "@id" when denormalizing a relation.')
  97.                     ->setDeprecated(...$this->buildDeprecationArgs('2.7''The use of `allow_plain_identifiers` has been deprecated in 2.7 and will be removed in 3.0.'))
  98.                 ->end()
  99.                 ->arrayNode('validator')
  100.                     ->addDefaultsIfNotSet()
  101.                     ->children()
  102.                         ->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()
  103.                         ->booleanNode('query_parameter_validation')->defaultValue(true)->end()
  104.                     ->end()
  105.                 ->end()
  106.                 ->arrayNode('eager_loading')
  107.                     ->canBeDisabled()
  108.                     ->addDefaultsIfNotSet()
  109.                     ->children()
  110.                         ->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()
  111.                         ->integerNode('max_joins')->defaultValue(30)->info('Max number of joined relations before EagerLoading throws a RuntimeException')->end()
  112.                         ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end()
  113.                     ->end()
  114.                 ->end()
  115.                 ->booleanNode('enable_fos_user')
  116.                     ->defaultValue(class_exists(FOSUserBundle::class))
  117.                     ->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.'))
  118.                     ->info('Enable the FOSUserBundle integration.')
  119.                 ->end()
  120.                 ->booleanNode('enable_nelmio_api_doc')
  121.                     ->defaultFalse()
  122.                     ->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.'))
  123.                     ->info('Enable the NelmioApiDocBundle integration.')
  124.                 ->end()
  125.                 ->booleanNode('enable_swagger')->defaultTrue()->info('Enable the Swagger documentation and export.')->end()
  126.                 ->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger UI')->end()
  127.                 ->booleanNode('enable_re_doc')->defaultValue(class_exists(TwigBundle::class))->info('Enable ReDoc')->end()
  128.                 ->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
  129.                 ->booleanNode('enable_docs')->defaultTrue()->info('Enable the docs')->end()
  130.                 ->booleanNode('enable_profiler')->defaultTrue()->info('Enable the data collector and the WebProfilerBundle integration.')->end()
  131.                 ->arrayNode('collection')
  132.                     ->addDefaultsIfNotSet()
  133.                     ->children()
  134.                         ->scalarNode('exists_parameter_name')->defaultValue('exists')->cannotBeEmpty()->info('The name of the query parameter to filter on nullable field values.')->end()
  135.                         ->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
  136.                         ->scalarNode('order_parameter_name')->defaultValue('order')->cannotBeEmpty()->info('The name of the query parameter to order results.')->end()
  137.                         ->enumNode('order_nulls_comparison')->defaultNull()->values(array_merge(array_keys(OrderFilterInterface::NULLS_DIRECTION_MAP), [null]))->info('The nulls comparison strategy.')->end()
  138.                         ->arrayNode('pagination')
  139.                             ->canBeDisabled()
  140.                             ->addDefaultsIfNotSet()
  141.                             ->children()
  142.                                 ->booleanNode('enabled')
  143.                                     ->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.'))
  144.                                     ->defaultTrue()
  145.                                     ->info('To enable or disable pagination for all resource collections by default.')
  146.                                 ->end()
  147.                                 ->booleanNode('partial')
  148.                                     ->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.'))
  149.                                     ->defaultFalse()
  150.                                     ->info('To enable or disable partial pagination for all resource collections by default when pagination is enabled.')
  151.                                 ->end()
  152.                                 ->booleanNode('client_enabled')
  153.                                     ->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.'))
  154.                                     ->defaultFalse()
  155.                                     ->info('To allow the client to enable or disable the pagination.')
  156.                                 ->end()
  157.                                 ->booleanNode('client_items_per_page')
  158.                                     ->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.'))
  159.                                     ->defaultFalse()
  160.                                     ->info('To allow the client to set the number of items per page.')
  161.                                 ->end()
  162.                                 ->booleanNode('client_partial')
  163.                                     ->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.'))
  164.                                     ->defaultFalse()
  165.                                     ->info('To allow the client to enable or disable partial pagination.')
  166.                                 ->end()
  167.                                 ->integerNode('items_per_page')
  168.                                     ->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.'))
  169.                                     ->defaultValue(30)
  170.                                     ->info('The default number of items per page.')
  171.                                 ->end()
  172.                                 ->integerNode('maximum_items_per_page')
  173.                                     ->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.'))
  174.                                     ->defaultNull()
  175.                                     ->info('The maximum number of items per page.')
  176.                                 ->end()
  177.                                 ->scalarNode('page_parameter_name')->defaultValue('page')->cannotBeEmpty()->info('The default name of the parameter handling the page number.')->end()
  178.                                 ->scalarNode('enabled_parameter_name')->defaultValue('pagination')->cannotBeEmpty()->info('The name of the query parameter to enable or disable pagination.')->end()
  179.                                 ->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()
  180.                                 ->scalarNode('partial_parameter_name')->defaultValue('partial')->cannotBeEmpty()->info('The name of the query parameter to enable or disable partial pagination.')->end()
  181.                             ->end()
  182.                         ->end()
  183.                     ->end()
  184.                 ->end()
  185.                 ->arrayNode('mapping')
  186.                     ->addDefaultsIfNotSet()
  187.                     ->children()
  188.                         ->arrayNode('paths')
  189.                             ->prototype('scalar')->end()
  190.                         ->end()
  191.                     ->end()
  192.                 ->end()
  193.                 ->arrayNode('resource_class_directories')
  194.                     ->prototype('scalar')->end()
  195.                 ->end()
  196.             ->end();
  197.         $this->addDoctrineOrmSection($rootNode);
  198.         $this->addDoctrineMongoDbOdmSection($rootNode);
  199.         $this->addOAuthSection($rootNode);
  200.         $this->addGraphQlSection($rootNode);
  201.         $this->addSwaggerSection($rootNode);
  202.         $this->addHttpCacheSection($rootNode);
  203.         $this->addMercureSection($rootNode);
  204.         $this->addMessengerSection($rootNode);
  205.         $this->addElasticsearchSection($rootNode);
  206.         $this->addOpenApiSection($rootNode);
  207.         $this->addMakerSection($rootNode);
  208.         $this->addExceptionToStatusSection($rootNode);
  209.         $this->addFormatSection($rootNode'formats', [
  210.             'jsonld' => ['mime_types' => ['application/ld+json']],
  211.             'json' => ['mime_types' => ['application/json']], // Swagger support
  212.             'html' => ['mime_types' => ['text/html']], // Swagger UI support
  213.         ]);
  214.         $this->addFormatSection($rootNode'patch_formats', []);
  215.         $this->addFormatSection($rootNode'error_formats', [
  216.             'jsonproblem' => ['mime_types' => ['application/problem+json']],
  217.             'jsonld' => ['mime_types' => ['application/ld+json']],
  218.         ]);
  219.         $this->addDefaultsSection($rootNode);
  220.         return $treeBuilder;
  221.     }
  222.     private function addDoctrineOrmSection(ArrayNodeDefinition $rootNode): void
  223.     {
  224.         $rootNode
  225.             ->children()
  226.                 ->arrayNode('doctrine')
  227.                     ->{class_exists(DoctrineBundle::class) && interface_exists(EntityManagerInterface::class) ? 'canBeDisabled' 'canBeEnabled'}()
  228.                 ->end()
  229.             ->end();
  230.     }
  231.     private function addDoctrineMongoDbOdmSection(ArrayNodeDefinition $rootNode): void
  232.     {
  233.         $rootNode
  234.             ->children()
  235.                 ->arrayNode('doctrine_mongodb_odm')
  236.                     ->{class_exists(DoctrineMongoDBBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  237.                 ->end()
  238.             ->end();
  239.     }
  240.     private function addOAuthSection(ArrayNodeDefinition $rootNode): void
  241.     {
  242.         $rootNode
  243.             ->children()
  244.                 ->arrayNode('oauth')
  245.                     ->canBeEnabled()
  246.                     ->addDefaultsIfNotSet()
  247.                     ->children()
  248.                         ->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
  249.                         ->scalarNode('clientSecret')
  250.                             ->defaultValue('')
  251.                             ->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')
  252.                         ->end()
  253.                         ->booleanNode('pkce')->defaultFalse()->info('Enable the oauth PKCE.')->end()
  254.                         ->scalarNode('type')->defaultValue('oauth2')->info('The oauth type.')->end()
  255.                         ->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
  256.                         ->scalarNode('tokenUrl')->defaultValue('')->info('The oauth token url.')->end()
  257.                         ->scalarNode('authorizationUrl')->defaultValue('')->info('The oauth authentication url.')->end()
  258.                         ->scalarNode('refreshUrl')->defaultValue('')->info('The oauth refresh url.')->end()
  259.                         ->arrayNode('scopes')
  260.                             ->prototype('scalar')->end()
  261.                         ->end()
  262.                     ->end()
  263.                 ->end()
  264.             ->end();
  265.     }
  266.     private function addGraphQlSection(ArrayNodeDefinition $rootNode): void
  267.     {
  268.         $rootNode
  269.             ->children()
  270.                 ->arrayNode('graphql')
  271.                     ->{class_exists(GraphQL::class) ? 'canBeDisabled' 'canBeEnabled'}()
  272.                     ->addDefaultsIfNotSet()
  273.                     ->children()
  274.                         ->scalarNode('default_ide')->defaultValue('graphiql')->end()
  275.                         ->arrayNode('graphiql')
  276.                             ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  277.                         ->end()
  278.                         ->arrayNode('graphql_playground')
  279.                             ->{class_exists(GraphQL::class) && class_exists(TwigBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  280.                         ->end()
  281.                         ->scalarNode('nesting_separator')->defaultValue('_')->info('The separator to use to filter nested fields.')->end()
  282.                         ->arrayNode('collection')
  283.                             ->addDefaultsIfNotSet()
  284.                             ->children()
  285.                                 ->arrayNode('pagination')
  286.                                     ->canBeDisabled()
  287.                                 ->end()
  288.                             ->end()
  289.                         ->end()
  290.                     ->end()
  291.                 ->end()
  292.             ->end();
  293.     }
  294.     private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
  295.     {
  296.         $defaultVersions = [23];
  297.         $rootNode
  298.             ->children()
  299.                 ->arrayNode('swagger')
  300.                     ->addDefaultsIfNotSet()
  301.                     ->children()
  302.                         ->arrayNode('versions')
  303.                             ->info('The active versions of Open API to be exported or used in the swagger_ui. The first value is the default.')
  304.                             ->defaultValue($defaultVersions)
  305.                             ->beforeNormalization()
  306.                                 ->always(static function ($v) {
  307.                                     if (!\is_array($v)) {
  308.                                         $v = [$v];
  309.                                     }
  310.                                     foreach ($v as &$version) {
  311.                                         $version = (int) $version;
  312.                                     }
  313.                                     return $v;
  314.                                 })
  315.                             ->end()
  316.                             ->validate()
  317.                                 ->ifTrue(static function ($v) use ($defaultVersions) {
  318.                                     return $v !== array_intersect($v$defaultVersions);
  319.                                 })
  320.                                 ->thenInvalid(sprintf('Only the versions %s are supported. Got %s.'implode(' and '$defaultVersions), '%s'))
  321.                             ->end()
  322.                             ->prototype('scalar')->end()
  323.                         ->end()
  324.                         ->arrayNode('api_keys')
  325.                             ->prototype('array')
  326.                                 ->children()
  327.                                     ->scalarNode('name')
  328.                                         ->info('The name of the header or query parameter containing the api key.')
  329.                                     ->end()
  330.                                     ->enumNode('type')
  331.                                         ->info('Whether the api key should be a query parameter or a header.')
  332.                                         ->values(['query''header'])
  333.                                     ->end()
  334.                                 ->end()
  335.                             ->end()
  336.                         ->end()
  337.                         ->variableNode('swagger_ui_extra_configuration')
  338.                             ->defaultValue([])
  339.                             ->validate()
  340.                                 ->ifTrue(static function ($v) { return false === \is_array($v); })
  341.                                 ->thenInvalid('The swagger_ui_extra_configuration parameter must be an array.')
  342.                             ->end()
  343.                             ->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
  344.                         ->end()
  345.                     ->end()
  346.                 ->end()
  347.             ->end();
  348.     }
  349.     private function addHttpCacheSection(ArrayNodeDefinition $rootNode): void
  350.     {
  351.         $rootNode
  352.             ->children()
  353.                 ->arrayNode('http_cache')
  354.                     ->addDefaultsIfNotSet()
  355.                     ->children()
  356.                         ->booleanNode('etag')
  357.                             ->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.'))
  358.                             ->defaultTrue()
  359.                             ->info('Automatically generate etags for API responses.')
  360.                         ->end()
  361.                         ->integerNode('max_age')
  362.                             ->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.'))
  363.                             ->defaultNull()
  364.                             ->info('Default value for the response max age.')
  365.                         ->end()
  366.                         ->integerNode('shared_max_age')
  367.                             ->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.'))
  368.                             ->defaultNull()
  369.                             ->info('Default value for the response shared (proxy) max age.')
  370.                         ->end()
  371.                         ->arrayNode('vary')
  372.                             ->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.'))
  373.                             ->defaultValue(['Accept'])
  374.                             ->prototype('scalar')->end()
  375.                             ->info('Default values of the "Vary" HTTP header.')
  376.                         ->end()
  377.                         ->booleanNode('public')->defaultNull()->info('To make all responses public by default.')->end()
  378.                         ->arrayNode('invalidation')
  379.                             ->info('Enable the tags-based cache invalidation system.')
  380.                             ->canBeEnabled()
  381.                             ->children()
  382.                                 ->arrayNode('varnish_urls')
  383.                                     ->defaultValue([])
  384.                                     ->prototype('scalar')->end()
  385.                                     ->info('URLs of the Varnish servers to purge using cache tags when a resource is updated.')
  386.                                 ->end()
  387.                                 ->integerNode('max_header_length')
  388.                                     ->defaultValue(7500)
  389.                                     ->info('Max header length supported by the server')
  390.                                 ->end()
  391.                                 ->variableNode('request_options')
  392.                                     ->defaultValue([])
  393.                                     ->validate()
  394.                                         ->ifTrue(static function ($v) { return false === \is_array($v); })
  395.                                         ->thenInvalid('The request_options parameter must be an array.')
  396.                                     ->end()
  397.                                     ->info('To pass options to the client charged with the request.')
  398.                                 ->end()
  399.                                 ->scalarNode('purger')
  400.                                     ->defaultValue('api_platform.http_cache.purger.varnish')
  401.                                     ->info('Specify a varnish purger to use (available values: "api_platform.http_cache.purger.varnish.ban" or "api_platform.http_cache.purger.varnish.xkey").')
  402.                                 ->end()
  403.                                 ->arrayNode('xkey')
  404.                                     ->addDefaultsIfNotSet()
  405.                                     ->children()
  406.                                         ->scalarNode('glue')
  407.                                         ->defaultValue(' ')
  408.                                         ->info('xkey glue between keys')
  409.                                         ->end()
  410.                                     ->end()
  411.                                 ->end()
  412.                             ->end()
  413.                         ->end()
  414.                     ->end()
  415.                 ->end()
  416.             ->end();
  417.     }
  418.     private function addMercureSection(ArrayNodeDefinition $rootNode): void
  419.     {
  420.         $rootNode
  421.             ->children()
  422.                 ->arrayNode('mercure')
  423.                     ->{class_exists(MercureBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  424.                     ->children()
  425.                         ->scalarNode('hub_url')
  426.                             ->defaultNull()
  427.                             ->info('The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle\'s default hub.')
  428.                         ->end()
  429.                     ->end()
  430.                 ->end()
  431.             ->end();
  432.     }
  433.     private function addMessengerSection(ArrayNodeDefinition $rootNode): void
  434.     {
  435.         $rootNode
  436.             ->children()
  437.                 ->arrayNode('messenger')
  438.                     ->{!class_exists(FullStack::class) && interface_exists(MessageBusInterface::class) ? 'canBeDisabled' 'canBeEnabled'}()
  439.                 ->end()
  440.             ->end();
  441.     }
  442.     private function addElasticsearchSection(ArrayNodeDefinition $rootNode): void
  443.     {
  444.         $rootNode
  445.             ->children()
  446.                 ->arrayNode('elasticsearch')
  447.                     ->canBeEnabled()
  448.                     ->addDefaultsIfNotSet()
  449.                     ->children()
  450.                         ->booleanNode('enabled')
  451.                             ->defaultFalse()
  452.                             ->validate()
  453.                                 ->ifTrue()
  454.                                 ->then(static function (bool $v): bool {
  455.                                     if (!class_exists(ElasticsearchClient::class)) {
  456.                                         throw new InvalidConfigurationException('The elasticsearch/elasticsearch package is required for Elasticsearch support.');
  457.                                     }
  458.                                     return $v;
  459.                                 })
  460.                             ->end()
  461.                         ->end()
  462.                         ->arrayNode('hosts')
  463.                             ->beforeNormalization()->castToArray()->end()
  464.                             ->defaultValue([])
  465.                             ->prototype('scalar')->end()
  466.                         ->end()
  467.                         ->arrayNode('mapping')
  468.                             ->normalizeKeys(false)
  469.                             ->useAttributeAsKey('resource_class')
  470.                             ->prototype('array')
  471.                                 ->children()
  472.                                     ->scalarNode('index')->defaultNull()->end()
  473.                                     ->scalarNode('type')->defaultValue(DocumentMetadata::DEFAULT_TYPE)->end()
  474.                                 ->end()
  475.                             ->end()
  476.                         ->end()
  477.                     ->end()
  478.                 ->end()
  479.             ->end();
  480.     }
  481.     private function addOpenApiSection(ArrayNodeDefinition $rootNode): void
  482.     {
  483.         $rootNode
  484.             ->children()
  485.                 ->arrayNode('openapi')
  486.                     ->addDefaultsIfNotSet()
  487.                         ->children()
  488.                         ->arrayNode('contact')
  489.                         ->addDefaultsIfNotSet()
  490.                             ->children()
  491.                                 ->scalarNode('name')->defaultNull()->info('The identifying name of the contact person/organization.')->end()
  492.                                 ->scalarNode('url')->defaultNull()->info('The URL pointing to the contact information. MUST be in the format of a URL.')->end()
  493.                                 ->scalarNode('email')->defaultNull()->info('The email address of the contact person/organization. MUST be in the format of an email address.')->end()
  494.                             ->end()
  495.                         ->end()
  496.                         ->booleanNode('backward_compatibility_layer')->defaultTrue()->info('Enable this to decorate the "api_platform.swagger.normalizer.documentation" instead of decorating the OpenAPI factory.')->end()
  497.                         ->scalarNode('termsOfService')->defaultNull()->info('A URL to the Terms of Service for the API. MUST be in the format of a URL.')->end()
  498.                         ->arrayNode('license')
  499.                         ->addDefaultsIfNotSet()
  500.                             ->children()
  501.                                 ->scalarNode('name')->defaultNull()->info('The license name used for the API.')->end()
  502.                                 ->scalarNode('url')->defaultNull()->info('URL to the license used for the API. MUST be in the format of a URL.')->end()
  503.                             ->end()
  504.                         ->end()
  505.                         ->variableNode('swagger_ui_extra_configuration')
  506.                             ->defaultValue([])
  507.                             ->validate()
  508.                                 ->ifTrue(static function ($v) { return false === \is_array($v); })
  509.                                 ->thenInvalid('The swagger_ui_extra_configuration parameter must be an array.')
  510.                             ->end()
  511.                             ->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
  512.                         ->end()
  513.                     ->end()
  514.                 ->end()
  515.             ->end();
  516.     }
  517.     /**
  518.      * @throws InvalidConfigurationException
  519.      */
  520.     private function addExceptionToStatusSection(ArrayNodeDefinition $rootNode): void
  521.     {
  522.         $rootNode
  523.             ->children()
  524.                 ->arrayNode('exception_to_status')
  525.                     ->defaultValue([
  526.                         SerializerExceptionInterface::class => Response::HTTP_BAD_REQUEST,
  527.                         InvalidArgumentException::class => Response::HTTP_BAD_REQUEST,
  528.                         FilterValidationException::class => Response::HTTP_BAD_REQUEST,
  529.                         OptimisticLockException::class => Response::HTTP_CONFLICT,
  530.                     ])
  531.                     ->info('The list of exceptions mapped to their HTTP status code.')
  532.                     ->normalizeKeys(false)
  533.                     ->useAttributeAsKey('exception_class')
  534.                     ->beforeNormalization()
  535.                         ->ifArray()
  536.                         ->then(static function (array $exceptionToStatus) {
  537.                             foreach ($exceptionToStatus as &$httpStatusCode) {
  538.                                 if (\is_int($httpStatusCode)) {
  539.                                     continue;
  540.                                 }
  541.                                 if (\defined($httpStatusCodeConstant sprintf('%s::%s'Response::class, $httpStatusCode))) {
  542.                                     @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);
  543.                                     $httpStatusCode \constant($httpStatusCodeConstant);
  544.                                 }
  545.                             }
  546.                             return $exceptionToStatus;
  547.                         })
  548.                     ->end()
  549.                     ->prototype('integer')->end()
  550.                     ->validate()
  551.                         ->ifArray()
  552.                         ->then(static function (array $exceptionToStatus) {
  553.                             foreach ($exceptionToStatus as $httpStatusCode) {
  554.                                 if ($httpStatusCode 100 || $httpStatusCode >= 600) {
  555.                                     throw new InvalidConfigurationException(sprintf('The HTTP status code "%s" is not valid.'$httpStatusCode));
  556.                                 }
  557.                             }
  558.                             return $exceptionToStatus;
  559.                         })
  560.                     ->end()
  561.                 ->end()
  562.             ->end();
  563.     }
  564.     private function addFormatSection(ArrayNodeDefinition $rootNodestring $key, array $defaultValue): void
  565.     {
  566.         $rootNode
  567.             ->children()
  568.                 ->arrayNode($key)
  569.                     ->defaultValue($defaultValue)
  570.                     ->info('The list of enabled formats. The first one will be the default.')
  571.                     ->normalizeKeys(false)
  572.                     ->useAttributeAsKey('format')
  573.                     ->beforeNormalization()
  574.                         ->ifArray()
  575.                         ->then(static function ($v) {
  576.                             foreach ($v as $format => $value) {
  577.                                 if (isset($value['mime_types'])) {
  578.                                     continue;
  579.                                 }
  580.                                 $v[$format] = ['mime_types' => $value];
  581.                             }
  582.                             return $v;
  583.                         })
  584.                     ->end()
  585.                     ->prototype('array')
  586.                         ->children()
  587.                             ->arrayNode('mime_types')->prototype('scalar')->end()->end()
  588.                         ->end()
  589.                     ->end()
  590.                 ->end()
  591.             ->end();
  592.     }
  593.     private function addDefaultsSection(ArrayNodeDefinition $rootNode): void
  594.     {
  595.         $nameConverter = new CamelCaseToSnakeCaseNameConverter();
  596.         $defaultsNode $rootNode->children()->arrayNode('defaults');
  597.         $defaultsNode
  598.             ->ignoreExtraKeys(false)
  599.             ->beforeNormalization()
  600.             ->always(static function (array $defaults) use ($nameConverter) {
  601.                 $normalizedDefaults = [];
  602.                 foreach ($defaults as $option => $value) {
  603.                     $option $nameConverter->normalize($option);
  604.                     $normalizedDefaults[$option] = $value;
  605.                 }
  606.                 return $normalizedDefaults;
  607.             });
  608.         // TODO: test defaults with things that are no in the constructor
  609.         if (class_exists(ApiResource::class)) {
  610.             $reflection = new \ReflectionClass(ApiResource::class);
  611.             foreach ($reflection->getConstructor()->getParameters() as $parameter) {
  612.                 $defaultsNode->children()->variableNode($nameConverter->normalize($parameter->getName()));
  613.             }
  614.             return;
  615.         }
  616.         [$publicProperties$configurableAttributes] = LegacyApiResource::getConfigMetadata();
  617.         foreach (array_merge($publicProperties$configurableAttributpies) as $attribute => $_) {
  618.             $snakeCased $nameConverter->normalize($attribute);
  619.             $defaultsNode->children()->variableNode($snakeCased);
  620.         }
  621.     }
  622.     private function addMakerSection(ArrayNodeDefinition $rootNode): void
  623.     {
  624.         $rootNode
  625.             ->children()
  626.                 ->arrayNode('maker')
  627.                     ->{class_exists(MakerBundle::class) ? 'canBeDisabled' 'canBeEnabled'}()
  628.                 ->end()
  629.             ->end();
  630.     }
  631.     private function buildDeprecationArgs(string $versionstring $message): array
  632.     {
  633.         return method_exists(BaseNode::class, 'getDeprecation')
  634.             ? ['api-platform/core'$version$message]
  635.             : [$message];
  636.     }
  637. }
  638. class_alias(Configuration::class, \ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Configuration::class);