vendor/symfony/framework-bundle/DependencyInjection/Configuration.php line 82

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.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 Symfony\Bundle\FrameworkBundle\DependencyInjection;
  11. use Doctrine\Common\Annotations\Annotation;
  12. use Doctrine\DBAL\Connection;
  13. use Psr\Log\LogLevel;
  14. use Symfony\Bundle\FullStack;
  15. use Symfony\Component\Asset\Package;
  16. use Symfony\Component\Cache\Adapter\DoctrineAdapter;
  17. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  18. use Symfony\Component\Config\Definition\Builder\NodeBuilder;
  19. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  20. use Symfony\Component\Config\Definition\ConfigurationInterface;
  21. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  22. use Symfony\Component\DependencyInjection\ContainerBuilder;
  23. use Symfony\Component\DependencyInjection\Exception\LogicException;
  24. use Symfony\Component\Form\Form;
  25. use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;
  26. use Symfony\Component\HttpClient\HttpClient;
  27. use Symfony\Component\HttpFoundation\Cookie;
  28. use Symfony\Component\Lock\Lock;
  29. use Symfony\Component\Lock\Store\SemaphoreStore;
  30. use Symfony\Component\Mailer\Mailer;
  31. use Symfony\Component\Messenger\MessageBusInterface;
  32. use Symfony\Component\Notifier\Notifier;
  33. use Symfony\Component\PropertyAccess\PropertyAccessor;
  34. use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
  35. use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter;
  36. use Symfony\Component\Semaphore\Semaphore;
  37. use Symfony\Component\Serializer\Serializer;
  38. use Symfony\Component\Translation\Translator;
  39. use Symfony\Component\Uid\Factory\UuidFactory;
  40. use Symfony\Component\Validator\Validation;
  41. use Symfony\Component\WebLink\HttpHeaderSerializer;
  42. use Symfony\Component\Workflow\WorkflowEvents;
  43. /**
  44.  * FrameworkExtension configuration structure.
  45.  */
  46. class Configuration implements ConfigurationInterface
  47. {
  48.     private bool $debug;
  49.     /**
  50.      * @param bool $debug Whether debugging is enabled or not
  51.      */
  52.     public function __construct(bool $debug)
  53.     {
  54.         $this->debug $debug;
  55.     }
  56.     /**
  57.      * Generates the configuration tree builder.
  58.      */
  59.     public function getConfigTreeBuilder(): TreeBuilder
  60.     {
  61.         $treeBuilder = new TreeBuilder('framework');
  62.         $rootNode $treeBuilder->getRootNode();
  63.         $rootNode
  64.             ->beforeNormalization()
  65.                 ->ifTrue(function ($v) { return !isset($v['assets']) && isset($v['templating']) && class_exists(Package::class); })
  66.                 ->then(function ($v) {
  67.                     $v['assets'] = [];
  68.                     return $v;
  69.                 })
  70.             ->end()
  71.             ->validate()
  72.                 ->always(function ($v) {
  73.                     if (!isset($v['http_method_override'])) {
  74.                         trigger_deprecation('symfony/framework-bundle''6.1''Not setting the "framework.http_method_override" config option is deprecated. It will default to "false" in 7.0.');
  75.                         $v['http_method_override'] = true;
  76.                     }
  77.                     return $v;
  78.                 })
  79.             ->end()
  80.             ->fixXmlConfig('enabled_locale')
  81.             ->children()
  82.                 ->scalarNode('secret')->end()
  83.                 ->booleanNode('http_method_override')
  84.                     ->info("Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. Note: When using the HttpCache, you need to call the method in your front controller instead")
  85.                     ->treatNullLike(false)
  86.                 ->end()
  87.                 ->scalarNode('trust_x_sendfile_type_header')
  88.                     ->info('Set true to enable support for xsendfile in binary file responses.')
  89.                     ->defaultFalse()
  90.                 ->end()
  91.                 ->scalarNode('ide')->defaultValue('%env(default::SYMFONY_IDE)%')->end()
  92.                 ->booleanNode('test')->end()
  93.                 ->scalarNode('default_locale')->defaultValue('en')->end()
  94.                 ->booleanNode('set_locale_from_accept_language')
  95.                     ->info('Whether to use the Accept-Language HTTP header to set the Request locale (only when the "_locale" request attribute is not passed).')
  96.                     ->defaultFalse()
  97.                 ->end()
  98.                 ->booleanNode('set_content_language_from_locale')
  99.                     ->info('Whether to set the Content-Language HTTP header on the Response using the Request locale.')
  100.                     ->defaultFalse()
  101.                 ->end()
  102.                 ->arrayNode('enabled_locales')
  103.                     ->info('Defines the possible locales for the application. This list is used for generating translations files, but also to restrict which locales are allowed when it is set from Accept-Language header (using "set_locale_from_accept_language").')
  104.                     ->prototype('scalar')->end()
  105.                 ->end()
  106.                 ->arrayNode('trusted_hosts')
  107.                     ->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end()
  108.                     ->prototype('scalar')->end()
  109.                 ->end()
  110.                 ->scalarNode('trusted_proxies')->end()
  111.                 ->arrayNode('trusted_headers')
  112.                     ->fixXmlConfig('trusted_header')
  113.                     ->performNoDeepMerging()
  114.                     ->defaultValue(['x-forwarded-for''x-forwarded-port''x-forwarded-proto'])
  115.                     ->beforeNormalization()->ifString()->then(function ($v) { return $v array_map('trim'explode(','$v)) : []; })->end()
  116.                     ->enumPrototype()
  117.                         ->values([
  118.                             'forwarded',
  119.                             'x-forwarded-for''x-forwarded-host''x-forwarded-proto''x-forwarded-port''x-forwarded-prefix',
  120.                         ])
  121.                     ->end()
  122.                 ->end()
  123.                 ->scalarNode('error_controller')
  124.                     ->defaultValue('error_controller')
  125.                 ->end()
  126.             ->end()
  127.         ;
  128.         $willBeAvailable = static function (string $packagestring $classstring $parentPackage null) {
  129.             $parentPackages = (array) $parentPackage;
  130.             $parentPackages[] = 'symfony/framework-bundle';
  131.             return ContainerBuilder::willBeAvailable($package$class$parentPackages);
  132.         };
  133.         $enableIfStandalone = static function (string $packagestring $class) use ($willBeAvailable) {
  134.             return !class_exists(FullStack::class) && $willBeAvailable($package$class) ? 'canBeDisabled' 'canBeEnabled';
  135.         };
  136.         $this->addCsrfSection($rootNode);
  137.         $this->addFormSection($rootNode$enableIfStandalone);
  138.         $this->addHttpCacheSection($rootNode);
  139.         $this->addEsiSection($rootNode);
  140.         $this->addSsiSection($rootNode);
  141.         $this->addFragmentsSection($rootNode);
  142.         $this->addProfilerSection($rootNode);
  143.         $this->addWorkflowSection($rootNode);
  144.         $this->addRouterSection($rootNode);
  145.         $this->addSessionSection($rootNode);
  146.         $this->addRequestSection($rootNode);
  147.         $this->addAssetsSection($rootNode$enableIfStandalone);
  148.         $this->addTranslatorSection($rootNode$enableIfStandalone);
  149.         $this->addValidationSection($rootNode$enableIfStandalone);
  150.         $this->addAnnotationsSection($rootNode$willBeAvailable);
  151.         $this->addSerializerSection($rootNode$enableIfStandalone);
  152.         $this->addPropertyAccessSection($rootNode$willBeAvailable);
  153.         $this->addPropertyInfoSection($rootNode$enableIfStandalone);
  154.         $this->addCacheSection($rootNode$willBeAvailable);
  155.         $this->addPhpErrorsSection($rootNode);
  156.         $this->addExceptionsSection($rootNode);
  157.         $this->addWebLinkSection($rootNode$enableIfStandalone);
  158.         $this->addLockSection($rootNode$enableIfStandalone);
  159.         $this->addSemaphoreSection($rootNode$enableIfStandalone);
  160.         $this->addMessengerSection($rootNode$enableIfStandalone);
  161.         $this->addRobotsIndexSection($rootNode);
  162.         $this->addHttpClientSection($rootNode$enableIfStandalone);
  163.         $this->addMailerSection($rootNode$enableIfStandalone);
  164.         $this->addSecretsSection($rootNode);
  165.         $this->addNotifierSection($rootNode$enableIfStandalone);
  166.         $this->addRateLimiterSection($rootNode$enableIfStandalone);
  167.         $this->addUidSection($rootNode$enableIfStandalone);
  168.         $this->addHtmlSanitizerSection($rootNode$enableIfStandalone);
  169.         return $treeBuilder;
  170.     }
  171.     private function addSecretsSection(ArrayNodeDefinition $rootNode)
  172.     {
  173.         $rootNode
  174.             ->children()
  175.                 ->arrayNode('secrets')
  176.                     ->canBeDisabled()
  177.                     ->children()
  178.                         ->scalarNode('vault_directory')->defaultValue('%kernel.project_dir%/config/secrets/%kernel.runtime_environment%')->cannotBeEmpty()->end()
  179.                         ->scalarNode('local_dotenv_file')->defaultValue('%kernel.project_dir%/.env.%kernel.environment%.local')->end()
  180.                         ->scalarNode('decryption_env_var')->defaultValue('base64:default::SYMFONY_DECRYPTION_SECRET')->end()
  181.                     ->end()
  182.                 ->end()
  183.             ->end()
  184.         ;
  185.     }
  186.     private function addCsrfSection(ArrayNodeDefinition $rootNode)
  187.     {
  188.         $rootNode
  189.             ->children()
  190.                 ->arrayNode('csrf_protection')
  191.                     ->treatFalseLike(['enabled' => false])
  192.                     ->treatTrueLike(['enabled' => true])
  193.                     ->treatNullLike(['enabled' => true])
  194.                     ->addDefaultsIfNotSet()
  195.                     ->children()
  196.                         // defaults to framework.session.enabled && !class_exists(FullStack::class) && interface_exists(CsrfTokenManagerInterface::class)
  197.                         ->booleanNode('enabled')->defaultNull()->end()
  198.                     ->end()
  199.                 ->end()
  200.             ->end()
  201.         ;
  202.     }
  203.     private function addFormSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  204.     {
  205.         $rootNode
  206.             ->children()
  207.                 ->arrayNode('form')
  208.                     ->info('form configuration')
  209.                     ->{$enableIfStandalone('symfony/form'Form::class)}()
  210.                     ->children()
  211.                         ->arrayNode('csrf_protection')
  212.                             ->treatFalseLike(['enabled' => false])
  213.                             ->treatTrueLike(['enabled' => true])
  214.                             ->treatNullLike(['enabled' => true])
  215.                             ->addDefaultsIfNotSet()
  216.                             ->children()
  217.                                 ->booleanNode('enabled')->defaultNull()->end() // defaults to framework.csrf_protection.enabled
  218.                                 ->scalarNode('field_name')->defaultValue('_token')->end()
  219.                             ->end()
  220.                         ->end()
  221.                         // to be deprecated in Symfony 6.1
  222.                         ->booleanNode('legacy_error_messages')->end()
  223.                     ->end()
  224.                 ->end()
  225.             ->end()
  226.         ;
  227.     }
  228.     private function addHttpCacheSection(ArrayNodeDefinition $rootNode)
  229.     {
  230.         $rootNode
  231.             ->children()
  232.                 ->arrayNode('http_cache')
  233.                     ->info('HTTP cache configuration')
  234.                     ->canBeEnabled()
  235.                     ->fixXmlConfig('private_header')
  236.                     ->children()
  237.                         ->booleanNode('debug')->defaultValue('%kernel.debug%')->end()
  238.                         ->enumNode('trace_level')
  239.                             ->values(['none''short''full'])
  240.                         ->end()
  241.                         ->scalarNode('trace_header')->end()
  242.                         ->integerNode('default_ttl')->end()
  243.                         ->arrayNode('private_headers')
  244.                             ->performNoDeepMerging()
  245.                             ->scalarPrototype()->end()
  246.                         ->end()
  247.                         ->booleanNode('allow_reload')->end()
  248.                         ->booleanNode('allow_revalidate')->end()
  249.                         ->integerNode('stale_while_revalidate')->end()
  250.                         ->integerNode('stale_if_error')->end()
  251.                     ->end()
  252.                 ->end()
  253.             ->end()
  254.         ;
  255.     }
  256.     private function addEsiSection(ArrayNodeDefinition $rootNode)
  257.     {
  258.         $rootNode
  259.             ->children()
  260.                 ->arrayNode('esi')
  261.                     ->info('esi configuration')
  262.                     ->canBeEnabled()
  263.                 ->end()
  264.             ->end()
  265.         ;
  266.     }
  267.     private function addSsiSection(ArrayNodeDefinition $rootNode)
  268.     {
  269.         $rootNode
  270.             ->children()
  271.                 ->arrayNode('ssi')
  272.                     ->info('ssi configuration')
  273.                     ->canBeEnabled()
  274.                 ->end()
  275.             ->end();
  276.     }
  277.     private function addFragmentsSection(ArrayNodeDefinition $rootNode)
  278.     {
  279.         $rootNode
  280.             ->children()
  281.                 ->arrayNode('fragments')
  282.                     ->info('fragments configuration')
  283.                     ->canBeEnabled()
  284.                     ->children()
  285.                         ->scalarNode('hinclude_default_template')->defaultNull()->end()
  286.                         ->scalarNode('path')->defaultValue('/_fragment')->end()
  287.                     ->end()
  288.                 ->end()
  289.             ->end()
  290.         ;
  291.     }
  292.     private function addProfilerSection(ArrayNodeDefinition $rootNode)
  293.     {
  294.         $rootNode
  295.             ->children()
  296.                 ->arrayNode('profiler')
  297.                     ->info('profiler configuration')
  298.                     ->canBeEnabled()
  299.                     ->children()
  300.                         ->booleanNode('collect')->defaultTrue()->end()
  301.                         ->scalarNode('collect_parameter')->defaultNull()->info('The name of the parameter to use to enable or disable collection on a per request basis')->end()
  302.                         ->booleanNode('only_exceptions')->defaultFalse()->end()
  303.                         ->booleanNode('only_main_requests')->defaultFalse()->end()
  304.                         ->scalarNode('dsn')->defaultValue('file:%kernel.cache_dir%/profiler')->end()
  305.                         ->booleanNode('collect_serializer_data')->info('Enables the serializer data collector and profiler panel')->defaultFalse()->end()
  306.                     ->end()
  307.                 ->end()
  308.             ->end()
  309.         ;
  310.     }
  311.     private function addWorkflowSection(ArrayNodeDefinition $rootNode)
  312.     {
  313.         $rootNode
  314.             ->fixXmlConfig('workflow')
  315.             ->children()
  316.                 ->arrayNode('workflows')
  317.                     ->canBeEnabled()
  318.                     ->beforeNormalization()
  319.                         ->always(function ($v) {
  320.                             if (\is_array($v) && true === $v['enabled']) {
  321.                                 $workflows $v;
  322.                                 unset($workflows['enabled']);
  323.                                 if (=== \count($workflows) && isset($workflows[0]['enabled']) && === \count($workflows[0])) {
  324.                                     $workflows = [];
  325.                                 }
  326.                                 if (=== \count($workflows) && isset($workflows['workflows']) && !array_is_list($workflows['workflows']) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail''type''marking_store''supports''support_strategy''initial_marking''places''transitions']))) {
  327.                                     $workflows $workflows['workflows'];
  328.                                 }
  329.                                 foreach ($workflows as $key => $workflow) {
  330.                                     if (isset($workflow['enabled']) && false === $workflow['enabled']) {
  331.                                         throw new LogicException(sprintf('Cannot disable a single workflow. Remove the configuration for the workflow "%s" instead.'$workflow['name']));
  332.                                     }
  333.                                     unset($workflows[$key]['enabled']);
  334.                                 }
  335.                                 $v = [
  336.                                     'enabled' => true,
  337.                                     'workflows' => $workflows,
  338.                                 ];
  339.                             }
  340.                             return $v;
  341.                         })
  342.                     ->end()
  343.                     ->children()
  344.                         ->arrayNode('workflows')
  345.                             ->useAttributeAsKey('name')
  346.                             ->prototype('array')
  347.                                 ->fixXmlConfig('support')
  348.                                 ->fixXmlConfig('place')
  349.                                 ->fixXmlConfig('transition')
  350.                                 ->fixXmlConfig('event_to_dispatch''events_to_dispatch')
  351.                                 ->children()
  352.                                     ->arrayNode('audit_trail')
  353.                                         ->canBeEnabled()
  354.                                     ->end()
  355.                                     ->enumNode('type')
  356.                                         ->values(['workflow''state_machine'])
  357.                                         ->defaultValue('state_machine')
  358.                                     ->end()
  359.                                     ->arrayNode('marking_store')
  360.                                         ->children()
  361.                                             ->enumNode('type')
  362.                                                 ->values(['method'])
  363.                                             ->end()
  364.                                             ->scalarNode('property')
  365.                                                 ->defaultValue('marking')
  366.                                             ->end()
  367.                                             ->scalarNode('service')
  368.                                                 ->cannotBeEmpty()
  369.                                             ->end()
  370.                                         ->end()
  371.                                     ->end()
  372.                                     ->arrayNode('supports')
  373.                                         ->beforeNormalization()
  374.                                             ->ifString()
  375.                                             ->then(function ($v) { return [$v]; })
  376.                                         ->end()
  377.                                         ->prototype('scalar')
  378.                                             ->cannotBeEmpty()
  379.                                             ->validate()
  380.                                                 ->ifTrue(function ($v) { return !class_exists($v) && !interface_exists($vfalse); })
  381.                                                 ->thenInvalid('The supported class or interface "%s" does not exist.')
  382.                                             ->end()
  383.                                         ->end()
  384.                                     ->end()
  385.                                     ->scalarNode('support_strategy')
  386.                                         ->cannotBeEmpty()
  387.                                     ->end()
  388.                                     ->arrayNode('initial_marking')
  389.                                         ->beforeNormalization()->castToArray()->end()
  390.                                         ->defaultValue([])
  391.                                         ->prototype('scalar')->end()
  392.                                     ->end()
  393.                                     ->variableNode('events_to_dispatch')
  394.                                         ->defaultValue(null)
  395.                                         ->validate()
  396.                                             ->ifTrue(function ($v) {
  397.                                                 if (null === $v) {
  398.                                                     return false;
  399.                                                 }
  400.                                                 if (!\is_array($v)) {
  401.                                                     return true;
  402.                                                 }
  403.                                                 foreach ($v as $value) {
  404.                                                     if (!\is_string($value)) {
  405.                                                         return true;
  406.                                                     }
  407.                                                     if (class_exists(WorkflowEvents::class) && !\in_array($valueWorkflowEvents::ALIASES)) {
  408.                                                         return true;
  409.                                                     }
  410.                                                 }
  411.                                                 return false;
  412.                                             })
  413.                                             ->thenInvalid('The value must be "null" or an array of workflow events (like ["workflow.enter"]).')
  414.                                         ->end()
  415.                                         ->info('Select which Transition events should be dispatched for this Workflow')
  416.                                         ->example(['workflow.enter''workflow.transition'])
  417.                                     ->end()
  418.                                     ->arrayNode('places')
  419.                                         ->beforeNormalization()
  420.                                             ->always()
  421.                                             ->then(function ($places) {
  422.                                                 // It's an indexed array of shape  ['place1', 'place2']
  423.                                                 if (isset($places[0]) && \is_string($places[0])) {
  424.                                                     return array_map(function (string $place) {
  425.                                                         return ['name' => $place];
  426.                                                     }, $places);
  427.                                                 }
  428.                                                 // It's an indexed array, we let the validation occur
  429.                                                 if (isset($places[0]) && \is_array($places[0])) {
  430.                                                     return $places;
  431.                                                 }
  432.                                                 foreach ($places as $name => $place) {
  433.                                                     if (\is_array($place) && \array_key_exists('name'$place)) {
  434.                                                         continue;
  435.                                                     }
  436.                                                     $place['name'] = $name;
  437.                                                     $places[$name] = $place;
  438.                                                 }
  439.                                                 return array_values($places);
  440.                                             })
  441.                                         ->end()
  442.                                         ->isRequired()
  443.                                         ->requiresAtLeastOneElement()
  444.                                         ->prototype('array')
  445.                                             ->children()
  446.                                                 ->scalarNode('name')
  447.                                                     ->isRequired()
  448.                                                     ->cannotBeEmpty()
  449.                                                 ->end()
  450.                                                 ->arrayNode('metadata')
  451.                                                     ->normalizeKeys(false)
  452.                                                     ->defaultValue([])
  453.                                                     ->example(['color' => 'blue''description' => 'Workflow to manage article.'])
  454.                                                     ->prototype('variable')
  455.                                                     ->end()
  456.                                                 ->end()
  457.                                             ->end()
  458.                                         ->end()
  459.                                     ->end()
  460.                                     ->arrayNode('transitions')
  461.                                         ->beforeNormalization()
  462.                                             ->always()
  463.                                             ->then(function ($transitions) {
  464.                                                 // It's an indexed array, we let the validation occur
  465.                                                 if (isset($transitions[0]) && \is_array($transitions[0])) {
  466.                                                     return $transitions;
  467.                                                 }
  468.                                                 foreach ($transitions as $name => $transition) {
  469.                                                     if (\is_array($transition) && \array_key_exists('name'$transition)) {
  470.                                                         continue;
  471.                                                     }
  472.                                                     $transition['name'] = $name;
  473.                                                     $transitions[$name] = $transition;
  474.                                                 }
  475.                                                 return $transitions;
  476.                                             })
  477.                                         ->end()
  478.                                         ->isRequired()
  479.                                         ->requiresAtLeastOneElement()
  480.                                         ->prototype('array')
  481.                                             ->children()
  482.                                                 ->scalarNode('name')
  483.                                                     ->isRequired()
  484.                                                     ->cannotBeEmpty()
  485.                                                 ->end()
  486.                                                 ->scalarNode('guard')
  487.                                                     ->cannotBeEmpty()
  488.                                                     ->info('An expression to block the transition')
  489.                                                     ->example('is_fully_authenticated() and is_granted(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
  490.                                                 ->end()
  491.                                                 ->arrayNode('from')
  492.                                                     ->beforeNormalization()
  493.                                                         ->ifString()
  494.                                                         ->then(function ($v) { return [$v]; })
  495.                                                     ->end()
  496.                                                     ->requiresAtLeastOneElement()
  497.                                                     ->prototype('scalar')
  498.                                                         ->cannotBeEmpty()
  499.                                                     ->end()
  500.                                                 ->end()
  501.                                                 ->arrayNode('to')
  502.                                                     ->beforeNormalization()
  503.                                                         ->ifString()
  504.                                                         ->then(function ($v) { return [$v]; })
  505.                                                     ->end()
  506.                                                     ->requiresAtLeastOneElement()
  507.                                                     ->prototype('scalar')
  508.                                                         ->cannotBeEmpty()
  509.                                                     ->end()
  510.                                                 ->end()
  511.                                                 ->arrayNode('metadata')
  512.                                                     ->normalizeKeys(false)
  513.                                                     ->defaultValue([])
  514.                                                     ->example(['color' => 'blue''description' => 'Workflow to manage article.'])
  515.                                                     ->prototype('variable')
  516.                                                     ->end()
  517.                                                 ->end()
  518.                                             ->end()
  519.                                         ->end()
  520.                                     ->end()
  521.                                     ->arrayNode('metadata')
  522.                                         ->normalizeKeys(false)
  523.                                         ->defaultValue([])
  524.                                         ->example(['color' => 'blue''description' => 'Workflow to manage article.'])
  525.                                         ->prototype('variable')
  526.                                         ->end()
  527.                                     ->end()
  528.                                 ->end()
  529.                                 ->validate()
  530.                                     ->ifTrue(function ($v) {
  531.                                         return $v['supports'] && isset($v['support_strategy']);
  532.                                     })
  533.                                     ->thenInvalid('"supports" and "support_strategy" cannot be used together.')
  534.                                 ->end()
  535.                                 ->validate()
  536.                                     ->ifTrue(function ($v) {
  537.                                         return !$v['supports'] && !isset($v['support_strategy']);
  538.                                     })
  539.                                     ->thenInvalid('"supports" or "support_strategy" should be configured.')
  540.                                 ->end()
  541.                                 ->beforeNormalization()
  542.                                         ->always()
  543.                                         ->then(function ($values) {
  544.                                             // Special case to deal with XML when the user wants an empty array
  545.                                             if (\array_key_exists('event_to_dispatch'$values) && null === $values['event_to_dispatch']) {
  546.                                                 $values['events_to_dispatch'] = [];
  547.                                                 unset($values['event_to_dispatch']);
  548.                                             }
  549.                                             return $values;
  550.                                         })
  551.                                 ->end()
  552.                             ->end()
  553.                         ->end()
  554.                     ->end()
  555.                 ->end()
  556.             ->end()
  557.         ;
  558.     }
  559.     private function addRouterSection(ArrayNodeDefinition $rootNode)
  560.     {
  561.         $rootNode
  562.             ->children()
  563.                 ->arrayNode('router')
  564.                     ->info('router configuration')
  565.                     ->canBeEnabled()
  566.                     ->children()
  567.                         ->scalarNode('resource')->isRequired()->end()
  568.                         ->scalarNode('type')->end()
  569.                         ->scalarNode('default_uri')
  570.                             ->info('The default URI used to generate URLs in a non-HTTP context')
  571.                             ->defaultNull()
  572.                         ->end()
  573.                         ->scalarNode('http_port')->defaultValue(80)->end()
  574.                         ->scalarNode('https_port')->defaultValue(443)->end()
  575.                         ->scalarNode('strict_requirements')
  576.                             ->info(
  577.                                 "set to true to throw an exception when a parameter does not match the requirements\n".
  578.                                 "set to false to disable exceptions when a parameter does not match the requirements (and return null instead)\n".
  579.                                 "set to null to disable parameter checks against requirements\n".
  580.                                 "'true' is the preferred configuration in development mode, while 'false' or 'null' might be preferred in production"
  581.                             )
  582.                             ->defaultTrue()
  583.                         ->end()
  584.                         ->booleanNode('utf8')->defaultTrue()->end()
  585.                     ->end()
  586.                 ->end()
  587.             ->end()
  588.         ;
  589.     }
  590.     private function addSessionSection(ArrayNodeDefinition $rootNode)
  591.     {
  592.         $rootNode
  593.             ->children()
  594.                 ->arrayNode('session')
  595.                     ->info('session configuration')
  596.                     ->canBeEnabled()
  597.                     ->children()
  598.                         ->scalarNode('storage_factory_id')->defaultValue('session.storage.factory.native')->end()
  599.                         ->scalarNode('handler_id')->defaultValue('session.handler.native_file')->end()
  600.                         ->scalarNode('name')
  601.                             ->validate()
  602.                                 ->ifTrue(function ($v) {
  603.                                     parse_str($v$parsed);
  604.                                     return implode('&'array_keys($parsed)) !== (string) $v;
  605.                                 })
  606.                                 ->thenInvalid('Session name %s contains illegal character(s)')
  607.                             ->end()
  608.                         ->end()
  609.                         ->scalarNode('cookie_lifetime')->end()
  610.                         ->scalarNode('cookie_path')->end()
  611.                         ->scalarNode('cookie_domain')->end()
  612.                         ->enumNode('cookie_secure')->values([truefalse'auto'])->end()
  613.                         ->booleanNode('cookie_httponly')->defaultTrue()->end()
  614.                         ->enumNode('cookie_samesite')->values([nullCookie::SAMESITE_LAXCookie::SAMESITE_STRICTCookie::SAMESITE_NONE])->defaultNull()->end()
  615.                         ->booleanNode('use_cookies')->end()
  616.                         ->scalarNode('gc_divisor')->end()
  617.                         ->scalarNode('gc_probability')->defaultValue(1)->end()
  618.                         ->scalarNode('gc_maxlifetime')->end()
  619.                         ->scalarNode('save_path')->defaultValue('%kernel.cache_dir%/sessions')->end()
  620.                         ->integerNode('metadata_update_threshold')
  621.                             ->defaultValue(0)
  622.                             ->info('seconds to wait between 2 session metadata updates')
  623.                         ->end()
  624.                         ->integerNode('sid_length')
  625.                             ->min(22)
  626.                             ->max(256)
  627.                         ->end()
  628.                         ->integerNode('sid_bits_per_character')
  629.                             ->min(4)
  630.                             ->max(6)
  631.                         ->end()
  632.                     ->end()
  633.                 ->end()
  634.             ->end()
  635.         ;
  636.     }
  637.     private function addRequestSection(ArrayNodeDefinition $rootNode)
  638.     {
  639.         $rootNode
  640.             ->children()
  641.                 ->arrayNode('request')
  642.                     ->info('request configuration')
  643.                     ->canBeEnabled()
  644.                     ->fixXmlConfig('format')
  645.                     ->children()
  646.                         ->arrayNode('formats')
  647.                             ->useAttributeAsKey('name')
  648.                             ->prototype('array')
  649.                                 ->beforeNormalization()
  650.                                     ->ifTrue(function ($v) { return \is_array($v) && isset($v['mime_type']); })
  651.                                     ->then(function ($v) { return $v['mime_type']; })
  652.                                 ->end()
  653.                                 ->beforeNormalization()->castToArray()->end()
  654.                                 ->prototype('scalar')->end()
  655.                             ->end()
  656.                         ->end()
  657.                     ->end()
  658.                 ->end()
  659.             ->end()
  660.         ;
  661.     }
  662.     private function addAssetsSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  663.     {
  664.         $rootNode
  665.             ->children()
  666.                 ->arrayNode('assets')
  667.                     ->info('assets configuration')
  668.                     ->{$enableIfStandalone('symfony/asset'Package::class)}()
  669.                     ->fixXmlConfig('base_url')
  670.                     ->children()
  671.                         ->booleanNode('strict_mode')
  672.                             ->info('Throw an exception if an entry is missing from the manifest.json')
  673.                             ->defaultFalse()
  674.                         ->end()
  675.                         ->scalarNode('version_strategy')->defaultNull()->end()
  676.                         ->scalarNode('version')->defaultNull()->end()
  677.                         ->scalarNode('version_format')->defaultValue('%%s?%%s')->end()
  678.                         ->scalarNode('json_manifest_path')->defaultNull()->end()
  679.                         ->scalarNode('base_path')->defaultValue('')->end()
  680.                         ->arrayNode('base_urls')
  681.                             ->requiresAtLeastOneElement()
  682.                             ->beforeNormalization()->castToArray()->end()
  683.                             ->prototype('scalar')->end()
  684.                         ->end()
  685.                     ->end()
  686.                     ->validate()
  687.                         ->ifTrue(function ($v) {
  688.                             return isset($v['version_strategy']) && isset($v['version']);
  689.                         })
  690.                         ->thenInvalid('You cannot use both "version_strategy" and "version" at the same time under "assets".')
  691.                     ->end()
  692.                     ->validate()
  693.                         ->ifTrue(function ($v) {
  694.                             return isset($v['version_strategy']) && isset($v['json_manifest_path']);
  695.                         })
  696.                         ->thenInvalid('You cannot use both "version_strategy" and "json_manifest_path" at the same time under "assets".')
  697.                     ->end()
  698.                     ->validate()
  699.                         ->ifTrue(function ($v) {
  700.                             return isset($v['version']) && isset($v['json_manifest_path']);
  701.                         })
  702.                         ->thenInvalid('You cannot use both "version" and "json_manifest_path" at the same time under "assets".')
  703.                     ->end()
  704.                     ->fixXmlConfig('package')
  705.                     ->children()
  706.                         ->arrayNode('packages')
  707.                             ->normalizeKeys(false)
  708.                             ->useAttributeAsKey('name')
  709.                             ->prototype('array')
  710.                                 ->fixXmlConfig('base_url')
  711.                                 ->children()
  712.                                     ->booleanNode('strict_mode')
  713.                                         ->info('Throw an exception if an entry is missing from the manifest.json')
  714.                                         ->defaultFalse()
  715.                                     ->end()
  716.                                     ->scalarNode('version_strategy')->defaultNull()->end()
  717.                                     ->scalarNode('version')
  718.                                         ->beforeNormalization()
  719.                                         ->ifTrue(function ($v) { return '' === $v; })
  720.                                         ->then(function ($v) { return; })
  721.                                         ->end()
  722.                                     ->end()
  723.                                     ->scalarNode('version_format')->defaultNull()->end()
  724.                                     ->scalarNode('json_manifest_path')->defaultNull()->end()
  725.                                     ->scalarNode('base_path')->defaultValue('')->end()
  726.                                     ->arrayNode('base_urls')
  727.                                         ->requiresAtLeastOneElement()
  728.                                         ->beforeNormalization()->castToArray()->end()
  729.                                         ->prototype('scalar')->end()
  730.                                     ->end()
  731.                                 ->end()
  732.                                 ->validate()
  733.                                     ->ifTrue(function ($v) {
  734.                                         return isset($v['version_strategy']) && isset($v['version']);
  735.                                     })
  736.                                     ->thenInvalid('You cannot use both "version_strategy" and "version" at the same time under "assets" packages.')
  737.                                 ->end()
  738.                                 ->validate()
  739.                                     ->ifTrue(function ($v) {
  740.                                         return isset($v['version_strategy']) && isset($v['json_manifest_path']);
  741.                                     })
  742.                                     ->thenInvalid('You cannot use both "version_strategy" and "json_manifest_path" at the same time under "assets" packages.')
  743.                                 ->end()
  744.                                 ->validate()
  745.                                     ->ifTrue(function ($v) {
  746.                                         return isset($v['version']) && isset($v['json_manifest_path']);
  747.                                     })
  748.                                     ->thenInvalid('You cannot use both "version" and "json_manifest_path" at the same time under "assets" packages.')
  749.                                 ->end()
  750.                             ->end()
  751.                         ->end()
  752.                     ->end()
  753.                 ->end()
  754.             ->end()
  755.         ;
  756.     }
  757.     private function addTranslatorSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  758.     {
  759.         $rootNode
  760.             ->children()
  761.                 ->arrayNode('translator')
  762.                     ->info('translator configuration')
  763.                     ->{$enableIfStandalone('symfony/translation'Translator::class)}()
  764.                     ->fixXmlConfig('fallback')
  765.                     ->fixXmlConfig('path')
  766.                     ->fixXmlConfig('provider')
  767.                     ->children()
  768.                         ->arrayNode('fallbacks')
  769.                             ->info('Defaults to the value of "default_locale".')
  770.                             ->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end()
  771.                             ->prototype('scalar')->end()
  772.                             ->defaultValue([])
  773.                         ->end()
  774.                         ->booleanNode('logging')->defaultValue(false)->end()
  775.                         ->scalarNode('formatter')->defaultValue('translator.formatter.default')->end()
  776.                         ->scalarNode('cache_dir')->defaultValue('%kernel.cache_dir%/translations')->end()
  777.                         ->scalarNode('default_path')
  778.                             ->info('The default path used to load translations')
  779.                             ->defaultValue('%kernel.project_dir%/translations')
  780.                         ->end()
  781.                         ->arrayNode('paths')
  782.                             ->prototype('scalar')->end()
  783.                         ->end()
  784.                         ->arrayNode('pseudo_localization')
  785.                             ->canBeEnabled()
  786.                             ->fixXmlConfig('localizable_html_attribute')
  787.                             ->children()
  788.                                 ->booleanNode('accents')->defaultTrue()->end()
  789.                                 ->floatNode('expansion_factor')
  790.                                     ->min(1.0)
  791.                                     ->defaultValue(1.0)
  792.                                 ->end()
  793.                                 ->booleanNode('brackets')->defaultTrue()->end()
  794.                                 ->booleanNode('parse_html')->defaultFalse()->end()
  795.                                 ->arrayNode('localizable_html_attributes')
  796.                                     ->prototype('scalar')->end()
  797.                                 ->end()
  798.                             ->end()
  799.                         ->end()
  800.                         ->arrayNode('providers')
  801.                             ->info('Translation providers you can read/write your translations from')
  802.                             ->useAttributeAsKey('name')
  803.                             ->prototype('array')
  804.                                 ->fixXmlConfig('domain')
  805.                                 ->fixXmlConfig('locale')
  806.                                 ->children()
  807.                                     ->scalarNode('dsn')->end()
  808.                                     ->arrayNode('domains')
  809.                                         ->prototype('scalar')->end()
  810.                                         ->defaultValue([])
  811.                                     ->end()
  812.                                     ->arrayNode('locales')
  813.                                         ->prototype('scalar')->end()
  814.                                         ->defaultValue([])
  815.                                         ->info('If not set, all locales listed under framework.enabled_locales are used.')
  816.                                     ->end()
  817.                                 ->end()
  818.                             ->end()
  819.                             ->defaultValue([])
  820.                         ->end()
  821.                     ->end()
  822.                 ->end()
  823.             ->end()
  824.         ;
  825.     }
  826.     private function addValidationSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  827.     {
  828.         $rootNode
  829.             ->children()
  830.                 ->arrayNode('validation')
  831.                     ->info('validation configuration')
  832.                     ->{$enableIfStandalone('symfony/validator'Validation::class)}()
  833.                     ->children()
  834.                         ->scalarNode('cache')->end()
  835.                         ->booleanNode('enable_annotations')->{!class_exists(FullStack::class) ? 'defaultTrue' 'defaultFalse'}()->end()
  836.                         ->arrayNode('static_method')
  837.                             ->defaultValue(['loadValidatorMetadata'])
  838.                             ->prototype('scalar')->end()
  839.                             ->treatFalseLike([])
  840.                             ->validate()->castToArray()->end()
  841.                         ->end()
  842.                         ->scalarNode('translation_domain')->defaultValue('validators')->end()
  843.                         ->enumNode('email_validation_mode')->values(['html5''loose''strict'])->end()
  844.                         ->arrayNode('mapping')
  845.                             ->addDefaultsIfNotSet()
  846.                             ->fixXmlConfig('path')
  847.                             ->children()
  848.                                 ->arrayNode('paths')
  849.                                     ->prototype('scalar')->end()
  850.                                 ->end()
  851.                             ->end()
  852.                         ->end()
  853.                         ->arrayNode('not_compromised_password')
  854.                             ->canBeDisabled()
  855.                             ->children()
  856.                                 ->booleanNode('enabled')
  857.                                     ->defaultTrue()
  858.                                     ->info('When disabled, compromised passwords will be accepted as valid.')
  859.                                 ->end()
  860.                                 ->scalarNode('endpoint')
  861.                                     ->defaultNull()
  862.                                     ->info('API endpoint for the NotCompromisedPassword Validator.')
  863.                                 ->end()
  864.                             ->end()
  865.                         ->end()
  866.                         ->arrayNode('auto_mapping')
  867.                             ->info('A collection of namespaces for which auto-mapping will be enabled by default, or null to opt-in with the EnableAutoMapping constraint.')
  868.                             ->example([
  869.                                 'App\\Entity\\' => [],
  870.                                 'App\\WithSpecificLoaders\\' => ['validator.property_info_loader'],
  871.                             ])
  872.                             ->useAttributeAsKey('namespace')
  873.                             ->normalizeKeys(false)
  874.                             ->beforeNormalization()
  875.                                 ->ifArray()
  876.                                 ->then(function (array $values): array {
  877.                                     foreach ($values as $k => $v) {
  878.                                         if (isset($v['service'])) {
  879.                                             continue;
  880.                                         }
  881.                                         if (isset($v['namespace'])) {
  882.                                             $values[$k]['services'] = [];
  883.                                             continue;
  884.                                         }
  885.                                         if (!\is_array($v)) {
  886.                                             $values[$v]['services'] = [];
  887.                                             unset($values[$k]);
  888.                                             continue;
  889.                                         }
  890.                                         $tmp $v;
  891.                                         unset($values[$k]);
  892.                                         $values[$k]['services'] = $tmp;
  893.                                     }
  894.                                     return $values;
  895.                                 })
  896.                             ->end()
  897.                             ->arrayPrototype()
  898.                                 ->fixXmlConfig('service')
  899.                                 ->children()
  900.                                     ->arrayNode('services')
  901.                                         ->prototype('scalar')->end()
  902.                                     ->end()
  903.                                 ->end()
  904.                             ->end()
  905.                         ->end()
  906.                     ->end()
  907.                 ->end()
  908.             ->end()
  909.         ;
  910.     }
  911.     private function addAnnotationsSection(ArrayNodeDefinition $rootNode, callable $willBeAvailable)
  912.     {
  913.         $rootNode
  914.             ->children()
  915.                 ->arrayNode('annotations')
  916.                     ->info('annotation configuration')
  917.                     ->{$willBeAvailable('doctrine/annotations'Annotation::class) ? 'canBeDisabled' 'canBeEnabled'}()
  918.                     ->children()
  919.                         ->enumNode('cache')
  920.                             ->values(['none''php_array''file'])
  921.                             ->defaultValue('php_array')
  922.                         ->end()
  923.                         ->scalarNode('file_cache_dir')->defaultValue('%kernel.cache_dir%/annotations')->end()
  924.                         ->booleanNode('debug')->defaultValue($this->debug)->end()
  925.                     ->end()
  926.                 ->end()
  927.             ->end()
  928.         ;
  929.     }
  930.     private function addSerializerSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  931.     {
  932.         $rootNode
  933.             ->children()
  934.                 ->arrayNode('serializer')
  935.                     ->info('serializer configuration')
  936.                     ->{$enableIfStandalone('symfony/serializer'Serializer::class)}()
  937.                     ->children()
  938.                         ->booleanNode('enable_annotations')->{!class_exists(FullStack::class) ? 'defaultTrue' 'defaultFalse'}()->end()
  939.                         ->scalarNode('name_converter')->end()
  940.                         ->scalarNode('circular_reference_handler')->end()
  941.                         ->scalarNode('max_depth_handler')->end()
  942.                         ->arrayNode('mapping')
  943.                             ->addDefaultsIfNotSet()
  944.                             ->fixXmlConfig('path')
  945.                             ->children()
  946.                                 ->arrayNode('paths')
  947.                                     ->prototype('scalar')->end()
  948.                                 ->end()
  949.                             ->end()
  950.                         ->end()
  951.                         ->arrayNode('default_context')
  952.                             ->normalizeKeys(false)
  953.                             ->useAttributeAsKey('name')
  954.                             ->defaultValue([])
  955.                             ->prototype('variable')->end()
  956.                         ->end()
  957.                     ->end()
  958.                 ->end()
  959.             ->end()
  960.         ;
  961.     }
  962.     private function addPropertyAccessSection(ArrayNodeDefinition $rootNode, callable $willBeAvailable)
  963.     {
  964.         $rootNode
  965.             ->children()
  966.                 ->arrayNode('property_access')
  967.                     ->addDefaultsIfNotSet()
  968.                     ->info('Property access configuration')
  969.                     ->{$willBeAvailable('symfony/property-access'PropertyAccessor::class) ? 'canBeDisabled' 'canBeEnabled'}()
  970.                     ->children()
  971.                         ->booleanNode('magic_call')->defaultFalse()->end()
  972.                         ->booleanNode('magic_get')->defaultTrue()->end()
  973.                         ->booleanNode('magic_set')->defaultTrue()->end()
  974.                         ->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end()
  975.                         ->booleanNode('throw_exception_on_invalid_property_path')->defaultTrue()->end()
  976.                     ->end()
  977.                 ->end()
  978.             ->end()
  979.         ;
  980.     }
  981.     private function addPropertyInfoSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  982.     {
  983.         $rootNode
  984.             ->children()
  985.                 ->arrayNode('property_info')
  986.                     ->info('Property info configuration')
  987.                     ->{$enableIfStandalone('symfony/property-info'PropertyInfoExtractorInterface::class)}()
  988.                 ->end()
  989.             ->end()
  990.         ;
  991.     }
  992.     private function addCacheSection(ArrayNodeDefinition $rootNode, callable $willBeAvailable)
  993.     {
  994.         $rootNode
  995.             ->children()
  996.                 ->arrayNode('cache')
  997.                     ->info('Cache configuration')
  998.                     ->addDefaultsIfNotSet()
  999.                     ->fixXmlConfig('pool')
  1000.                     ->children()
  1001.                         ->scalarNode('prefix_seed')
  1002.                             ->info('Used to namespace cache keys when using several apps with the same shared backend')
  1003.                             ->defaultValue('_%kernel.project_dir%.%kernel.container_class%')
  1004.                             ->example('my-application-name/%kernel.environment%')
  1005.                         ->end()
  1006.                         ->scalarNode('app')
  1007.                             ->info('App related cache pools configuration')
  1008.                             ->defaultValue('cache.adapter.filesystem')
  1009.                         ->end()
  1010.                         ->scalarNode('system')
  1011.                             ->info('System related cache pools configuration')
  1012.                             ->defaultValue('cache.adapter.system')
  1013.                         ->end()
  1014.                         ->scalarNode('directory')->defaultValue('%kernel.cache_dir%/pools/app')->end()
  1015.                         ->scalarNode('default_psr6_provider')->end()
  1016.                         ->scalarNode('default_redis_provider')->defaultValue('redis://localhost')->end()
  1017.                         ->scalarNode('default_memcached_provider')->defaultValue('memcached://localhost')->end()
  1018.                         ->scalarNode('default_doctrine_dbal_provider')->defaultValue('database_connection')->end()
  1019.                         ->scalarNode('default_pdo_provider')->defaultValue($willBeAvailable('doctrine/dbal'Connection::class) && class_exists(DoctrineAdapter::class) ? 'database_connection' null)->end()
  1020.                         ->arrayNode('pools')
  1021.                             ->useAttributeAsKey('name')
  1022.                             ->prototype('array')
  1023.                                 ->fixXmlConfig('adapter')
  1024.                                 ->beforeNormalization()
  1025.                                     ->ifTrue(function ($v) { return isset($v['provider']) && \is_array($v['adapters'] ?? $v['adapter'] ?? null) && \count($v['adapters'] ?? $v['adapter']); })
  1026.                                     ->thenInvalid('Pool cannot have a "provider" while more than one adapter is defined')
  1027.                                 ->end()
  1028.                                 ->children()
  1029.                                     ->arrayNode('adapters')
  1030.                                         ->performNoDeepMerging()
  1031.                                         ->info('One or more adapters to chain for creating the pool, defaults to "cache.app".')
  1032.                                         ->beforeNormalization()->castToArray()->end()
  1033.                                         ->beforeNormalization()
  1034.                                             ->always()->then(function ($values) {
  1035.                                                 if ([0] === array_keys($values) && \is_array($values[0])) {
  1036.                                                     return $values[0];
  1037.                                                 }
  1038.                                                 $adapters = [];
  1039.                                                 foreach ($values as $k => $v) {
  1040.                                                     if (\is_int($k) && \is_string($v)) {
  1041.                                                         $adapters[] = $v;
  1042.                                                     } elseif (!\is_array($v)) {
  1043.                                                         $adapters[$k] = $v;
  1044.                                                     } elseif (isset($v['provider'])) {
  1045.                                                         $adapters[$v['provider']] = $v['name'] ?? $v;
  1046.                                                     } else {
  1047.                                                         $adapters[] = $v['name'] ?? $v;
  1048.                                                     }
  1049.                                                 }
  1050.                                                 return $adapters;
  1051.                                             })
  1052.                                         ->end()
  1053.                                         ->prototype('scalar')->end()
  1054.                                     ->end()
  1055.                                     ->scalarNode('tags')->defaultNull()->end()
  1056.                                     ->booleanNode('public')->defaultFalse()->end()
  1057.                                     ->scalarNode('default_lifetime')
  1058.                                         ->info('Default lifetime of the pool')
  1059.                                         ->example('"300" for 5 minutes expressed in seconds, "PT5M" for five minutes expressed as ISO 8601 time interval, or "5 minutes" as a date expression')
  1060.                                     ->end()
  1061.                                     ->scalarNode('provider')
  1062.                                         ->info('Overwrite the setting from the default provider for this adapter.')
  1063.                                     ->end()
  1064.                                     ->scalarNode('early_expiration_message_bus')
  1065.                                         ->example('"messenger.default_bus" to send early expiration events to the default Messenger bus.')
  1066.                                     ->end()
  1067.                                     ->scalarNode('clearer')->end()
  1068.                                 ->end()
  1069.                             ->end()
  1070.                             ->validate()
  1071.                                 ->ifTrue(function ($v) { return isset($v['cache.app']) || isset($v['cache.system']); })
  1072.                                 ->thenInvalid('"cache.app" and "cache.system" are reserved names')
  1073.                             ->end()
  1074.                         ->end()
  1075.                     ->end()
  1076.                 ->end()
  1077.             ->end()
  1078.         ;
  1079.     }
  1080.     private function addPhpErrorsSection(ArrayNodeDefinition $rootNode)
  1081.     {
  1082.         $rootNode
  1083.             ->children()
  1084.                 ->arrayNode('php_errors')
  1085.                     ->info('PHP errors handling configuration')
  1086.                     ->addDefaultsIfNotSet()
  1087.                     ->children()
  1088.                         ->variableNode('log')
  1089.                             ->info('Use the application logger instead of the PHP logger for logging PHP errors.')
  1090.                             ->example('"true" to use the default configuration: log all errors. "false" to disable. An integer bit field of E_* constants, or an array mapping E_* constants to log levels.')
  1091.                             ->defaultValue($this->debug)
  1092.                             ->treatNullLike($this->debug)
  1093.                             ->beforeNormalization()
  1094.                                 ->ifArray()
  1095.                                 ->then(function (array $v): array {
  1096.                                     if (!($v[0]['type'] ?? false)) {
  1097.                                         return $v;
  1098.                                     }
  1099.                                     // Fix XML normalization
  1100.                                     $ret = [];
  1101.                                     foreach ($v as ['type' => $type'logLevel' => $logLevel]) {
  1102.                                         $ret[$type] = $logLevel;
  1103.                                     }
  1104.                                     return $ret;
  1105.                                 })
  1106.                             ->end()
  1107.                             ->validate()
  1108.                                 ->ifTrue(function ($v) { return !(\is_int($v) || \is_bool($v) || \is_array($v)); })
  1109.                                 ->thenInvalid('The "php_errors.log" parameter should be either an integer, a boolean, or an array')
  1110.                             ->end()
  1111.                         ->end()
  1112.                         ->booleanNode('throw')
  1113.                             ->info('Throw PHP errors as \ErrorException instances.')
  1114.                             ->defaultValue($this->debug)
  1115.                             ->treatNullLike($this->debug)
  1116.                         ->end()
  1117.                     ->end()
  1118.                 ->end()
  1119.             ->end()
  1120.         ;
  1121.     }
  1122.     private function addExceptionsSection(ArrayNodeDefinition $rootNode)
  1123.     {
  1124.         $logLevels = (new \ReflectionClass(LogLevel::class))->getConstants();
  1125.         $rootNode
  1126.             ->fixXmlConfig('exception')
  1127.             ->children()
  1128.                 ->arrayNode('exceptions')
  1129.                     ->info('Exception handling configuration')
  1130.                     ->useAttributeAsKey('class')
  1131.                     ->beforeNormalization()
  1132.                         // Handle legacy XML configuration
  1133.                         ->ifArray()
  1134.                         ->then(function (array $v): array {
  1135.                             if (!\array_key_exists('exception'$v)) {
  1136.                                 return $v;
  1137.                             }
  1138.                             $v $v['exception'];
  1139.                             unset($v['exception']);
  1140.                             foreach ($v as &$exception) {
  1141.                                 $exception['class'] = $exception['name'];
  1142.                                 unset($exception['name']);
  1143.                             }
  1144.                             return $v;
  1145.                         })
  1146.                     ->end()
  1147.                     ->prototype('array')
  1148.                         ->children()
  1149.                             ->scalarNode('log_level')
  1150.                                 ->info('The level of log message. Null to let Symfony decide.')
  1151.                                 ->validate()
  1152.                                     ->ifTrue(function ($v) use ($logLevels) { return null !== $v && !\in_array($v$logLevelstrue); })
  1153.                                     ->thenInvalid(sprintf('The log level is not valid. Pick one among "%s".'implode('", "'$logLevels)))
  1154.                                 ->end()
  1155.                                 ->defaultNull()
  1156.                             ->end()
  1157.                             ->scalarNode('status_code')
  1158.                                 ->info('The status code of the response. Null or 0 to let Symfony decide.')
  1159.                                 ->beforeNormalization()
  1160.                                     ->ifTrue(function ($v) { return === $v; })
  1161.                                     ->then(function ($v) { return null; })
  1162.                                 ->end()
  1163.                                 ->validate()
  1164.                                     ->ifTrue(function ($v) { return null !== $v && ($v 100 || $v 599); })
  1165.                                     ->thenInvalid('The status code is not valid. Pick a value between 100 and 599.')
  1166.                                 ->end()
  1167.                                 ->defaultNull()
  1168.                             ->end()
  1169.                         ->end()
  1170.                     ->end()
  1171.                 ->end()
  1172.             ->end()
  1173.         ;
  1174.     }
  1175.     private function addLockSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1176.     {
  1177.         $rootNode
  1178.             ->children()
  1179.                 ->arrayNode('lock')
  1180.                     ->info('Lock configuration')
  1181.                     ->{$enableIfStandalone('symfony/lock'Lock::class)}()
  1182.                     ->beforeNormalization()
  1183.                         ->ifString()->then(function ($v) { return ['enabled' => true'resources' => $v]; })
  1184.                     ->end()
  1185.                     ->beforeNormalization()
  1186.                         ->ifTrue(function ($v) { return \is_array($v) && !isset($v['enabled']); })
  1187.                         ->then(function ($v) { return $v + ['enabled' => true]; })
  1188.                     ->end()
  1189.                     ->beforeNormalization()
  1190.                         ->ifTrue(function ($v) { return \is_array($v) && !isset($v['resources']) && !isset($v['resource']); })
  1191.                         ->then(function ($v) {
  1192.                             $e $v['enabled'];
  1193.                             unset($v['enabled']);
  1194.                             return ['enabled' => $e'resources' => $v];
  1195.                         })
  1196.                     ->end()
  1197.                     ->addDefaultsIfNotSet()
  1198.                     ->validate()
  1199.                         ->ifTrue(static function (array $config) { return $config['enabled'] && !$config['resources']; })
  1200.                         ->thenInvalid('At least one resource must be defined.')
  1201.                     ->end()
  1202.                     ->fixXmlConfig('resource')
  1203.                     ->children()
  1204.                         ->arrayNode('resources')
  1205.                             ->normalizeKeys(false)
  1206.                             ->useAttributeAsKey('name')
  1207.                             ->defaultValue(['default' => [class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphore' 'flock']])
  1208.                             ->beforeNormalization()
  1209.                                 ->ifString()->then(function ($v) { return ['default' => $v]; })
  1210.                             ->end()
  1211.                             ->beforeNormalization()
  1212.                                 ->ifTrue(function ($v) { return \is_array($v) && array_is_list($v); })
  1213.                                 ->then(function ($v) {
  1214.                                     $resources = [];
  1215.                                     foreach ($v as $resource) {
  1216.                                         $resources[] = \is_array($resource) && isset($resource['name'])
  1217.                                             ? [$resource['name'] => $resource['value']]
  1218.                                             : ['default' => $resource]
  1219.                                         ;
  1220.                                     }
  1221.                                     return array_merge_recursive([], ...$resources);
  1222.                                 })
  1223.                             ->end()
  1224.                             ->prototype('array')
  1225.                                 ->performNoDeepMerging()
  1226.                                 ->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end()
  1227.                                 ->prototype('scalar')->end()
  1228.                             ->end()
  1229.                         ->end()
  1230.                     ->end()
  1231.                 ->end()
  1232.             ->end()
  1233.         ;
  1234.     }
  1235.     private function addSemaphoreSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1236.     {
  1237.         $rootNode
  1238.             ->children()
  1239.                 ->arrayNode('semaphore')
  1240.                     ->info('Semaphore configuration')
  1241.                     ->{$enableIfStandalone('symfony/semaphore'Semaphore::class)}()
  1242.                     ->beforeNormalization()
  1243.                         ->ifString()->then(function ($v) { return ['enabled' => true'resources' => $v]; })
  1244.                     ->end()
  1245.                     ->beforeNormalization()
  1246.                         ->ifTrue(function ($v) { return \is_array($v) && !isset($v['enabled']); })
  1247.                         ->then(function ($v) { return $v + ['enabled' => true]; })
  1248.                     ->end()
  1249.                     ->beforeNormalization()
  1250.                         ->ifTrue(function ($v) { return \is_array($v) && !isset($v['resources']) && !isset($v['resource']); })
  1251.                         ->then(function ($v) {
  1252.                             $e $v['enabled'];
  1253.                             unset($v['enabled']);
  1254.                             return ['enabled' => $e'resources' => $v];
  1255.                         })
  1256.                     ->end()
  1257.                     ->addDefaultsIfNotSet()
  1258.                     ->fixXmlConfig('resource')
  1259.                     ->children()
  1260.                         ->arrayNode('resources')
  1261.                             ->normalizeKeys(false)
  1262.                             ->useAttributeAsKey('name')
  1263.                             ->requiresAtLeastOneElement()
  1264.                             ->beforeNormalization()
  1265.                                 ->ifString()->then(function ($v) { return ['default' => $v]; })
  1266.                             ->end()
  1267.                             ->beforeNormalization()
  1268.                                 ->ifTrue(function ($v) { return \is_array($v) && array_is_list($v); })
  1269.                                 ->then(function ($v) {
  1270.                                     $resources = [];
  1271.                                     foreach ($v as $resource) {
  1272.                                         $resources[] = \is_array($resource) && isset($resource['name'])
  1273.                                             ? [$resource['name'] => $resource['value']]
  1274.                                             : ['default' => $resource]
  1275.                                         ;
  1276.                                     }
  1277.                                     return array_merge_recursive([], ...$resources);
  1278.                                 })
  1279.                             ->end()
  1280.                             ->prototype('scalar')->end()
  1281.                         ->end()
  1282.                     ->end()
  1283.                 ->end()
  1284.             ->end()
  1285.         ;
  1286.     }
  1287.     private function addWebLinkSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1288.     {
  1289.         $rootNode
  1290.             ->children()
  1291.                 ->arrayNode('web_link')
  1292.                     ->info('web links configuration')
  1293.                     ->{$enableIfStandalone('symfony/weblink'HttpHeaderSerializer::class)}()
  1294.                 ->end()
  1295.             ->end()
  1296.         ;
  1297.     }
  1298.     private function addMessengerSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1299.     {
  1300.         $rootNode
  1301.             ->children()
  1302.                 ->arrayNode('messenger')
  1303.                     ->info('Messenger configuration')
  1304.                     ->{$enableIfStandalone('symfony/messenger'MessageBusInterface::class)}()
  1305.                     ->fixXmlConfig('transport')
  1306.                     ->fixXmlConfig('bus''buses')
  1307.                     ->validate()
  1308.                         ->ifTrue(function ($v) { return isset($v['buses']) && \count($v['buses']) > && null === $v['default_bus']; })
  1309.                         ->thenInvalid('You must specify the "default_bus" if you define more than one bus.')
  1310.                     ->end()
  1311.                     ->validate()
  1312.                         ->ifTrue(static function ($v): bool { return isset($v['buses']) && null !== $v['default_bus'] && !isset($v['buses'][$v['default_bus']]); })
  1313.                         ->then(static function (array $v): void { throw new InvalidConfigurationException(sprintf('The specified default bus "%s" is not configured. Available buses are "%s".'$v['default_bus'], implode('", "'array_keys($v['buses'])))); })
  1314.                     ->end()
  1315.                     ->children()
  1316.                         ->arrayNode('routing')
  1317.                             ->normalizeKeys(false)
  1318.                             ->useAttributeAsKey('message_class')
  1319.                             ->beforeNormalization()
  1320.                                 ->always()
  1321.                                 ->then(function ($config) {
  1322.                                     if (!\is_array($config)) {
  1323.                                         return [];
  1324.                                     }
  1325.                                     // If XML config with only one routing attribute
  1326.                                     if (=== \count($config) && isset($config['message-class']) && isset($config['sender'])) {
  1327.                                         $config = [=> $config];
  1328.                                     }
  1329.                                     $newConfig = [];
  1330.                                     foreach ($config as $k => $v) {
  1331.                                         if (!\is_int($k)) {
  1332.                                             $newConfig[$k] = [
  1333.                                                 'senders' => $v['senders'] ?? (\is_array($v) ? array_values($v) : [$v]),
  1334.                                             ];
  1335.                                         } else {
  1336.                                             $newConfig[$v['message-class']]['senders'] = array_map(
  1337.                                                 function ($a) {
  1338.                                                     return \is_string($a) ? $a $a['service'];
  1339.                                                 },
  1340.                                                 array_values($v['sender'])
  1341.                                             );
  1342.                                         }
  1343.                                     }
  1344.                                     return $newConfig;
  1345.                                 })
  1346.                             ->end()
  1347.                             ->prototype('array')
  1348.                                 ->performNoDeepMerging()
  1349.                                 ->children()
  1350.                                     ->arrayNode('senders')
  1351.                                         ->requiresAtLeastOneElement()
  1352.                                         ->prototype('scalar')->end()
  1353.                                     ->end()
  1354.                                 ->end()
  1355.                             ->end()
  1356.                         ->end()
  1357.                         ->arrayNode('serializer')
  1358.                             ->addDefaultsIfNotSet()
  1359.                             ->children()
  1360.                                 ->scalarNode('default_serializer')
  1361.                                     ->defaultValue('messenger.transport.native_php_serializer')
  1362.                                     ->info('Service id to use as the default serializer for the transports.')
  1363.                                 ->end()
  1364.                                 ->arrayNode('symfony_serializer')
  1365.                                     ->addDefaultsIfNotSet()
  1366.                                     ->children()
  1367.                                         ->scalarNode('format')->defaultValue('json')->info('Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default).')->end()
  1368.                                         ->arrayNode('context')
  1369.                                             ->normalizeKeys(false)
  1370.                                             ->useAttributeAsKey('name')
  1371.                                             ->defaultValue([])
  1372.                                             ->info('Context array for the messenger.transport.symfony_serializer service (which is not the serializer used by default).')
  1373.                                             ->prototype('variable')->end()
  1374.                                         ->end()
  1375.                                     ->end()
  1376.                                 ->end()
  1377.                             ->end()
  1378.                         ->end()
  1379.                         ->arrayNode('transports')
  1380.                             ->normalizeKeys(false)
  1381.                             ->useAttributeAsKey('name')
  1382.                             ->arrayPrototype()
  1383.                                 ->beforeNormalization()
  1384.                                     ->ifString()
  1385.                                     ->then(function (string $dsn) {
  1386.                                         return ['dsn' => $dsn];
  1387.                                     })
  1388.                                 ->end()
  1389.                                 ->fixXmlConfig('option')
  1390.                                 ->children()
  1391.                                     ->scalarNode('dsn')->end()
  1392.                                     ->scalarNode('serializer')->defaultNull()->info('Service id of a custom serializer to use.')->end()
  1393.                                     ->arrayNode('options')
  1394.                                         ->normalizeKeys(false)
  1395.                                         ->defaultValue([])
  1396.                                         ->prototype('variable')
  1397.                                         ->end()
  1398.                                     ->end()
  1399.                                     ->scalarNode('failure_transport')
  1400.                                         ->defaultNull()
  1401.                                         ->info('Transport name to send failed messages to (after all retries have failed).')
  1402.                                     ->end()
  1403.                                     ->arrayNode('retry_strategy')
  1404.                                         ->addDefaultsIfNotSet()
  1405.                                         ->beforeNormalization()
  1406.                                             ->always(function ($v) {
  1407.                                                 if (isset($v['service']) && (isset($v['max_retries']) || isset($v['delay']) || isset($v['multiplier']) || isset($v['max_delay']))) {
  1408.                                                     throw new \InvalidArgumentException('The "service" cannot be used along with the other "retry_strategy" options.');
  1409.                                                 }
  1410.                                                 return $v;
  1411.                                             })
  1412.                                         ->end()
  1413.                                         ->children()
  1414.                                             ->scalarNode('service')->defaultNull()->info('Service id to override the retry strategy entirely')->end()
  1415.                                             ->integerNode('max_retries')->defaultValue(3)->min(0)->end()
  1416.                                             ->integerNode('delay')->defaultValue(1000)->min(0)->info('Time in ms to delay (or the initial value when multiplier is used)')->end()
  1417.                                             ->floatNode('multiplier')->defaultValue(2)->min(1)->info('If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries))')->end()
  1418.                                             ->integerNode('max_delay')->defaultValue(0)->min(0)->info('Max time in ms that a retry should ever be delayed (0 = infinite)')->end()
  1419.                                         ->end()
  1420.                                     ->end()
  1421.                                 ->end()
  1422.                             ->end()
  1423.                         ->end()
  1424.                         ->scalarNode('failure_transport')
  1425.                             ->defaultNull()
  1426.                             ->info('Transport name to send failed messages to (after all retries have failed).')
  1427.                         ->end()
  1428.                         ->booleanNode('reset_on_message')
  1429.                             ->defaultTrue()
  1430.                             ->info('Reset container services after each message.')
  1431.                             ->setDeprecated('symfony/framework-bundle''6.1''Option "%node%" at "%path%" is deprecated. It does nothing and will be removed in version 7.0.')
  1432.                             ->validate()
  1433.                                 ->ifTrue(static fn ($v) => true !== $v)
  1434.                                 ->thenInvalid('The "framework.messenger.reset_on_message" configuration option can be set to "true" only. To prevent services resetting after each message you can set the "--no-reset" option in "messenger:consume" command.')
  1435.                             ->end()
  1436.                         ->end()
  1437.                         ->scalarNode('default_bus')->defaultNull()->end()
  1438.                         ->arrayNode('buses')
  1439.                             ->defaultValue(['messenger.bus.default' => ['default_middleware' => true'middleware' => []]])
  1440.                             ->normalizeKeys(false)
  1441.                             ->useAttributeAsKey('name')
  1442.                             ->arrayPrototype()
  1443.                                 ->addDefaultsIfNotSet()
  1444.                                 ->children()
  1445.                                     ->enumNode('default_middleware')
  1446.                                         ->values([truefalse'allow_no_handlers'])
  1447.                                         ->defaultTrue()
  1448.                                     ->end()
  1449.                                     ->arrayNode('middleware')
  1450.                                         ->performNoDeepMerging()
  1451.                                         ->beforeNormalization()
  1452.                                             ->ifTrue(function ($v) { return \is_string($v) || (\is_array($v) && !\is_int(key($v))); })
  1453.                                             ->then(function ($v) { return [$v]; })
  1454.                                         ->end()
  1455.                                         ->defaultValue([])
  1456.                                         ->arrayPrototype()
  1457.                                             ->beforeNormalization()
  1458.                                                 ->always()
  1459.                                                 ->then(function ($middleware): array {
  1460.                                                     if (!\is_array($middleware)) {
  1461.                                                         return ['id' => $middleware];
  1462.                                                     }
  1463.                                                     if (isset($middleware['id'])) {
  1464.                                                         return $middleware;
  1465.                                                     }
  1466.                                                     if (\count($middleware)) {
  1467.                                                         throw new \InvalidArgumentException('Invalid middleware at path "framework.messenger": a map with a single factory id as key and its arguments as value was expected, '.json_encode($middleware).' given.');
  1468.                                                     }
  1469.                                                     return [
  1470.                                                         'id' => key($middleware),
  1471.                                                         'arguments' => current($middleware),
  1472.                                                     ];
  1473.                                                 })
  1474.                                             ->end()
  1475.                                             ->fixXmlConfig('argument')
  1476.                                             ->children()
  1477.                                                 ->scalarNode('id')->isRequired()->cannotBeEmpty()->end()
  1478.                                                 ->arrayNode('arguments')
  1479.                                                     ->normalizeKeys(false)
  1480.                                                     ->defaultValue([])
  1481.                                                     ->prototype('variable')
  1482.                                                 ->end()
  1483.                                             ->end()
  1484.                                         ->end()
  1485.                                     ->end()
  1486.                                 ->end()
  1487.                             ->end()
  1488.                         ->end()
  1489.                     ->end()
  1490.                 ->end()
  1491.             ->end()
  1492.         ;
  1493.     }
  1494.     private function addRobotsIndexSection(ArrayNodeDefinition $rootNode)
  1495.     {
  1496.         $rootNode
  1497.             ->children()
  1498.                 ->booleanNode('disallow_search_engine_index')
  1499.                     ->info('Enabled by default when debug is enabled.')
  1500.                     ->defaultValue($this->debug)
  1501.                     ->treatNullLike($this->debug)
  1502.                 ->end()
  1503.             ->end()
  1504.         ;
  1505.     }
  1506.     private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1507.     {
  1508.         $rootNode
  1509.             ->children()
  1510.                 ->arrayNode('http_client')
  1511.                     ->info('HTTP Client configuration')
  1512.                     ->{$enableIfStandalone('symfony/http-client'HttpClient::class)}()
  1513.                     ->fixXmlConfig('scoped_client')
  1514.                     ->beforeNormalization()
  1515.                         ->always(function ($config) {
  1516.                             if (empty($config['scoped_clients']) || !\is_array($config['default_options']['retry_failed'] ?? null)) {
  1517.                                 return $config;
  1518.                             }
  1519.                             foreach ($config['scoped_clients'] as &$scopedConfig) {
  1520.                                 if (!isset($scopedConfig['retry_failed']) || true === $scopedConfig['retry_failed']) {
  1521.                                     $scopedConfig['retry_failed'] = $config['default_options']['retry_failed'];
  1522.                                     continue;
  1523.                                 }
  1524.                                 if (\is_array($scopedConfig['retry_failed'])) {
  1525.                                     $scopedConfig['retry_failed'] = $scopedConfig['retry_failed'] + $config['default_options']['retry_failed'];
  1526.                                 }
  1527.                             }
  1528.                             return $config;
  1529.                         })
  1530.                     ->end()
  1531.                     ->children()
  1532.                         ->integerNode('max_host_connections')
  1533.                             ->info('The maximum number of connections to a single host.')
  1534.                         ->end()
  1535.                         ->arrayNode('default_options')
  1536.                             ->fixXmlConfig('header')
  1537.                             ->children()
  1538.                                 ->arrayNode('headers')
  1539.                                     ->info('Associative array: header => value(s).')
  1540.                                     ->useAttributeAsKey('name')
  1541.                                     ->normalizeKeys(false)
  1542.                                     ->variablePrototype()->end()
  1543.                                 ->end()
  1544.                                 ->integerNode('max_redirects')
  1545.                                     ->info('The maximum number of redirects to follow.')
  1546.                                 ->end()
  1547.                                 ->scalarNode('http_version')
  1548.                                     ->info('The default HTTP version, typically 1.1 or 2.0, leave to null for the best version.')
  1549.                                 ->end()
  1550.                                 ->arrayNode('resolve')
  1551.                                     ->info('Associative array: domain => IP.')
  1552.                                     ->useAttributeAsKey('host')
  1553.                                     ->beforeNormalization()
  1554.                                         ->always(function ($config) {
  1555.                                             if (!\is_array($config)) {
  1556.                                                 return [];
  1557.                                             }
  1558.                                             if (!isset($config['host'], $config['value']) || \count($config) > 2) {
  1559.                                                 return $config;
  1560.                                             }
  1561.                                             return [$config['host'] => $config['value']];
  1562.                                         })
  1563.                                     ->end()
  1564.                                     ->normalizeKeys(false)
  1565.                                     ->scalarPrototype()->end()
  1566.                                 ->end()
  1567.                                 ->scalarNode('proxy')
  1568.                                     ->info('The URL of the proxy to pass requests through or null for automatic detection.')
  1569.                                 ->end()
  1570.                                 ->scalarNode('no_proxy')
  1571.                                     ->info('A comma separated list of hosts that do not require a proxy to be reached.')
  1572.                                 ->end()
  1573.                                 ->floatNode('timeout')
  1574.                                     ->info('The idle timeout, defaults to the "default_socket_timeout" ini parameter.')
  1575.                                 ->end()
  1576.                                 ->floatNode('max_duration')
  1577.                                     ->info('The maximum execution time for the request+response as a whole.')
  1578.                                 ->end()
  1579.                                 ->scalarNode('bindto')
  1580.                                     ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.')
  1581.                                 ->end()
  1582.                                 ->booleanNode('verify_peer')
  1583.                                     ->info('Indicates if the peer should be verified in an SSL/TLS context.')
  1584.                                 ->end()
  1585.                                 ->booleanNode('verify_host')
  1586.                                     ->info('Indicates if the host should exist as a certificate common name.')
  1587.                                 ->end()
  1588.                                 ->scalarNode('cafile')
  1589.                                     ->info('A certificate authority file.')
  1590.                                 ->end()
  1591.                                 ->scalarNode('capath')
  1592.                                     ->info('A directory that contains multiple certificate authority files.')
  1593.                                 ->end()
  1594.                                 ->scalarNode('local_cert')
  1595.                                     ->info('A PEM formatted certificate file.')
  1596.                                 ->end()
  1597.                                 ->scalarNode('local_pk')
  1598.                                     ->info('A private key file.')
  1599.                                 ->end()
  1600.                                 ->scalarNode('passphrase')
  1601.                                     ->info('The passphrase used to encrypt the "local_pk" file.')
  1602.                                 ->end()
  1603.                                 ->scalarNode('ciphers')
  1604.                                     ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)')
  1605.                                 ->end()
  1606.                                 ->arrayNode('peer_fingerprint')
  1607.                                     ->info('Associative array: hashing algorithm => hash(es).')
  1608.                                     ->normalizeKeys(false)
  1609.                                     ->children()
  1610.                                         ->variableNode('sha1')->end()
  1611.                                         ->variableNode('pin-sha256')->end()
  1612.                                         ->variableNode('md5')->end()
  1613.                                     ->end()
  1614.                                 ->end()
  1615.                                 ->append($this->addHttpClientRetrySection())
  1616.                             ->end()
  1617.                         ->end()
  1618.                         ->scalarNode('mock_response_factory')
  1619.                             ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable.')
  1620.                         ->end()
  1621.                         ->arrayNode('scoped_clients')
  1622.                             ->useAttributeAsKey('name')
  1623.                             ->normalizeKeys(false)
  1624.                             ->arrayPrototype()
  1625.                                 ->fixXmlConfig('header')
  1626.                                 ->beforeNormalization()
  1627.                                     ->always()
  1628.                                     ->then(function ($config) {
  1629.                                         if (!class_exists(HttpClient::class)) {
  1630.                                             throw new LogicException('HttpClient support cannot be enabled as the component is not installed. Try running "composer require symfony/http-client".');
  1631.                                         }
  1632.                                         return \is_array($config) ? $config : ['base_uri' => $config];
  1633.                                     })
  1634.                                 ->end()
  1635.                                 ->validate()
  1636.                                     ->ifTrue(function ($v) { return !isset($v['scope']) && !isset($v['base_uri']); })
  1637.                                     ->thenInvalid('Either "scope" or "base_uri" should be defined.')
  1638.                                 ->end()
  1639.                                 ->validate()
  1640.                                     ->ifTrue(function ($v) { return !empty($v['query']) && !isset($v['base_uri']); })
  1641.                                     ->thenInvalid('"query" applies to "base_uri" but no base URI is defined.')
  1642.                                 ->end()
  1643.                                 ->children()
  1644.                                     ->scalarNode('scope')
  1645.                                         ->info('The regular expression that the request URL must match before adding the other options. When none is provided, the base URI is used instead.')
  1646.                                         ->cannotBeEmpty()
  1647.                                     ->end()
  1648.                                     ->scalarNode('base_uri')
  1649.                                         ->info('The URI to resolve relative URLs, following rules in RFC 3985, section 2.')
  1650.                                         ->cannotBeEmpty()
  1651.                                     ->end()
  1652.                                     ->scalarNode('auth_basic')
  1653.                                         ->info('An HTTP Basic authentication "username:password".')
  1654.                                     ->end()
  1655.                                     ->scalarNode('auth_bearer')
  1656.                                         ->info('A token enabling HTTP Bearer authorization.')
  1657.                                     ->end()
  1658.                                     ->scalarNode('auth_ntlm')
  1659.                                         ->info('A "username:password" pair to use Microsoft NTLM authentication (requires the cURL extension).')
  1660.                                     ->end()
  1661.                                     ->arrayNode('query')
  1662.                                         ->info('Associative array of query string values merged with the base URI.')
  1663.                                         ->useAttributeAsKey('key')
  1664.                                         ->beforeNormalization()
  1665.                                             ->always(function ($config) {
  1666.                                                 if (!\is_array($config)) {
  1667.                                                     return [];
  1668.                                                 }
  1669.                                                 if (!isset($config['key'], $config['value']) || \count($config) > 2) {
  1670.                                                     return $config;
  1671.                                                 }
  1672.                                                 return [$config['key'] => $config['value']];
  1673.                                             })
  1674.                                         ->end()
  1675.                                         ->normalizeKeys(false)
  1676.                                         ->scalarPrototype()->end()
  1677.                                     ->end()
  1678.                                     ->arrayNode('headers')
  1679.                                         ->info('Associative array: header => value(s).')
  1680.                                         ->useAttributeAsKey('name')
  1681.                                         ->normalizeKeys(false)
  1682.                                         ->variablePrototype()->end()
  1683.                                     ->end()
  1684.                                     ->integerNode('max_redirects')
  1685.                                         ->info('The maximum number of redirects to follow.')
  1686.                                     ->end()
  1687.                                     ->scalarNode('http_version')
  1688.                                         ->info('The default HTTP version, typically 1.1 or 2.0, leave to null for the best version.')
  1689.                                     ->end()
  1690.                                     ->arrayNode('resolve')
  1691.                                         ->info('Associative array: domain => IP.')
  1692.                                         ->useAttributeAsKey('host')
  1693.                                         ->beforeNormalization()
  1694.                                             ->always(function ($config) {
  1695.                                                 if (!\is_array($config)) {
  1696.                                                     return [];
  1697.                                                 }
  1698.                                                 if (!isset($config['host'], $config['value']) || \count($config) > 2) {
  1699.                                                     return $config;
  1700.                                                 }
  1701.                                                 return [$config['host'] => $config['value']];
  1702.                                             })
  1703.                                         ->end()
  1704.                                         ->normalizeKeys(false)
  1705.                                         ->scalarPrototype()->end()
  1706.                                     ->end()
  1707.                                     ->scalarNode('proxy')
  1708.                                         ->info('The URL of the proxy to pass requests through or null for automatic detection.')
  1709.                                     ->end()
  1710.                                     ->scalarNode('no_proxy')
  1711.                                         ->info('A comma separated list of hosts that do not require a proxy to be reached.')
  1712.                                     ->end()
  1713.                                     ->floatNode('timeout')
  1714.                                         ->info('The idle timeout, defaults to the "default_socket_timeout" ini parameter.')
  1715.                                     ->end()
  1716.                                     ->floatNode('max_duration')
  1717.                                         ->info('The maximum execution time for the request+response as a whole.')
  1718.                                     ->end()
  1719.                                     ->scalarNode('bindto')
  1720.                                         ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.')
  1721.                                     ->end()
  1722.                                     ->booleanNode('verify_peer')
  1723.                                         ->info('Indicates if the peer should be verified in an SSL/TLS context.')
  1724.                                     ->end()
  1725.                                     ->booleanNode('verify_host')
  1726.                                         ->info('Indicates if the host should exist as a certificate common name.')
  1727.                                     ->end()
  1728.                                     ->scalarNode('cafile')
  1729.                                         ->info('A certificate authority file.')
  1730.                                     ->end()
  1731.                                     ->scalarNode('capath')
  1732.                                         ->info('A directory that contains multiple certificate authority files.')
  1733.                                     ->end()
  1734.                                     ->scalarNode('local_cert')
  1735.                                         ->info('A PEM formatted certificate file.')
  1736.                                     ->end()
  1737.                                     ->scalarNode('local_pk')
  1738.                                         ->info('A private key file.')
  1739.                                     ->end()
  1740.                                     ->scalarNode('passphrase')
  1741.                                         ->info('The passphrase used to encrypt the "local_pk" file.')
  1742.                                     ->end()
  1743.                                     ->scalarNode('ciphers')
  1744.                                         ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)')
  1745.                                     ->end()
  1746.                                     ->arrayNode('peer_fingerprint')
  1747.                                         ->info('Associative array: hashing algorithm => hash(es).')
  1748.                                         ->normalizeKeys(false)
  1749.                                         ->children()
  1750.                                             ->variableNode('sha1')->end()
  1751.                                             ->variableNode('pin-sha256')->end()
  1752.                                             ->variableNode('md5')->end()
  1753.                                         ->end()
  1754.                                     ->end()
  1755.                                     ->append($this->addHttpClientRetrySection())
  1756.                                 ->end()
  1757.                             ->end()
  1758.                         ->end()
  1759.                     ->end()
  1760.                 ->end()
  1761.             ->end()
  1762.         ;
  1763.     }
  1764.     private function addHttpClientRetrySection()
  1765.     {
  1766.         $root = new NodeBuilder();
  1767.         return $root
  1768.             ->arrayNode('retry_failed')
  1769.                 ->fixXmlConfig('http_code')
  1770.                 ->canBeEnabled()
  1771.                 ->addDefaultsIfNotSet()
  1772.                 ->beforeNormalization()
  1773.                     ->always(function ($v) {
  1774.                         if (isset($v['retry_strategy']) && (isset($v['http_codes']) || isset($v['delay']) || isset($v['multiplier']) || isset($v['max_delay']) || isset($v['jitter']))) {
  1775.                             throw new \InvalidArgumentException('The "retry_strategy" option cannot be used along with the "http_codes", "delay", "multiplier", "max_delay" or "jitter" options.');
  1776.                         }
  1777.                         return $v;
  1778.                     })
  1779.                 ->end()
  1780.                 ->children()
  1781.                     ->scalarNode('retry_strategy')->defaultNull()->info('service id to override the retry strategy')->end()
  1782.                     ->arrayNode('http_codes')
  1783.                         ->performNoDeepMerging()
  1784.                         ->beforeNormalization()
  1785.                             ->ifArray()
  1786.                             ->then(static function ($v) {
  1787.                                 $list = [];
  1788.                                 foreach ($v as $key => $val) {
  1789.                                     if (is_numeric($val)) {
  1790.                                         $list[] = ['code' => $val];
  1791.                                     } elseif (\is_array($val)) {
  1792.                                         if (isset($val['code']) || isset($val['methods'])) {
  1793.                                             $list[] = $val;
  1794.                                         } else {
  1795.                                             $list[] = ['code' => $key'methods' => $val];
  1796.                                         }
  1797.                                     } elseif (true === $val || null === $val) {
  1798.                                         $list[] = ['code' => $key];
  1799.                                     }
  1800.                                 }
  1801.                                 return $list;
  1802.                             })
  1803.                         ->end()
  1804.                         ->useAttributeAsKey('code')
  1805.                         ->arrayPrototype()
  1806.                             ->fixXmlConfig('method')
  1807.                             ->children()
  1808.                                 ->integerNode('code')->end()
  1809.                                 ->arrayNode('methods')
  1810.                                     ->beforeNormalization()
  1811.                                     ->ifArray()
  1812.                                         ->then(function ($v) {
  1813.                                             return array_map('strtoupper'$v);
  1814.                                         })
  1815.                                     ->end()
  1816.                                     ->prototype('scalar')->end()
  1817.                                     ->info('A list of HTTP methods that triggers a retry for this status code. When empty, all methods are retried')
  1818.                                 ->end()
  1819.                             ->end()
  1820.                         ->end()
  1821.                         ->info('A list of HTTP status code that triggers a retry')
  1822.                     ->end()
  1823.                     ->integerNode('max_retries')->defaultValue(3)->min(0)->end()
  1824.                     ->integerNode('delay')->defaultValue(1000)->min(0)->info('Time in ms to delay (or the initial value when multiplier is used)')->end()
  1825.                     ->floatNode('multiplier')->defaultValue(2)->min(1)->info('If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries)')->end()
  1826.                     ->integerNode('max_delay')->defaultValue(0)->min(0)->info('Max time in ms that a retry should ever be delayed (0 = infinite)')->end()
  1827.                     ->floatNode('jitter')->defaultValue(0.1)->min(0)->max(1)->info('Randomness in percent (between 0 and 1) to apply to the delay')->end()
  1828.                 ->end()
  1829.         ;
  1830.     }
  1831.     private function addMailerSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1832.     {
  1833.         $rootNode
  1834.             ->children()
  1835.                 ->arrayNode('mailer')
  1836.                     ->info('Mailer configuration')
  1837.                     ->{$enableIfStandalone('symfony/mailer'Mailer::class)}()
  1838.                     ->validate()
  1839.                         ->ifTrue(function ($v) { return isset($v['dsn']) && \count($v['transports']); })
  1840.                         ->thenInvalid('"dsn" and "transports" cannot be used together.')
  1841.                     ->end()
  1842.                     ->fixXmlConfig('transport')
  1843.                     ->fixXmlConfig('header')
  1844.                     ->children()
  1845.                         ->scalarNode('message_bus')->defaultNull()->info('The message bus to use. Defaults to the default bus if the Messenger component is installed.')->end()
  1846.                         ->scalarNode('dsn')->defaultNull()->end()
  1847.                         ->arrayNode('transports')
  1848.                             ->useAttributeAsKey('name')
  1849.                             ->prototype('scalar')->end()
  1850.                         ->end()
  1851.                         ->arrayNode('envelope')
  1852.                             ->info('Mailer Envelope configuration')
  1853.                             ->children()
  1854.                                 ->scalarNode('sender')->end()
  1855.                                 ->arrayNode('recipients')
  1856.                                     ->performNoDeepMerging()
  1857.                                     ->beforeNormalization()
  1858.                                     ->ifArray()
  1859.                                         ->then(function ($v) {
  1860.                                             return array_filter(array_values($v));
  1861.                                         })
  1862.                                     ->end()
  1863.                                     ->prototype('scalar')->end()
  1864.                                 ->end()
  1865.                             ->end()
  1866.                         ->end()
  1867.                         ->arrayNode('headers')
  1868.                             ->normalizeKeys(false)
  1869.                             ->useAttributeAsKey('name')
  1870.                             ->prototype('array')
  1871.                                 ->normalizeKeys(false)
  1872.                                 ->beforeNormalization()
  1873.                                     ->ifTrue(function ($v) { return !\is_array($v) || array_keys($v) !== ['value']; })
  1874.                                     ->then(function ($v) { return ['value' => $v]; })
  1875.                                 ->end()
  1876.                                 ->children()
  1877.                                     ->variableNode('value')->end()
  1878.                                 ->end()
  1879.                             ->end()
  1880.                         ->end()
  1881.                     ->end()
  1882.                 ->end()
  1883.             ->end()
  1884.         ;
  1885.     }
  1886.     private function addNotifierSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1887.     {
  1888.         $rootNode
  1889.             ->children()
  1890.                 ->arrayNode('notifier')
  1891.                     ->info('Notifier configuration')
  1892.                     ->{$enableIfStandalone('symfony/notifier'Notifier::class)}()
  1893.                     ->fixXmlConfig('chatter_transport')
  1894.                     ->children()
  1895.                         ->arrayNode('chatter_transports')
  1896.                             ->useAttributeAsKey('name')
  1897.                             ->prototype('scalar')->end()
  1898.                         ->end()
  1899.                     ->end()
  1900.                     ->fixXmlConfig('texter_transport')
  1901.                     ->children()
  1902.                         ->arrayNode('texter_transports')
  1903.                             ->useAttributeAsKey('name')
  1904.                             ->prototype('scalar')->end()
  1905.                         ->end()
  1906.                     ->end()
  1907.                     ->children()
  1908.                         ->booleanNode('notification_on_failed_messages')->defaultFalse()->end()
  1909.                     ->end()
  1910.                     ->children()
  1911.                         ->arrayNode('channel_policy')
  1912.                             ->useAttributeAsKey('name')
  1913.                             ->prototype('array')
  1914.                                 ->beforeNormalization()->ifString()->then(function (string $v) { return [$v]; })->end()
  1915.                                 ->prototype('scalar')->end()
  1916.                             ->end()
  1917.                         ->end()
  1918.                     ->end()
  1919.                     ->fixXmlConfig('admin_recipient')
  1920.                     ->children()
  1921.                         ->arrayNode('admin_recipients')
  1922.                             ->prototype('array')
  1923.                                 ->children()
  1924.                                     ->scalarNode('email')->cannotBeEmpty()->end()
  1925.                                     ->scalarNode('phone')->defaultValue('')->end()
  1926.                                 ->end()
  1927.                             ->end()
  1928.                         ->end()
  1929.                     ->end()
  1930.                 ->end()
  1931.             ->end()
  1932.         ;
  1933.     }
  1934.     private function addRateLimiterSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  1935.     {
  1936.         $rootNode
  1937.             ->children()
  1938.                 ->arrayNode('rate_limiter')
  1939.                     ->info('Rate limiter configuration')
  1940.                     ->{$enableIfStandalone('symfony/rate-limiter'TokenBucketLimiter::class)}()
  1941.                     ->fixXmlConfig('limiter')
  1942.                     ->beforeNormalization()
  1943.                         ->ifTrue(function ($v) { return \is_array($v) && !isset($v['limiters']) && !isset($v['limiter']); })
  1944.                         ->then(function (array $v) {
  1945.                             $newV = [
  1946.                                 'enabled' => $v['enabled'] ?? true,
  1947.                             ];
  1948.                             unset($v['enabled']);
  1949.                             $newV['limiters'] = $v;
  1950.                             return $newV;
  1951.                         })
  1952.                     ->end()
  1953.                     ->children()
  1954.                         ->arrayNode('limiters')
  1955.                             ->useAttributeAsKey('name')
  1956.                             ->arrayPrototype()
  1957.                                 ->children()
  1958.                                     ->scalarNode('lock_factory')
  1959.                                         ->info('The service ID of the lock factory used by this limiter (or null to disable locking)')
  1960.                                         ->defaultValue('lock.factory')
  1961.                                     ->end()
  1962.                                     ->scalarNode('cache_pool')
  1963.                                         ->info('The cache pool to use for storing the current limiter state')
  1964.                                         ->defaultValue('cache.rate_limiter')
  1965.                                     ->end()
  1966.                                     ->scalarNode('storage_service')
  1967.                                         ->info('The service ID of a custom storage implementation, this precedes any configured "cache_pool"')
  1968.                                         ->defaultNull()
  1969.                                     ->end()
  1970.                                     ->enumNode('policy')
  1971.                                         ->info('The algorithm to be used by this limiter')
  1972.                                         ->isRequired()
  1973.                                         ->values(['fixed_window''token_bucket''sliding_window''no_limit'])
  1974.                                     ->end()
  1975.                                     ->integerNode('limit')
  1976.                                         ->info('The maximum allowed hits in a fixed interval or burst')
  1977.                                         ->isRequired()
  1978.                                     ->end()
  1979.                                     ->scalarNode('interval')
  1980.                                         ->info('Configures the fixed interval if "policy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).')
  1981.                                     ->end()
  1982.                                     ->arrayNode('rate')
  1983.                                         ->info('Configures the fill rate if "policy" is set to "token_bucket"')
  1984.                                         ->children()
  1985.                                             ->scalarNode('interval')
  1986.                                                 ->info('Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).')
  1987.                                             ->end()
  1988.                                             ->integerNode('amount')->info('Amount of tokens to add each interval')->defaultValue(1)->end()
  1989.                                         ->end()
  1990.                                     ->end()
  1991.                                 ->end()
  1992.                             ->end()
  1993.                         ->end()
  1994.                     ->end()
  1995.                 ->end()
  1996.             ->end()
  1997.         ;
  1998.     }
  1999.     private function addUidSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  2000.     {
  2001.         $rootNode
  2002.             ->children()
  2003.                 ->arrayNode('uid')
  2004.                     ->info('Uid configuration')
  2005.                     ->{$enableIfStandalone('symfony/uid'UuidFactory::class)}()
  2006.                     ->addDefaultsIfNotSet()
  2007.                     ->children()
  2008.                         ->enumNode('default_uuid_version')
  2009.                             ->defaultValue(6)
  2010.                             ->values([641])
  2011.                         ->end()
  2012.                         ->enumNode('name_based_uuid_version')
  2013.                             ->defaultValue(5)
  2014.                             ->values([53])
  2015.                         ->end()
  2016.                         ->scalarNode('name_based_uuid_namespace')
  2017.                             ->cannotBeEmpty()
  2018.                         ->end()
  2019.                         ->enumNode('time_based_uuid_version')
  2020.                             ->defaultValue(6)
  2021.                             ->values([61])
  2022.                         ->end()
  2023.                         ->scalarNode('time_based_uuid_node')
  2024.                             ->cannotBeEmpty()
  2025.                         ->end()
  2026.                     ->end()
  2027.                 ->end()
  2028.             ->end()
  2029.         ;
  2030.     }
  2031.     private function addHtmlSanitizerSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
  2032.     {
  2033.         $rootNode
  2034.             ->children()
  2035.                 ->arrayNode('html_sanitizer')
  2036.                     ->info('HtmlSanitizer configuration')
  2037.                     ->{$enableIfStandalone('symfony/html-sanitizer'HtmlSanitizerInterface::class)}()
  2038.                     ->fixXmlConfig('sanitizer')
  2039.                     ->children()
  2040.                         ->arrayNode('sanitizers')
  2041.                             ->useAttributeAsKey('name')
  2042.                             ->arrayPrototype()
  2043.                                 ->fixXmlConfig('allow_element')
  2044.                                 ->fixXmlConfig('block_element')
  2045.                                 ->fixXmlConfig('drop_element')
  2046.                                 ->fixXmlConfig('allow_attribute')
  2047.                                 ->fixXmlConfig('drop_attribute')
  2048.                                 ->fixXmlConfig('force_attribute')
  2049.                                 ->fixXmlConfig('allowed_link_scheme')
  2050.                                 ->fixXmlConfig('allowed_link_host')
  2051.                                 ->fixXmlConfig('allowed_media_scheme')
  2052.                                 ->fixXmlConfig('allowed_media_host')
  2053.                                 ->fixXmlConfig('with_attribute_sanitizer')
  2054.                                 ->fixXmlConfig('without_attribute_sanitizer')
  2055.                                 ->children()
  2056.                                     ->booleanNode('allow_safe_elements')
  2057.                                         ->info('Allows "safe" elements and attributes.')
  2058.                                         ->defaultFalse()
  2059.                                     ->end()
  2060.                                     ->booleanNode('allow_static_elements')
  2061.                                         ->info('Allows all static elements and attributes from the W3C Sanitizer API standard.')
  2062.                                         ->defaultFalse()
  2063.                                     ->end()
  2064.                                     ->arrayNode('allow_elements')
  2065.                                         ->info('Configures the elements that the sanitizer should retain from the input. The element name is the key, the value is either a list of allowed attributes for this element or "*" to allow the default set of attributes (https://wicg.github.io/sanitizer-api/#default-configuration).')
  2066.                                         ->example(['i' => '*''a' => ['title'], 'span' => 'class'])
  2067.                                         ->normalizeKeys(false)
  2068.                                         ->useAttributeAsKey('name')
  2069.                                         ->variablePrototype()
  2070.                                             ->beforeNormalization()
  2071.                                                 ->ifArray()->then(fn ($n) => $n['attribute'] ?? $n)
  2072.                                             ->end()
  2073.                                             ->validate()
  2074.                                                 ->ifTrue(fn ($n): bool => !\is_string($n) && !\is_array($n))
  2075.                                                 ->thenInvalid('The value must be either a string or an array of strings.')
  2076.                                             ->end()
  2077.                                         ->end()
  2078.                                     ->end()
  2079.                                     ->arrayNode('block_elements')
  2080.                                         ->info('Configures elements as blocked. Blocked elements are elements the sanitizer should remove from the input, but retain their children.')
  2081.                                         ->beforeNormalization()
  2082.                                             ->ifString()
  2083.                                             ->then(fn (string $n): array => (array) $n)
  2084.                                         ->end()
  2085.                                         ->scalarPrototype()->end()
  2086.                                     ->end()
  2087.                                     ->arrayNode('drop_elements')
  2088.                                         ->info('Configures elements as dropped. Dropped elements are elements the sanitizer should remove from the input, including their children.')
  2089.                                         ->beforeNormalization()
  2090.                                             ->ifString()
  2091.                                             ->then(fn (string $n): array => (array) $n)
  2092.                                         ->end()
  2093.                                         ->scalarPrototype()->end()
  2094.                                     ->end()
  2095.                                     ->arrayNode('allow_attributes')
  2096.                                         ->info('Configures attributes as allowed. Allowed attributes are attributes the sanitizer should retain from the input.')
  2097.                                         ->normalizeKeys(false)
  2098.                                         ->useAttributeAsKey('name')
  2099.                                         ->variablePrototype()
  2100.                                             ->beforeNormalization()
  2101.                                                 ->ifArray()->then(fn ($n) => $n['element'] ?? $n)
  2102.                                             ->end()
  2103.                                         ->end()
  2104.                                     ->end()
  2105.                                     ->arrayNode('drop_attributes')
  2106.                                         ->info('Configures attributes as dropped. Dropped attributes are attributes the sanitizer should remove from the input.')
  2107.                                         ->normalizeKeys(false)
  2108.                                         ->useAttributeAsKey('name')
  2109.                                         ->variablePrototype()
  2110.                                             ->beforeNormalization()
  2111.                                                 ->ifArray()->then(fn ($n) => $n['element'] ?? $n)
  2112.                                             ->end()
  2113.                                         ->end()
  2114.                                     ->end()
  2115.                                     ->arrayNode('force_attributes')
  2116.                                         ->info('Forcefully set the values of certain attributes on certain elements.')
  2117.                                         ->normalizeKeys(false)
  2118.                                         ->useAttributeAsKey('name')
  2119.                                         ->arrayPrototype()
  2120.                                             ->normalizeKeys(false)
  2121.                                             ->useAttributeAsKey('name')
  2122.                                             ->scalarPrototype()->end()
  2123.                                         ->end()
  2124.                                     ->end()
  2125.                                     ->booleanNode('force_https_urls')
  2126.                                         ->info('Transforms URLs using the HTTP scheme to use the HTTPS scheme instead.')
  2127.                                         ->defaultFalse()
  2128.                                     ->end()
  2129.                                     ->arrayNode('allowed_link_schemes')
  2130.                                         ->info('Allows only a given list of schemes to be used in links href attributes.')
  2131.                                         ->scalarPrototype()->end()
  2132.                                     ->end()
  2133.                                     ->variableNode('allowed_link_hosts')
  2134.                                         ->info('Allows only a given list of hosts to be used in links href attributes.')
  2135.                                         ->defaultValue(null)
  2136.                                         ->validate()
  2137.                                             ->ifTrue(function ($v) { return !\is_array($v) && null !== $v; })
  2138.                                             ->thenInvalid('The "allowed_link_hosts" parameter must be an array or null')
  2139.                                         ->end()
  2140.                                     ->end()
  2141.                                     ->booleanNode('allow_relative_links')
  2142.                                         ->info('Allows relative URLs to be used in links href attributes.')
  2143.                                         ->defaultFalse()
  2144.                                     ->end()
  2145.                                     ->arrayNode('allowed_media_schemes')
  2146.                                         ->info('Allows only a given list of schemes to be used in media source attributes (img, audio, video, ...).')
  2147.                                         ->scalarPrototype()->end()
  2148.                                     ->end()
  2149.                                     ->variableNode('allowed_media_hosts')
  2150.                                         ->info('Allows only a given list of hosts to be used in media source attributes (img, audio, video, ...).')
  2151.                                         ->defaultValue(null)
  2152.                                         ->validate()
  2153.                                             ->ifTrue(function ($v) { return !\is_array($v) && null !== $v; })
  2154.                                             ->thenInvalid('The "allowed_media_hosts" parameter must be an array or null')
  2155.                                         ->end()
  2156.                                     ->end()
  2157.                                     ->booleanNode('allow_relative_medias')
  2158.                                         ->info('Allows relative URLs to be used in media source attributes (img, audio, video, ...).')
  2159.                                         ->defaultFalse()
  2160.                                     ->end()
  2161.                                     ->arrayNode('with_attribute_sanitizers')
  2162.                                         ->info('Registers custom attribute sanitizers.')
  2163.                                         ->scalarPrototype()->end()
  2164.                                     ->end()
  2165.                                     ->arrayNode('without_attribute_sanitizers')
  2166.                                         ->info('Unregisters custom attribute sanitizers.')
  2167.                                         ->scalarPrototype()->end()
  2168.                                     ->end()
  2169.                                     ->integerNode('max_input_length')
  2170.                                         ->info('The maximum length allowed for the sanitized input.')
  2171.                                         ->defaultValue(0)
  2172.                                     ->end()
  2173.                                 ->end()
  2174.                             ->end()
  2175.                         ->end()
  2176.                     ->end()
  2177.                 ->end()
  2178.             ->end()
  2179.         ;
  2180.     }
  2181. }