vendor/friendsofsymfony/rest-bundle/DependencyInjection/Configuration.php line 474

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the FOSRestBundle package.
  4.  *
  5.  * (c) FriendsOfSymfony <http://friendsofsymfony.github.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. namespace FOS\RestBundle\DependencyInjection;
  11. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  12. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  13. use Symfony\Component\Config\Definition\ConfigurationInterface;
  14. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\OptionsResolver\OptionsResolver;
  17. use Symfony\Component\Serializer\Encoder\XmlEncoder;
  18. /**
  19.  * This class contains the configuration information for the bundle.
  20.  *
  21.  * This information is solely responsible for how the different configuration
  22.  * sections are normalized, and merged.
  23.  *
  24.  * @author Lukas Kahwe Smith <smith@pooteeweet.org>
  25.  *
  26.  * @internal
  27.  */
  28. final class Configuration implements ConfigurationInterface
  29. {
  30.     /**
  31.      * Default debug mode value.
  32.      *
  33.      * @var bool
  34.      */
  35.     private $debug;
  36.     public function __construct(bool $debug)
  37.     {
  38.         $this->debug $debug;
  39.     }
  40.     public function getConfigTreeBuilder(): TreeBuilder
  41.     {
  42.         $treeBuilder = new TreeBuilder('fos_rest');
  43.         if (method_exists($treeBuilder'getRootNode')) {
  44.             $rootNode $treeBuilder->getRootNode();
  45.         } else {
  46.             $rootNode $treeBuilder->root('fos_rest');
  47.         }
  48.         $rootNode
  49.             ->children()
  50.                 ->scalarNode('disable_csrf_role')->defaultNull()->end()
  51.                 ->arrayNode('access_denied_listener')
  52.                     ->canBeEnabled()
  53.                     ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
  54.                     ->beforeNormalization()
  55.                         ->ifArray()->then(function ($v) {
  56.                             if (!empty($v) && empty($v['formats'])) {
  57.                                 unset($v['enabled']);
  58.                                 $v = ['enabled' => true'formats' => $v];
  59.                             }
  60.                             return $v;
  61.                         })
  62.                     ->end()
  63.                     ->fixXmlConfig('format''formats')
  64.                     ->children()
  65.                         ->scalarNode('service')->defaultNull()->end()
  66.                         ->arrayNode('formats')
  67.                             ->useAttributeAsKey('name')
  68.                             ->prototype('boolean')->end()
  69.                         ->end()
  70.                     ->end()
  71.                 ->end()
  72.                 ->scalarNode('unauthorized_challenge')->defaultNull()->end()
  73.                 ->arrayNode('param_fetcher_listener')
  74.                     ->beforeNormalization()
  75.                         ->ifString()
  76.                         ->then(function ($v) {
  77.                             return ['enabled' => in_array($v, ['force''true']), 'force' => 'force' === $v];
  78.                         })
  79.                     ->end()
  80.                     ->canBeEnabled()
  81.                     ->children()
  82.                         ->booleanNode('force')->defaultFalse()->end()
  83.                         ->scalarNode('service')->defaultNull()->end()
  84.                     ->end()
  85.                 ->end()
  86.                 ->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')->end()
  87.                 ->arrayNode('allowed_methods_listener')
  88.                     ->canBeEnabled()
  89.                     ->children()
  90.                         ->scalarNode('service')->defaultNull()->end()
  91.                     ->end()
  92.                 ->end()
  93.                 ->arrayNode('routing_loader')
  94.                     ->addDefaultsIfNotSet()
  95.                     ->beforeNormalization()
  96.                         ->ifTrue(function ($v) { return isset($v['enabled']) && false !== $v['enabled']; })
  97.                         ->then(function ($v) {
  98.                             @trigger_error('Enabling the route generation feature is deprecated since FOSRestBundle 2.8.'E_USER_DEPRECATED);
  99.                             return $v;
  100.                         })
  101.                     ->end()
  102.                     ->beforeNormalization()
  103.                         ->ifTrue(function ($v) { return is_bool($v); })
  104.                         ->then(function ($v) {
  105.                             return [
  106.                                 'enabled' => $v,
  107.                             ];
  108.                         })
  109.                     ->end()
  110.                     ->children()
  111.                         ->booleanNode('enabled')
  112.                             ->defaultValue(function () {
  113.                                 @trigger_error('Enabling the route generation feature is deprecated since FOSRestBundle 2.8.'E_USER_DEPRECATED);
  114.                                 return true;
  115.                             })
  116.                         ->end()
  117.                         ->scalarNode('default_format')->defaultNull()->end()
  118.                         ->scalarNode('prefix_methods')->defaultTrue()->end()
  119.                         ->scalarNode('include_format')->defaultTrue()->end()
  120.                     ->end()
  121.                 ->end()
  122.                 ->arrayNode('body_converter')
  123.                     ->canBeEnabled()
  124.                     ->children()
  125.                         ->scalarNode('validate')
  126.                             ->defaultFalse()
  127.                             ->beforeNormalization()
  128.                                 ->ifTrue()
  129.                                 ->then(function ($value) {
  130.                                     if (!class_exists(OptionsResolver::class)) {
  131.                                         throw new InvalidConfigurationException("'body_converter.validate: true' requires OptionsResolver component installation ( composer require symfony/options-resolver )");
  132.                                     }
  133.                                     return $value;
  134.                                 })
  135.                             ->end()
  136.                         ->end()
  137.                         ->scalarNode('validation_errors_argument')->defaultValue('validationErrors')->end()
  138.                     ->end()
  139.                 ->end()
  140.                 ->arrayNode('service')
  141.                     ->addDefaultsIfNotSet()
  142.                     ->children()
  143.                         ->scalarNode('router')->defaultValue('router')->setDeprecated('The "%path%.%node%" configuration key has been deprecated in FOSRestBundle 2.8.')->end()
  144.                         ->scalarNode('templating')
  145.                             ->defaultValue('templating')
  146.                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
  147.                         ->end()
  148.                         ->scalarNode('serializer')->defaultNull()->end()
  149.                         ->scalarNode('view_handler')->defaultValue('fos_rest.view_handler.default')->end()
  150.                         ->scalarNode('inflector')
  151.                             ->defaultValue('fos_rest.inflector.doctrine')
  152.                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
  153.                         ->end()
  154.                         ->scalarNode('validator')->defaultValue('validator')->end()
  155.                     ->end()
  156.                 ->end()
  157.                 ->arrayNode('serializer')
  158.                     ->addDefaultsIfNotSet()
  159.                     ->children()
  160.                         ->scalarNode('version')->defaultNull()->end()
  161.                         ->arrayNode('groups')
  162.                             ->prototype('scalar')->end()
  163.                         ->end()
  164.                         ->booleanNode('serialize_null')->defaultFalse()->end()
  165.                     ->end()
  166.                 ->end()
  167.                 ->arrayNode('zone')
  168.                     ->cannotBeOverwritten()
  169.                     ->prototype('array')
  170.                     ->fixXmlConfig('ip')
  171.                     ->children()
  172.                         ->scalarNode('path')
  173.                             ->defaultNull()
  174.                             ->info('use the urldecoded format')
  175.                             ->example('^/path to resource/')
  176.                         ->end()
  177.                         ->scalarNode('host')->defaultNull()->end()
  178.                         ->arrayNode('methods')
  179.                             ->beforeNormalization()->ifString()->then(function ($v) {
  180.                                 return preg_split('/\s*,\s*/'$v);
  181.                             })->end()
  182.                             ->prototype('scalar')->end()
  183.                         ->end()
  184.                         ->arrayNode('ips')
  185.                             ->beforeNormalization()->ifString()->then(function ($v) {
  186.                                 return array($v);
  187.                             })->end()
  188.                             ->prototype('scalar')->end()
  189.                         ->end()
  190.                     ->end()
  191.                 ->end()
  192.             ->end()
  193.         ->end();
  194.         $this->addViewSection($rootNode);
  195.         $this->addExceptionSection($rootNode);
  196.         $this->addBodyListenerSection($rootNode);
  197.         $this->addFormatListenerSection($rootNode);
  198.         $this->addVersioningSection($rootNode);
  199.         return $treeBuilder;
  200.     }
  201.     private function addViewSection(ArrayNodeDefinition $rootNode)
  202.     {
  203.         $rootNode
  204.             ->children()
  205.                 ->arrayNode('view')
  206.                     ->fixXmlConfig('format''formats')
  207.                     ->fixXmlConfig('mime_type''mime_types')
  208.                     ->fixXmlConfig('templating_format''templating_formats')
  209.                     ->fixXmlConfig('force_redirect''force_redirects')
  210.                     ->addDefaultsIfNotSet()
  211.                     ->children()
  212.                         ->scalarNode('default_engine')
  213.                             ->setDeprecated('The "%path%.%node%" option has been deprecated in FOSRestBundle 2.8.')
  214.                             ->defaultValue('twig')
  215.                         ->end()
  216.                         ->arrayNode('force_redirects')
  217.                             ->setDeprecated('The "%path%.%node%" option has been deprecated in FOSRestBundle 2.8.')
  218.                             ->useAttributeAsKey('name')
  219.                             ->defaultValue(['html' => true])
  220.                             ->prototype('boolean')->end()
  221.                         ->end()
  222.                         ->arrayNode('mime_types')
  223.                             ->canBeEnabled()
  224.                             ->beforeNormalization()
  225.                                 ->ifArray()->then(function ($v) {
  226.                                     if (!empty($v) && empty($v['formats'])) {
  227.                                         unset($v['enabled']);
  228.                                         $v = ['enabled' => true'formats' => $v];
  229.                                     }
  230.                                     return $v;
  231.                                 })
  232.                             ->end()
  233.                             ->fixXmlConfig('format''formats')
  234.                             ->children()
  235.                                 ->scalarNode('service')->defaultNull()->end()
  236.                                 ->arrayNode('formats')
  237.                                     ->useAttributeAsKey('name')
  238.                                     ->prototype('array')
  239.                                         ->beforeNormalization()
  240.                                             ->ifString()
  241.                                             ->then(function ($v) { return array($v); })
  242.                                         ->end()
  243.                                         ->prototype('scalar')->end()
  244.                                     ->end()
  245.                                 ->end()
  246.                             ->end()
  247.                         ->end()
  248.                         ->arrayNode('formats')
  249.                             ->useAttributeAsKey('name')
  250.                             ->defaultValue(['json' => true'xml' => true])
  251.                             ->prototype('boolean')->end()
  252.                         ->end()
  253.                         ->arrayNode('templating_formats')
  254.                             ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in FOSRestBundle 2.8.')
  255.                             ->useAttributeAsKey('name')
  256.                             ->defaultValue(['html' => true])
  257.                             ->prototype('boolean')->end()
  258.                         ->end()
  259.                         ->arrayNode('view_response_listener')
  260.                             ->beforeNormalization()
  261.                                 ->ifString()
  262.                                 ->then(function ($v) {
  263.                                     return ['enabled' => in_array($v, ['force''true']), 'force' => 'force' === $v];
  264.                                 })
  265.                             ->end()
  266.                             ->canBeEnabled()
  267.                             ->children()
  268.                                 ->booleanNode('force')->defaultFalse()->end()
  269.                                 ->scalarNode('service')->defaultNull()->end()
  270.                             ->end()
  271.                         ->end()
  272.                         ->scalarNode('failed_validation')->defaultValue(Response::HTTP_BAD_REQUEST)->end()
  273.                         ->scalarNode('empty_content')->defaultValue(Response::HTTP_NO_CONTENT)->end()
  274.                         ->booleanNode('serialize_null')->defaultFalse()->end()
  275.                         ->arrayNode('jsonp_handler')
  276.                             ->canBeUnset()
  277.                             ->children()
  278.                                 ->scalarNode('callback_param')->defaultValue('callback')->end()
  279.                                 ->scalarNode('mime_type')->defaultValue('application/javascript+jsonp')->end()
  280.                             ->end()
  281.                         ->end()
  282.                     ->end()
  283.                 ->end()
  284.             ->end();
  285.     }
  286.     private function addBodyListenerSection(ArrayNodeDefinition $rootNode)
  287.     {
  288.         $decodersDefaultValue = ['json' => 'fos_rest.decoder.json'];
  289.         if (class_exists(XmlEncoder::class)) {
  290.             $decodersDefaultValue['xml'] = 'fos_rest.decoder.xml';
  291.         }
  292.         $rootNode
  293.             ->children()
  294.                 ->arrayNode('body_listener')
  295.                     ->fixXmlConfig('decoder''decoders')
  296.                     ->addDefaultsIfNotSet()
  297.                     ->canBeUnset()
  298.                     ->treatFalseLike(['enabled' => false])
  299.                     ->treatTrueLike(['enabled' => true])
  300.                     ->treatNullLike(['enabled' => true])
  301.                     ->children()
  302.                         ->booleanNode('enabled')
  303.                             ->defaultValue(function () {
  304.                                 @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);
  305.                                 return true;
  306.                             })
  307.                         ->end()
  308.                         ->scalarNode('service')->defaultNull()->end()
  309.                         ->scalarNode('default_format')->defaultNull()->end()
  310.                         ->booleanNode('throw_exception_on_unsupported_content_type')
  311.                             ->defaultFalse()
  312.                         ->end()
  313.                         ->arrayNode('decoders')
  314.                             ->useAttributeAsKey('name')
  315.                             ->defaultValue($decodersDefaultValue)
  316.                             ->prototype('scalar')->end()
  317.                         ->end()
  318.                         ->arrayNode('array_normalizer')
  319.                             ->addDefaultsIfNotSet()
  320.                             ->beforeNormalization()
  321.                                 ->ifString()->then(function ($v) {
  322.                                     return ['service' => $v];
  323.                                 })
  324.                             ->end()
  325.                             ->children()
  326.                                 ->scalarNode('service')->defaultNull()->end()
  327.                                 ->booleanNode('forms')->defaultFalse()->end()
  328.                             ->end()
  329.                         ->end()
  330.                     ->end()
  331.                 ->end()
  332.             ->end();
  333.     }
  334.     private function addFormatListenerSection(ArrayNodeDefinition $rootNode)
  335.     {
  336.         $rootNode
  337.             ->children()
  338.                 ->arrayNode('format_listener')
  339.                     ->fixXmlConfig('rule''rules')
  340.                     ->addDefaultsIfNotSet()
  341.                     ->canBeUnset()
  342.                     ->beforeNormalization()
  343.                         ->ifTrue(function ($v) {
  344.                             // check if we got an assoc array in rules
  345.                             return isset($v['rules'])
  346.                                 && is_array($v['rules'])
  347.                                 && array_keys($v['rules']) !== range(0count($v['rules']) - 1);
  348.                         })
  349.                         ->then(function ($v) {
  350.                             $v['rules'] = [$v['rules']];
  351.                             return $v;
  352.                         })
  353.                     ->end()
  354.                     ->canBeEnabled()
  355.                     ->children()
  356.                         ->scalarNode('service')->defaultNull()->end()
  357.                         ->arrayNode('rules')
  358.                             ->performNoDeepMerging()
  359.                             ->prototype('array')
  360.                                 ->fixXmlConfig('priority''priorities')
  361.                                 ->fixXmlConfig('attribute''attributes')
  362.                                 ->children()
  363.                                     ->scalarNode('path')->defaultNull()->info('URL path info')->end()
  364.                                     ->scalarNode('host')->defaultNull()->info('URL host name')->end()
  365.                                     ->variableNode('methods')->defaultNull()->info('Method for URL')->end()
  366.                                     ->arrayNode('attributes')
  367.                                         ->useAttributeAsKey('name')
  368.                                         ->prototype('variable')->end()
  369.                                     ->end()
  370.                                     ->booleanNode('stop')->defaultFalse()->end()
  371.                                     ->booleanNode('prefer_extension')->defaultTrue()->end()
  372.                                     ->scalarNode('fallback_format')->defaultValue('html')->end()
  373.                                     ->arrayNode('priorities')
  374.                                         ->beforeNormalization()->ifString()->then(function ($v) {
  375.                                             return preg_split('/\s*,\s*/'$v);
  376.                                         })->end()
  377.                                         ->prototype('scalar')->end()
  378.                                     ->end()
  379.                                 ->end()
  380.                             ->end()
  381.                         ->end()
  382.                     ->end()
  383.                 ->end()
  384.             ->end();
  385.     }
  386.     private function addVersioningSection(ArrayNodeDefinition $rootNode)
  387.     {
  388.         $rootNode
  389.         ->children()
  390.             ->arrayNode('versioning')
  391.                 ->canBeEnabled()
  392.                 ->children()
  393.                     ->scalarNode('default_version')->defaultNull()->end()
  394.                     ->arrayNode('resolvers')
  395.                         ->addDefaultsIfNotSet()
  396.                         ->children()
  397.                             ->arrayNode('query')
  398.                                 ->canBeDisabled()
  399.                                 ->children()
  400.                                     ->scalarNode('parameter_name')->defaultValue('version')->end()
  401.                                 ->end()
  402.                             ->end()
  403.                             ->arrayNode('custom_header')
  404.                                 ->canBeDisabled()
  405.                                 ->children()
  406.                                     ->scalarNode('header_name')->defaultValue('X-Accept-Version')->end()
  407.                                 ->end()
  408.                             ->end()
  409.                             ->arrayNode('media_type')
  410.                                 ->canBeDisabled()
  411.                                 ->children()
  412.                                     ->scalarNode('regex')->defaultValue('/(v|version)=(?P<version>[0-9\.]+)/')->end()
  413.                                 ->end()
  414.                             ->end()
  415.                         ->end()
  416.                     ->end()
  417.                     ->arrayNode('guessing_order')
  418.                         ->defaultValue(['query''custom_header''media_type'])
  419.                         ->validate()
  420.                             ->ifTrue(function ($v) {
  421.                                 foreach ($v as $resolver) {
  422.                                     if (!in_array($resolver, ['query''custom_header''media_type'])) {
  423.                                         return true;
  424.                                     }
  425.                                 }
  426.                             })
  427.                             ->thenInvalid('Versioning guessing order can only contain "query", "custom_header", "media_type".')
  428.                         ->end()
  429.                         ->prototype('scalar')->end()
  430.                     ->end()
  431.                 ->end()
  432.             ->end()
  433.         ->end();
  434.     }
  435.     private function addExceptionSection(ArrayNodeDefinition $rootNode)
  436.     {
  437.         $rootNode
  438.             ->children()
  439.                 ->arrayNode('exception')
  440.                     ->fixXmlConfig('code''codes')
  441.                     ->fixXmlConfig('message''messages')
  442.                     ->addDefaultsIfNotSet()
  443.                     ->canBeEnabled()
  444.                     ->validate()
  445.                       ->always()
  446.                       ->then(function ($v) {
  447.                           if (!$v['enabled']) {
  448.                             return $v;
  449.                           }
  450.                           if ($v['exception_listener']) {
  451.                               @trigger_error('Enabling the "fos_rest.exception.exception_listener" option is deprecated since FOSRestBundle 2.8.'E_USER_DEPRECATED);
  452.                           }
  453.                           if ($v['serialize_exceptions']) {
  454.                               @trigger_error('Enabling the "fos_rest.exception.serialize_exceptions" option is deprecated since FOSRestBundle 2.8.'E_USER_DEPRECATED);
  455.                           }
  456.                           return $v;
  457.                       })
  458.                     ->end()
  459.                     ->children()
  460.                         ->booleanNode('map_exception_codes')
  461.                             ->defaultFalse()
  462.                             ->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.')
  463.                         ->end()
  464.                         ->booleanNode('exception_listener')
  465.                             ->defaultTrue()
  466.                         ->end()
  467.                         ->scalarNode('exception_controller')
  468.                             ->defaultNull()
  469.                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
  470.                         ->end()
  471.                         ->booleanNode('serialize_exceptions')
  472.                             ->defaultTrue()
  473.                         ->end()
  474.                         ->enumNode('flatten_exception_format')
  475.                             ->defaultValue('legacy')
  476.                             ->values(['legacy''rfc7807'])
  477.                         ->end()
  478.                         ->scalarNode('service')
  479.                             ->defaultNull()
  480.                             ->setDeprecated('The "%path%.%node%" option is deprecated since FOSRestBundle 2.8.')
  481.                         ->end()
  482.                         ->booleanNode('serializer_error_renderer')->defaultValue(false)->end()
  483.                         ->arrayNode('codes')
  484.                             ->useAttributeAsKey('name')
  485.                             ->beforeNormalization()
  486.                                 ->ifArray()
  487.                                 ->then(function (array $items) {
  488.                                     foreach ($items as &$item) {
  489.                                         if (is_int($item)) {
  490.                                             continue;
  491.                                         }
  492.                                         if (!defined(sprintf('%s::%s'Response::class, $item))) {
  493.                                             throw new InvalidConfigurationException(sprintf('Invalid HTTP code in fos_rest.exception.codes, see %s for all valid codes.'Response::class));
  494.                                         }
  495.                                         $item constant(sprintf('%s::%s'Response::class, $item));
  496.                                     }
  497.                                     return $items;
  498.                                 })
  499.                             ->end()
  500.                             ->prototype('integer')->end()
  501.                             ->validate()
  502.                             ->ifArray()
  503.                                 ->then(function (array $items) {
  504.                                     foreach ($items as $class => $code) {
  505.                                         $this->testExceptionExists($class);
  506.                                     }
  507.                                     return $items;
  508.                                 })
  509.                             ->end()
  510.                         ->end()
  511.                         ->arrayNode('messages')
  512.                             ->useAttributeAsKey('name')
  513.                             ->prototype('boolean')->end()
  514.                             ->validate()
  515.                                 ->ifArray()
  516.                                 ->then(function (array $items) {
  517.                                     foreach ($items as $class => $nomatter) {
  518.                                         $this->testExceptionExists($class);
  519.                                     }
  520.                                     return $items;
  521.                                 })
  522.                             ->end()
  523.                         ->end()
  524.                         ->booleanNode('debug')
  525.                             ->defaultValue($this->debug)
  526.                         ->end()
  527.                     ->end()
  528.                 ->end()
  529.             ->end();
  530.     }
  531.     private function testExceptionExists(string $throwable)
  532.     {
  533.         if (!is_subclass_of($throwable, \Throwable::class)) {
  534.             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));
  535.         }
  536.     }
  537. }