- <?php
- /*
-  * This file is part of the FOSRestBundle package.
-  *
-  * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
-  *
-  * For the full copyright and license information, please view the LICENSE
-  * file that was distributed with this source code.
-  */
- namespace FOS\RestBundle\DependencyInjection;
- use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
- use Symfony\Component\Config\Definition\Builder\TreeBuilder;
- use Symfony\Component\Config\Definition\ConfigurationInterface;
- use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\OptionsResolver\OptionsResolver;
- use Symfony\Component\Serializer\Encoder\XmlEncoder;
- /**
-  * This class contains the configuration information for the bundle.
-  *
-  * This information is solely responsible for how the different configuration
-  * sections are normalized, and merged.
-  *
-  * @author Lukas Kahwe Smith <smith@pooteeweet.org>
-  *
-  * @internal
-  */
- final class Configuration implements ConfigurationInterface
- {
-     /**
-      * Default debug mode value.
-      *
-      * @var bool
-      */
-     private $debug;
-     public function __construct(bool $debug)
-     {
-         $this->debug = $debug;
-     }
-     public function getConfigTreeBuilder(): TreeBuilder
-     {
-         $treeBuilder = new TreeBuilder('fos_rest');
-         if (method_exists($treeBuilder, 'getRootNode')) {
-             $rootNode = $treeBuilder->getRootNode();
-         } else {
-             $rootNode = $treeBuilder->root('fos_rest');
-         }
-         $rootNode
-             ->children()
-                 ->scalarNode('disable_csrf_role')->defaultNull()->end()
-                 ->arrayNode('access_denied_listener')
-                     ->canBeEnabled()
-                     ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
-                     ->beforeNormalization()
-                         ->ifArray()->then(function ($v) {
-                             if (!empty($v) && empty($v['formats'])) {
-                                 unset($v['enabled']);
-                                 $v = ['enabled' => true, 'formats' => $v];
-                             }
-                             return $v;
-                         })
-                     ->end()
-                     ->fixXmlConfig('format', 'formats')
-                     ->children()
-                         ->scalarNode('service')->defaultNull()->end()
-                         ->arrayNode('formats')
-                             ->useAttributeAsKey('name')
-                             ->prototype('boolean')->end()
-                         ->end()
-                     ->end()
-                 ->end()
-                 ->scalarNode('unauthorized_challenge')->defaultNull()->end()
-                 ->arrayNode('param_fetcher_listener')
-                     ->beforeNormalization()
-                         ->ifString()
-                         ->then(function ($v) {
-                             return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
-                         })
-                     ->end()
-                     ->canBeEnabled()
-                     ->children()
-                         ->booleanNode('force')->defaultFalse()->end()
-                         ->scalarNode('service')->defaultNull()->end()
-                     ->end()
-                 ->end()
-                 ->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')->end()
-                 ->arrayNode('allowed_methods_listener')
-                     ->canBeEnabled()
-                     ->children()
-                         ->scalarNode('service')->defaultNull()->end()
-                     ->end()
-                 ->end()
-                 ->arrayNode('routing_loader')
-                     ->addDefaultsIfNotSet()
-                     ->beforeNormalization()
-                         ->ifTrue(function ($v) { return isset($v['enabled']) && false !== $v['enabled']; })
-                         ->then(function ($v) {
-                             @trigger_error('Enabling the route generation feature is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
-                             return $v;
-                         })
-                     ->end()
-                     ->beforeNormalization()
-                         ->ifTrue(function ($v) { return is_bool($v); })
-                         ->then(function ($v) {
-                             return [
-                                 'enabled' => $v,
-                             ];
-                         })
-                     ->end()
-                     ->children()
-                         ->booleanNode('enabled')
-                             ->defaultValue(function () {
-                                 @trigger_error('Enabling the route generation feature is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
-                                 return true;
-                             })
-                         ->end()
-                         ->scalarNode('default_format')->defaultNull()->end()
-                         ->scalarNode('prefix_methods')->defaultTrue()->end()
-                         ->scalarNode('include_format')->defaultTrue()->end()
-                     ->end()
-                 ->end()
-                 ->arrayNode('body_converter')
-                     ->canBeEnabled()
-                     ->children()
-                         ->scalarNode('validate')
-                             ->defaultFalse()
-                             ->beforeNormalization()
-                                 ->ifTrue()
-                                 ->then(function ($value) {
-                                     if (!class_exists(OptionsResolver::class)) {
-                                         throw new InvalidConfigurationException("'body_converter.validate: true' requires OptionsResolver component installation ( composer require symfony/options-resolver )");
-                                     }
-                                     return $value;
-                                 })
-                             ->end()
-                         ->end()
-                         ->scalarNode('validation_errors_argument')->defaultValue('validationErrors')->end()
-                     ->end()
-                 ->end()
-                 ->arrayNode('service')
-                     ->addDefaultsIfNotSet()
-                     ->children()
-                         ->scalarNode('router')->defaultValue('router')->setDeprecated('The "%path%.%node%" configuration key has been deprecated in FOSRestBundle 2.8.')->end()
-                         ->scalarNode('templating')
-                             ->defaultValue('templating')
-                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
-                         ->end()
-                         ->scalarNode('serializer')->defaultNull()->end()
-                         ->scalarNode('view_handler')->defaultValue('fos_rest.view_handler.default')->end()
-                         ->scalarNode('inflector')
-                             ->defaultValue('fos_rest.inflector.doctrine')
-                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
-                         ->end()
-                         ->scalarNode('validator')->defaultValue('validator')->end()
-                     ->end()
-                 ->end()
-                 ->arrayNode('serializer')
-                     ->addDefaultsIfNotSet()
-                     ->children()
-                         ->scalarNode('version')->defaultNull()->end()
-                         ->arrayNode('groups')
-                             ->prototype('scalar')->end()
-                         ->end()
-                         ->booleanNode('serialize_null')->defaultFalse()->end()
-                     ->end()
-                 ->end()
-                 ->arrayNode('zone')
-                     ->cannotBeOverwritten()
-                     ->prototype('array')
-                     ->fixXmlConfig('ip')
-                     ->children()
-                         ->scalarNode('path')
-                             ->defaultNull()
-                             ->info('use the urldecoded format')
-                             ->example('^/path to resource/')
-                         ->end()
-                         ->scalarNode('host')->defaultNull()->end()
-                         ->arrayNode('methods')
-                             ->beforeNormalization()->ifString()->then(function ($v) {
-                                 return preg_split('/\s*,\s*/', $v);
-                             })->end()
-                             ->prototype('scalar')->end()
-                         ->end()
-                         ->arrayNode('ips')
-                             ->beforeNormalization()->ifString()->then(function ($v) {
-                                 return [$v];
-                             })->end()
-                             ->prototype('scalar')->end()
-                         ->end()
-                     ->end()
-                 ->end()
-             ->end()
-         ->end();
-         $this->addViewSection($rootNode);
-         $this->addExceptionSection($rootNode);
-         $this->addBodyListenerSection($rootNode);
-         $this->addFormatListenerSection($rootNode);
-         $this->addVersioningSection($rootNode);
-         return $treeBuilder;
-     }
-     private function addViewSection(ArrayNodeDefinition $rootNode)
-     {
-         $rootNode
-             ->children()
-                 ->arrayNode('view')
-                     ->fixXmlConfig('format', 'formats')
-                     ->fixXmlConfig('mime_type', 'mime_types')
-                     ->fixXmlConfig('templating_format', 'templating_formats')
-                     ->fixXmlConfig('force_redirect', 'force_redirects')
-                     ->addDefaultsIfNotSet()
-                     ->children()
-                         ->scalarNode('default_engine')
-                             ->setDeprecated('The "%path%.%node%" option has been deprecated in FOSRestBundle 2.8.')
-                             ->defaultValue('twig')
-                         ->end()
-                         ->arrayNode('force_redirects')
-                             ->setDeprecated('The "%path%.%node%" option has been deprecated in FOSRestBundle 2.8.')
-                             ->useAttributeAsKey('name')
-                             ->defaultValue(['html' => true])
-                             ->prototype('boolean')->end()
-                         ->end()
-                         ->arrayNode('mime_types')
-                             ->canBeEnabled()
-                             ->beforeNormalization()
-                                 ->ifArray()->then(function ($v) {
-                                     if (!empty($v) && empty($v['formats'])) {
-                                         unset($v['enabled']);
-                                         $v = ['enabled' => true, 'formats' => $v];
-                                     }
-                                     return $v;
-                                 })
-                             ->end()
-                             ->fixXmlConfig('format', 'formats')
-                             ->children()
-                                 ->scalarNode('service')->defaultNull()->end()
-                                 ->arrayNode('formats')
-                                     ->useAttributeAsKey('name')
-                                     ->prototype('array')
-                                         ->beforeNormalization()
-                                             ->ifString()
-                                             ->then(function ($v) { return [$v]; })
-                                         ->end()
-                                         ->prototype('scalar')->end()
-                                     ->end()
-                                 ->end()
-                             ->end()
-                         ->end()
-                         ->arrayNode('formats')
-                             ->useAttributeAsKey('name')
-                             ->defaultValue(['json' => true, 'xml' => true])
-                             ->prototype('boolean')->end()
-                         ->end()
-                         ->arrayNode('templating_formats')
-                             ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in FOSRestBundle 2.8.')
-                             ->useAttributeAsKey('name')
-                             ->defaultValue(['html' => true])
-                             ->prototype('boolean')->end()
-                         ->end()
-                         ->arrayNode('view_response_listener')
-                             ->beforeNormalization()
-                                 ->ifString()
-                                 ->then(function ($v) {
-                                     return ['enabled' => in_array($v, ['force', 'true']), 'force' => 'force' === $v];
-                                 })
-                             ->end()
-                             ->canBeEnabled()
-                             ->children()
-                                 ->booleanNode('force')->defaultFalse()->end()
-                                 ->scalarNode('service')->defaultNull()->end()
-                             ->end()
-                         ->end()
-                         ->scalarNode('failed_validation')->defaultValue(Response::HTTP_BAD_REQUEST)->end()
-                         ->scalarNode('empty_content')->defaultValue(Response::HTTP_NO_CONTENT)->end()
-                         ->booleanNode('serialize_null')->defaultFalse()->end()
-                         ->arrayNode('jsonp_handler')
-                             ->canBeUnset()
-                             ->children()
-                                 ->scalarNode('callback_param')->defaultValue('callback')->end()
-                                 ->scalarNode('mime_type')->defaultValue('application/javascript+jsonp')->end()
-                             ->end()
-                         ->end()
-                     ->end()
-                 ->end()
-             ->end();
-     }
-     private function addBodyListenerSection(ArrayNodeDefinition $rootNode)
-     {
-         $decodersDefaultValue = ['json' => 'fos_rest.decoder.json'];
-         if (class_exists(XmlEncoder::class)) {
-             $decodersDefaultValue['xml'] = 'fos_rest.decoder.xml';
-         }
-         $rootNode
-             ->children()
-                 ->arrayNode('body_listener')
-                     ->fixXmlConfig('decoder', 'decoders')
-                     ->addDefaultsIfNotSet()
-                     ->canBeUnset()
-                     ->treatFalseLike(['enabled' => false])
-                     ->treatTrueLike(['enabled' => true])
-                     ->treatNullLike(['enabled' => true])
-                     ->children()
-                         ->booleanNode('enabled')
-                             ->defaultValue(function () {
-                                 @trigger_error('The body_listener config has been enabled by default and will be disabled by default in FOSRestBundle 3.0. Please enable or disable it explicitly.', E_USER_DEPRECATED);
-                                 return true;
-                             })
-                         ->end()
-                         ->scalarNode('service')->defaultNull()->end()
-                         ->scalarNode('default_format')->defaultNull()->end()
-                         ->booleanNode('throw_exception_on_unsupported_content_type')
-                             ->defaultFalse()
-                         ->end()
-                         ->arrayNode('decoders')
-                             ->useAttributeAsKey('name')
-                             ->defaultValue($decodersDefaultValue)
-                             ->prototype('scalar')->end()
-                         ->end()
-                         ->arrayNode('array_normalizer')
-                             ->addDefaultsIfNotSet()
-                             ->beforeNormalization()
-                                 ->ifString()->then(function ($v) {
-                                     return ['service' => $v];
-                                 })
-                             ->end()
-                             ->children()
-                                 ->scalarNode('service')->defaultNull()->end()
-                                 ->booleanNode('forms')->defaultFalse()->end()
-                             ->end()
-                         ->end()
-                     ->end()
-                 ->end()
-             ->end();
-     }
-     private function addFormatListenerSection(ArrayNodeDefinition $rootNode)
-     {
-         $rootNode
-             ->children()
-                 ->arrayNode('format_listener')
-                     ->fixXmlConfig('rule', 'rules')
-                     ->addDefaultsIfNotSet()
-                     ->canBeUnset()
-                     ->beforeNormalization()
-                         ->ifTrue(function ($v) {
-                             // check if we got an assoc array in rules
-                             return isset($v['rules'])
-                                 && is_array($v['rules'])
-                                 && array_keys($v['rules']) !== range(0, count($v['rules']) - 1);
-                         })
-                         ->then(function ($v) {
-                             $v['rules'] = [$v['rules']];
-                             return $v;
-                         })
-                     ->end()
-                     ->canBeEnabled()
-                     ->children()
-                         ->scalarNode('service')->defaultNull()->end()
-                         ->arrayNode('rules')
-                             ->performNoDeepMerging()
-                             ->prototype('array')
-                                 ->fixXmlConfig('priority', 'priorities')
-                                 ->fixXmlConfig('attribute', 'attributes')
-                                 ->children()
-                                     ->scalarNode('path')->defaultNull()->info('URL path info')->end()
-                                     ->scalarNode('host')->defaultNull()->info('URL host name')->end()
-                                     ->variableNode('methods')->defaultNull()->info('Method for URL')->end()
-                                     ->arrayNode('attributes')
-                                         ->useAttributeAsKey('name')
-                                         ->prototype('variable')->end()
-                                     ->end()
-                                     ->booleanNode('stop')->defaultFalse()->end()
-                                     ->booleanNode('prefer_extension')->defaultTrue()->end()
-                                     ->scalarNode('fallback_format')->defaultValue('html')->end()
-                                     ->arrayNode('priorities')
-                                         ->beforeNormalization()->ifString()->then(function ($v) {
-                                             return preg_split('/\s*,\s*/', $v);
-                                         })->end()
-                                         ->prototype('scalar')->end()
-                                     ->end()
-                                 ->end()
-                             ->end()
-                         ->end()
-                     ->end()
-                 ->end()
-             ->end();
-     }
-     private function addVersioningSection(ArrayNodeDefinition $rootNode)
-     {
-         $rootNode
-         ->children()
-             ->arrayNode('versioning')
-                 ->canBeEnabled()
-                 ->children()
-                     ->scalarNode('default_version')->defaultNull()->end()
-                     ->arrayNode('resolvers')
-                         ->addDefaultsIfNotSet()
-                         ->children()
-                             ->arrayNode('query')
-                                 ->canBeDisabled()
-                                 ->children()
-                                     ->scalarNode('parameter_name')->defaultValue('version')->end()
-                                 ->end()
-                             ->end()
-                             ->arrayNode('custom_header')
-                                 ->canBeDisabled()
-                                 ->children()
-                                     ->scalarNode('header_name')->defaultValue('X-Accept-Version')->end()
-                                 ->end()
-                             ->end()
-                             ->arrayNode('media_type')
-                                 ->canBeDisabled()
-                                 ->children()
-                                     ->scalarNode('regex')->defaultValue('/(v|version)=(?P<version>[0-9\.]+)/')->end()
-                                 ->end()
-                             ->end()
-                         ->end()
-                     ->end()
-                     ->arrayNode('guessing_order')
-                         ->defaultValue(['query', 'custom_header', 'media_type'])
-                         ->validate()
-                             ->ifTrue(function ($v) {
-                                 foreach ($v as $resolver) {
-                                     if (!in_array($resolver, ['query', 'custom_header', 'media_type'])) {
-                                         return true;
-                                     }
-                                 }
-                             })
-                             ->thenInvalid('Versioning guessing order can only contain "query", "custom_header", "media_type".')
-                         ->end()
-                         ->prototype('scalar')->end()
-                     ->end()
-                 ->end()
-             ->end()
-         ->end();
-     }
-     private function addExceptionSection(ArrayNodeDefinition $rootNode)
-     {
-         $rootNode
-             ->children()
-                 ->arrayNode('exception')
-                     ->fixXmlConfig('code', 'codes')
-                     ->fixXmlConfig('message', 'messages')
-                     ->addDefaultsIfNotSet()
-                     ->canBeEnabled()
-                     ->validate()
-                       ->always()
-                       ->then(function ($v) {
-                           if (!$v['enabled']) {
-                               return $v;
-                           }
-                           if ($v['exception_listener']) {
-                               @trigger_error('Enabling the "fos_rest.exception.exception_listener" option is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
-                           }
-                           if ($v['serialize_exceptions']) {
-                               @trigger_error('Enabling the "fos_rest.exception.serialize_exceptions" option is deprecated since FOSRestBundle 2.8.', E_USER_DEPRECATED);
-                           }
-                           return $v;
-                       })
-                     ->end()
-                     ->children()
-                         ->booleanNode('map_exception_codes')
-                             ->defaultFalse()
-                             ->info('Enables an event listener that maps exception codes to response status codes based on the map configured with the "fos_rest.exception.codes" option.')
-                         ->end()
-                         ->booleanNode('exception_listener')
-                             ->defaultTrue()
-                         ->end()
-                         ->scalarNode('exception_controller')
-                             ->defaultNull()
-                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
-                         ->end()
-                         ->booleanNode('serialize_exceptions')
-                             ->defaultTrue()
-                         ->end()
-                         ->enumNode('flatten_exception_format')
-                             ->defaultValue('legacy')
-                             ->values(['legacy', 'rfc7807'])
-                         ->end()
-                         ->scalarNode('service')
-                             ->defaultNull()
-                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
-                         ->end()
-                         ->booleanNode('serializer_error_renderer')->defaultValue(false)->end()
-                         ->arrayNode('codes')
-                             ->useAttributeAsKey('name')
-                             ->beforeNormalization()
-                                 ->ifArray()
-                                 ->then(function (array $items) {
-                                     foreach ($items as &$item) {
-                                         if (is_int($item)) {
-                                             continue;
-                                         }
-                                         if (!defined(sprintf('%s::%s', Response::class, $item))) {
-                                             throw new InvalidConfigurationException(sprintf('Invalid HTTP code in fos_rest.exception.codes, see %s for all valid codes.', Response::class));
-                                         }
-                                         $item = constant(sprintf('%s::%s', Response::class, $item));
-                                     }
-                                     return $items;
-                                 })
-                             ->end()
-                             ->prototype('integer')->end()
-                             ->validate()
-                             ->ifArray()
-                                 ->then(function (array $items) {
-                                     foreach ($items as $class => $code) {
-                                         $this->testExceptionExists($class);
-                                     }
-                                     return $items;
-                                 })
-                             ->end()
-                         ->end()
-                         ->arrayNode('messages')
-                             ->useAttributeAsKey('name')
-                             ->prototype('boolean')->end()
-                             ->validate()
-                                 ->ifArray()
-                                 ->then(function (array $items) {
-                                     foreach ($items as $class => $nomatter) {
-                                         $this->testExceptionExists($class);
-                                     }
-                                     return $items;
-                                 })
-                             ->end()
-                         ->end()
-                         ->booleanNode('debug')
-                             ->defaultValue($this->debug)
-                         ->end()
-                     ->end()
-                 ->end()
-             ->end();
-     }
-     private function testExceptionExists(string $throwable)
-     {
-         if (!is_a($throwable, \Throwable::class, true)) {
-             throw new InvalidConfigurationException(sprintf('FOSRestBundle exception mapper: Could not load class "%s" or the class does not extend from "%s". Most probably this is a configuration problem.', $throwable, \Throwable::class));
-         }
-     }
- }
-