vendor/pimcore/pimcore/bundles/CoreBundle/DependencyInjection/Configuration.php line 54

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace Pimcore\Bundle\CoreBundle\DependencyInjection;
  15. use Pimcore\Bundle\CoreBundle\DependencyInjection\Config\Processor\PlaceholderProcessor;
  16. use Pimcore\Cache\Pool\Redis;
  17. use Pimcore\Storage\Redis\ConnectionFactory;
  18. use Pimcore\Targeting\Storage\CookieStorage;
  19. use Pimcore\Targeting\Storage\TargetingStorageInterface;
  20. use Pimcore\Workflow\EventSubscriber\ChangePublishedStateSubscriber;
  21. use Pimcore\Workflow\EventSubscriber\NotificationSubscriber;
  22. use Pimcore\Workflow\Notification\NotificationEmailService;
  23. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  24. use Symfony\Component\Config\Definition\Builder\NodeDefinition;
  25. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  26. use Symfony\Component\Config\Definition\ConfigurationInterface;
  27. class Configuration implements ConfigurationInterface
  28. {
  29.     /**
  30.      * @var PlaceholderProcessor
  31.      */
  32.     private $placeholderProcessor;
  33.     private $placeholders = [];
  34.     public function __construct()
  35.     {
  36.         $this->placeholderProcessor = new PlaceholderProcessor();
  37.         $this->placeholders = [];
  38.     }
  39.     /**
  40.      * Generates the configuration tree builder.
  41.      *
  42.      * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
  43.      */
  44.     public function getConfigTreeBuilder()
  45.     {
  46.         $treeBuilder = new TreeBuilder();
  47.         $rootNode $treeBuilder->root('pimcore');
  48.         $rootNode->addDefaultsIfNotSet();
  49.         $rootNode->ignoreExtraKeys();
  50.         $rootNode
  51.             ->children()
  52.                 ->arrayNode('error_handling')
  53.                     ->addDefaultsIfNotSet()
  54.                     ->children()
  55.                         ->booleanNode('render_error_document')
  56.                             ->info('Render error document in case of an error instead of showing Symfony\'s error page')
  57.                             ->defaultTrue()
  58.                             ->beforeNormalization()
  59.                                 ->ifString()
  60.                                 ->then(function ($v) {
  61.                                     return (bool)$v;
  62.                                 })
  63.                             ->end()
  64.                         ->end()
  65.                     ->end()
  66.                 ->end()
  67.                 ->arrayNode('bundles')
  68.                     ->addDefaultsIfNotSet()
  69.                     ->children()
  70.                         ->arrayNode('search_paths')
  71.                             ->prototype('scalar')->end()
  72.                         ->end()
  73.                         ->booleanNode('handle_composer')
  74.                             ->defaultTrue()
  75.                         ->end()
  76.                     ->end()
  77.                 ->end()
  78.                 ->arrayNode('flags')
  79.                     ->info('Generic map for feature flags')
  80.                     ->prototype('scalar')->end()
  81.                 ->end()
  82.                 ->arrayNode('translations')
  83.                     ->addDefaultsIfNotSet()
  84.                     ->children()
  85.                         ->booleanNode('case_insensitive')
  86.                             ->beforeNormalization()
  87.                                 ->ifString()
  88.                                 ->then(function ($v) {
  89.                                     return (bool)$v;
  90.                                 })
  91.                             ->end()
  92.                             ->info('Force Pimcore translations to NOT be case sensitive. This only applies to translations set via Pimcore\'s translator (e.g. website translations)')
  93.                             ->defaultFalse()
  94.                         ->end()
  95.                         ->arrayNode('debugging')
  96.                             ->info('If debugging is enabled, the translator will return the plain translation key instead of the translated message.')
  97.                             ->addDefaultsIfNotSet()
  98.                             ->canBeDisabled()
  99.                             ->children()
  100.                                 ->scalarNode('parameter')
  101.                                     ->defaultValue('pimcore_debug_translations')
  102.                                 ->end()
  103.                             ->end()
  104.                         ->end()
  105.                         ->arrayNode('data_object')
  106.                             ->addDefaultsIfNotSet()
  107.                             ->children()
  108.                                 ->arrayNode('translation_extractor')
  109.                                     ->children()
  110.                                         ->arrayNode('attributes')
  111.                                             ->info('Can be used to restrict the extracted localized fields (e.g. used by XLIFF exporter in the Pimcore backend)')
  112.                                             ->prototype('array')
  113.                                                 ->prototype('scalar')->end()
  114.                                             ->end()
  115.                                             ->example(
  116.                                                 [
  117.                                                     'Product' => ['name''description'],
  118.                                                     'Brand' => ['name'],
  119.                                                 ]
  120.                                             )
  121.                                         ->end()
  122.                                     ->end()
  123.                                 ->end()
  124.                             ->end()
  125.                         ->end()
  126.                     ->end()
  127.                 ->end()
  128.                 ->arrayNode('maps')
  129.                     ->addDefaultsIfNotSet()
  130.                     ->children()
  131.                         ->scalarNode('tile_layer_url_template')
  132.                             ->defaultValue('https://a.tile.openstreetmap.org/{z}/{x}/{y}.png')
  133.                         ->end()
  134.                         ->scalarNode('geocoding_url_template')
  135.                             ->defaultValue('https://nominatim.openstreetmap.org/search?q={q}&addressdetails=1&format=json&limit=1')
  136.                         ->end()
  137.                         ->scalarNode('reverse_geocoding_url_template')
  138.                             ->defaultValue('https://nominatim.openstreetmap.org/reverse?format=json&lat={lat}&lon={lon}&addressdetails=1')
  139.                         ->end()
  140.                     ->end()
  141.                 ->end()
  142.             ->end();
  143.         $this->addGeneralNode($rootNode);
  144.         $this->addServicesNode($rootNode);
  145.         $this->addObjectsNode($rootNode);
  146.         $this->addAssetNode($rootNode);
  147.         $this->addDocumentsNode($rootNode);
  148.         $this->addEncryptionNode($rootNode);
  149.         $this->addModelsNode($rootNode);
  150.         $this->addRoutingNode($rootNode);
  151.         $this->addCacheNode($rootNode);
  152.         $this->addContextNode($rootNode);
  153.         $this->addAdminNode($rootNode);
  154.         $this->addWebProfilerNode($rootNode);
  155.         $this->addSecurityNode($rootNode);
  156.         $this->addEmailNode($rootNode);
  157.         $this->addNewsletterNode($rootNode);
  158.         $this->addCustomReportsNode($rootNode);
  159.         $this->addMigrationsNode($rootNode);
  160.         $this->addTargetingNode($rootNode);
  161.         $this->addSitemapsNode($rootNode);
  162.         $this->addMimeNode($rootNode);
  163.         $this->addWorkflowNode($rootNode);
  164.         $this->addHttpClientNode($rootNode);
  165.         $this->addApplicationLogNode($rootNode);
  166.         return $treeBuilder;
  167.     }
  168.     /**
  169.      * Add general config
  170.      *
  171.      * @param ArrayNodeDefinition $rootNode
  172.      */
  173.     private function addGeneralNode(ArrayNodeDefinition $rootNode)
  174.     {
  175.         $rootNode
  176.             ->children()
  177.             ->arrayNode('general')
  178.             ->ignoreExtraKeys()
  179.             ->addDefaultsIfNotSet()
  180.             ->children()
  181.                 ->scalarNode('timezone')
  182.                     ->defaultValue('Europe/Berlin')
  183.                 ->end()
  184.                 ->scalarNode('path_variable')
  185.                     ->defaultNull()
  186.                 ->end()
  187.                 ->scalarNode('domain')
  188.                     ->defaultNull()
  189.                 ->end()
  190.                 ->booleanNode('redirect_to_maindomain')
  191.                     ->beforeNormalization()
  192.                         ->ifString()
  193.                         ->then(function ($v) {
  194.                             return (bool)$v;
  195.                         })
  196.                     ->end()
  197.                     ->defaultFalse()
  198.                 ->end()
  199.                 ->scalarNode('language')
  200.                     ->defaultValue('en')
  201.                 ->end()
  202.                 ->scalarNode('valid_languages')
  203.                     ->defaultValue('en')
  204.                 ->end()
  205.                 ->arrayNode('fallback_languages')
  206.                     ->performNoDeepMerging()
  207.                     ->beforeNormalization()
  208.                     ->ifArray()
  209.                         ->then(function ($v) {
  210.                             return $v;
  211.                         })
  212.                     ->end()
  213.                     ->prototype('scalar')
  214.                     ->end()
  215.                 ->end()
  216.                 ->scalarNode('default_language')
  217.                     ->defaultValue('en')
  218.                 ->end()
  219.                 ->booleanNode('disable_usage_statistics')
  220.                     ->beforeNormalization()
  221.                         ->ifString()
  222.                         ->then(function ($v) {
  223.                             return (bool)$v;
  224.                         })
  225.                     ->end()
  226.                     ->defaultFalse()
  227.                 ->end()
  228.                 ->booleanNode('debug_admin_translations')
  229.                     ->beforeNormalization()
  230.                         ->ifString()
  231.                         ->then(function ($v) {
  232.                             return (bool)$v;
  233.                         })
  234.                     ->end()
  235.                     ->defaultFalse()
  236.                 ->end()
  237.                 ->scalarNode('instance_identifier')
  238.                     ->defaultNull()->end()
  239.                 ->booleanNode('show_cookie_notice')
  240.                     ->beforeNormalization()
  241.                         ->ifString()
  242.                         ->then(function ($v) {
  243.                             return (bool)$v;
  244.                         })
  245.                     ->end()
  246.                     ->defaultFalse()
  247.                 ->end()
  248.             ->end();
  249.     }
  250.     /**
  251.      * @param ArrayNodeDefinition $rootNode
  252.      */
  253.     private function addServicesNode(ArrayNodeDefinition $rootNode)
  254.     {
  255.         $rootNode
  256.             ->children()
  257.             ->arrayNode('services')
  258.                 ->children()
  259.                     ->arrayNode('google')
  260.                     ->children()
  261.                         ->scalarNode('client_id')
  262.                             ->defaultNull()
  263.                         ->end()
  264.                         ->scalarNode('email')
  265.                             ->defaultNull()
  266.                         ->end()
  267.                         ->scalarNode('simple_api_key')
  268.                             ->defaultNull()
  269.                         ->end()
  270.                         ->scalarNode('browser_api_key')
  271.                             ->defaultNull()
  272.                         ->end()
  273.                     ->end()
  274.                     ->end()
  275.                 ->end()
  276.             ->end()
  277.             ->arrayNode('webservice')
  278.                 ->canBeEnabled()
  279.             ->end();
  280.     }
  281.     /**
  282.      * @param ArrayNodeDefinition $rootNode
  283.      */
  284.     private function addModelsNode(ArrayNodeDefinition $rootNode)
  285.     {
  286.         $rootNode
  287.             ->children()
  288.                 ->arrayNode('models')
  289.                     ->addDefaultsIfNotSet()
  290.                     ->children()
  291.                         ->arrayNode('class_overrides')
  292.                             ->useAttributeAsKey('name')
  293.                             ->prototype('scalar');
  294.     }
  295.     /**
  296.      * @param ArrayNodeDefinition $rootNode
  297.      */
  298.     private function addHttpClientNode(ArrayNodeDefinition $rootNode)
  299.     {
  300.         $rootNode
  301.             ->children()
  302.                 ->arrayNode('httpclient')
  303.                 ->addDefaultsIfNotSet()
  304.                     ->children()
  305.                         ->scalarNode('adapter')
  306.                             ->defaultValue('Socket')
  307.                         ->end()
  308.                         ->scalarNode('proxy_host')
  309.                             ->defaultNull()
  310.                         ->end()
  311.                         ->scalarNode('proxy_port')
  312.                             ->defaultNull()
  313.                         ->end()
  314.                         ->scalarNode('proxy_user')
  315.                             ->defaultNull()
  316.                         ->end()
  317.                         ->scalarNode('proxy_pass')
  318.                             ->defaultNull()
  319.                         ->end()
  320.                     ->end()
  321.                 ->end()
  322.             ->end();
  323.     }
  324.     /**
  325.      * @param ArrayNodeDefinition $rootNode
  326.      */
  327.     private function addApplicationLogNode(ArrayNodeDefinition $rootNode)
  328.     {
  329.         $rootNode
  330.             ->children()
  331.                 ->arrayNode('applicationlog')
  332.                 ->addDefaultsIfNotSet()
  333.                     ->children()
  334.                         ->arrayNode('mail_notification')
  335.                             ->children()
  336.                                 ->booleanNode('send_log_summary')
  337.                                     ->beforeNormalization()
  338.                                         ->ifString()
  339.                                         ->then(function ($v) {
  340.                                             return (bool)$v;
  341.                                         })
  342.                                     ->end()
  343.                                     ->defaultFalse()
  344.                                 ->end()
  345.                                 ->scalarNode('filter_priority')
  346.                                     ->defaultNull()
  347.                                 ->end()
  348.                                 ->scalarNode('mail_receiver')
  349.                                 ->end()
  350.                             ->end()
  351.                         ->end()
  352.                         ->scalarNode('archive_treshold')
  353.                             ->defaultValue('')
  354.                         ->end()
  355.                         ->scalarNode('archive_alternative_database')
  356.                             ->defaultValue('')
  357.                         ->end()
  358.                     ->end()
  359.             ->end();
  360.     }
  361.     /**
  362.      * Add asset specific extension config
  363.      *
  364.      * @param ArrayNodeDefinition $rootNode
  365.      */
  366.     private function addAssetNode(ArrayNodeDefinition $rootNode)
  367.     {
  368.         $rootNode
  369.             ->children()
  370.                 ->arrayNode('assets')
  371.                 ->ignoreExtraKeys()
  372.                 ->addDefaultsIfNotSet()
  373.                 ->children()
  374.                     ->scalarNode('preview_image_thumbnail')
  375.                         ->defaultNull()
  376.                         ->end()
  377.                     ->scalarNode('default_upload_path')
  378.                         ->defaultValue('_default_upload_bucket')
  379.                         ->end()
  380.                     ->integerNode('tree_paging_limit')
  381.                         ->defaultValue(100)
  382.                         ->end()
  383.                     ->arrayNode('image')
  384.                         ->addDefaultsIfNotSet()
  385.                         ->children()
  386.                             ->arrayNode('low_quality_image_preview')
  387.                                 ->addDefaultsIfNotSet()
  388.                                 ->canBeDisabled()
  389.                                 ->children()
  390.                                     ->scalarNode('generator')
  391.                                     ->defaultNull()
  392.                                     ->end()
  393.                                 ->end()
  394.                             ->end()
  395.                             ->arrayNode('focal_point_detection')
  396.                                 ->addDefaultsIfNotSet()
  397.                                 ->canBeDisabled()
  398.                             ->end()
  399.                             ->arrayNode('thumbnails')
  400.                                 ->addDefaultsIfNotSet()
  401.                                 ->children()
  402.                                     ->booleanNode('webp_auto_support')
  403.                                         ->beforeNormalization()
  404.                                             ->ifString()
  405.                                             ->then(function ($v) {
  406.                                                 return (bool)$v;
  407.                                             })
  408.                                         ->end()
  409.                                         ->defaultTrue()
  410.                                     ->end()
  411.                                     ->booleanNode('auto_clear_temp_files')
  412.                                         ->beforeNormalization()
  413.                                             ->ifString()
  414.                                             ->then(function ($v) {
  415.                                                 return (bool)$v;
  416.                                             })
  417.                                         ->end()
  418.                                         ->defaultTrue()
  419.                                     ->end()
  420.                                 ->end()
  421.                             ->end()
  422.                         ->end()
  423.                     ->end()
  424.                     ->arrayNode('video')
  425.                         ->addDefaultsIfNotSet()
  426.                         ->children()
  427.                             ->arrayNode('thumbnails')
  428.                                 ->addDefaultsIfNotSet()
  429.                                 ->children()
  430.                                     ->booleanNode('auto_clear_temp_files')
  431.                                     ->defaultTrue()
  432.                                     ->end()
  433.                                 ->end()
  434.                             ->end()
  435.                         ->end()
  436.                     ->end()
  437.                     ->arrayNode('versions')
  438.                         ->addDefaultsIfNotSet()
  439.                         ->children()
  440.                             ->scalarNode('days')
  441.                                 ->defaultNull()
  442.                             ->end()
  443.                             ->scalarNode('steps')
  444.                                 ->defaultNull()
  445.                             ->end()
  446.                             ->booleanNode('use_hardlinks')
  447.                                 ->beforeNormalization()
  448.                                     ->ifString()
  449.                                     ->then(function ($v) {
  450.                                         return (bool)$v;
  451.                                     })
  452.                                 ->end()
  453.                                 ->defaultTrue()
  454.                             ->end()
  455.                         ->end()
  456.                     ->end()
  457.                     ->scalarNode('icc_rgb_profile')
  458.                         ->defaultNull()
  459.                     ->end()
  460.                     ->scalarNode('icc_cmyk_profile')
  461.                         ->defaultNull()
  462.                     ->end()
  463.                     ->booleanNode('hide_edit_image')
  464.                         ->defaultFalse()
  465.                     ->end()
  466.                     ->booleanNode('disable_tree_preview')
  467.                         ->defaultTrue()
  468.                     ->end()
  469.                 ->end()
  470.             ->end();
  471.     }
  472.     /**
  473.      * Add object specific extension config
  474.      *
  475.      * @param ArrayNodeDefinition $rootNode
  476.      */
  477.     private function addObjectsNode(ArrayNodeDefinition $rootNode)
  478.     {
  479.         $objectsNode $rootNode
  480.             ->children()
  481.                 ->arrayNode('objects')
  482.                     ->ignoreExtraKeys()
  483.                     ->addDefaultsIfNotSet()
  484.                     ->children()
  485.                         ->integerNode('tree_paging_limit')
  486.                             ->defaultValue(30)
  487.                         ->end()
  488.                         ->arrayNode('versions')
  489.                             ->children()
  490.                                 ->scalarNode('days')->defaultNull()->end()
  491.                                 ->scalarNode('steps')->defaultNull()->end()
  492.                             ->end()
  493.                         ->end()
  494.                     ->end();
  495.         $classDefinitionsNode $objectsNode
  496.             ->children()
  497.                 ->arrayNode('class_definitions')
  498.                     ->addDefaultsIfNotSet();
  499.         $this->addImplementationLoaderNode($classDefinitionsNode'data');
  500.         $this->addImplementationLoaderNode($classDefinitionsNode'layout');
  501.     }
  502.     /**
  503.      * Add encryption specific extension config
  504.      *
  505.      * @param ArrayNodeDefinition $rootNode
  506.      */
  507.     private function addEncryptionNode(ArrayNodeDefinition $rootNode)
  508.     {
  509.         $encryptionNode $rootNode
  510.             ->children()
  511.             ->arrayNode('encryption')->addDefaultsIfNotSet();
  512.         $encryptionNode
  513.             ->children()
  514.             ->scalarNode('secret')->defaultNull();
  515.     }
  516.     /**
  517.      * Add document specific extension config
  518.      *
  519.      * @param ArrayNodeDefinition $rootNode
  520.      */
  521.     private function addDocumentsNode(ArrayNodeDefinition $rootNode)
  522.     {
  523.         $documentsNode $rootNode
  524.             ->children()
  525.                 ->arrayNode('documents')
  526.                     ->ignoreExtraKeys()
  527.                     ->addDefaultsIfNotSet();
  528.         $this->addImplementationLoaderNode($documentsNode'tags');
  529.         $documentsNode
  530.             ->children()
  531.                 ->arrayNode('versions')
  532.                     ->children()
  533.                         ->scalarNode('days')
  534.                             ->defaultNull()
  535.                         ->end()
  536.                         ->scalarNode('steps')
  537.                             ->defaultNull()
  538.                         ->end()
  539.                     ->end()
  540.                 ->end()
  541.                 ->arrayNode('error_pages')
  542.                     ->children()
  543.                         ->scalarNode('default')
  544.                             ->defaultNull()
  545.                         ->end()
  546.                     ->end()
  547.                 ->end()
  548.                 ->booleanNode('create_redirect_when_moved')
  549.                     ->beforeNormalization()
  550.                         ->ifString()
  551.                         ->then(function ($v) {
  552.                             return (bool)$v;
  553.                         })
  554.                     ->end()
  555.                     ->defaultFalse()
  556.                 ->end()
  557.                 ->scalarNode('allow_trailing_slash')
  558.                     ->defaultValue('no')
  559.                 ->end()
  560.                 ->booleanNode('generate_preview')
  561.                     ->beforeNormalization()
  562.                         ->ifString()
  563.                         ->then(function ($v) {
  564.                             return (bool)$v;
  565.                         })
  566.                     ->end()
  567.                     ->defaultFalse()
  568.                 ->end()
  569.                 ->integerNode('tree_paging_limit')
  570.                     ->defaultValue(50)
  571.                 ->end()
  572.                 ->arrayNode('editables')
  573.                     ->addDefaultsIfNotSet()
  574.                     ->children()
  575.                         ->enumNode('naming_strategy')
  576.                             ->info('Sets naming strategy used to build editable names')
  577.                             ->values(['legacy''nested'])
  578.                             ->defaultValue('nested')
  579.                         ->end()
  580.                     ->end()
  581.                 ->end()
  582.                 ->arrayNode('areas')
  583.                     ->addDefaultsIfNotSet()
  584.                     ->children()
  585.                         ->booleanNode('autoload')
  586.                             ->beforeNormalization()
  587.                                 ->ifString()
  588.                                 ->then(function ($v) {
  589.                                     return (bool)$v;
  590.                                 })
  591.                             ->end()
  592.                             ->defaultTrue()
  593.                         ->end()
  594.                     ->end()
  595.                 ->end()
  596.                 ->arrayNode('newsletter')
  597.                     ->addDefaultsIfNotSet()
  598.                     ->children()
  599.                         ->scalarNode('defaultUrlPrefix')
  600.                             ->defaultNull()
  601.                         ->end()
  602.                     ->end()
  603.                 ->end()
  604.             ->end();
  605.     }
  606.     /**
  607.      * Add implementation node config (map, prefixes)
  608.      *
  609.      * @param ArrayNodeDefinition $node
  610.      * @param string $name
  611.      */
  612.     private function addImplementationLoaderNode(ArrayNodeDefinition $node$name)
  613.     {
  614.         $node
  615.             ->children()
  616.                 ->arrayNode($name)
  617.                     ->addDefaultsIfNotSet()
  618.                     ->children()
  619.                         ->arrayNode('map')
  620.                             ->useAttributeAsKey('name')
  621.                             ->prototype('scalar')->end()
  622.                         ->end()
  623.                         ->arrayNode('prefixes')
  624.                             ->prototype('scalar')->end()
  625.                         ->end()
  626.                     ->end()
  627.                 ->end()
  628.             ->end();
  629.     }
  630.     private function addRoutingNode(ArrayNodeDefinition $rootNode)
  631.     {
  632.         $rootNode
  633.             ->children()
  634.                 ->arrayNode('routing')
  635.                     ->addDefaultsIfNotSet()
  636.                     ->children()
  637.                         ->arrayNode('defaults')
  638.                             ->addDefaultsIfNotSet()
  639.                             ->children()
  640.                                 ->scalarNode('bundle')
  641.                                     ->defaultValue('AppBundle')
  642.                                 ->end()
  643.                                 ->scalarNode('controller')
  644.                                     ->defaultValue('Default')
  645.                                 ->end()
  646.                                 ->scalarNode('action')
  647.                                     ->defaultValue('default')
  648.                                 ->end()
  649.                             ->end()
  650.                         ->end()
  651.                         ->arrayNode('static')
  652.                             ->addDefaultsIfNotSet()
  653.                             ->children()
  654.                                 ->arrayNode('locale_params')
  655.                                     ->info('Route params from this list will be mapped to _locale if _locale is not set explicitely')
  656.                                     ->prototype('scalar')
  657.                                     ->defaultValue([])
  658.                                 ->end()
  659.                             ->end()
  660.                         ->end()
  661.                     ->end()
  662.                 ->end();
  663.     }
  664.     /**
  665.      * Add context config
  666.      *
  667.      * @param ArrayNodeDefinition $rootNode
  668.      */
  669.     private function addContextNode(ArrayNodeDefinition $rootNode)
  670.     {
  671.         $contextNode $rootNode->children()
  672.             ->arrayNode('context');
  673.         /** @var ArrayNodeDefinition|NodeDefinition $prototype */
  674.         $prototype $contextNode->prototype('array');
  675.         // define routes child on each context entry
  676.         $this->addRoutesChild($prototype'routes');
  677.     }
  678.     /**
  679.      * Add admin config
  680.      *
  681.      * @param ArrayNodeDefinition $rootNode
  682.      */
  683.     private function addAdminNode(ArrayNodeDefinition $rootNode)
  684.     {
  685.         $adminNode $rootNode->children()
  686.             ->arrayNode('admin')
  687.             ->ignoreExtraKeys()
  688.             ->addDefaultsIfNotSet();
  689.         // add session attribute bag config
  690.         $this->addAdminSessionAttributeBags($adminNode);
  691.         // unauthenticated routes won't be double checked for authentication in AdminControllerListener
  692.         $this->addRoutesChild($adminNode'unauthenticated_routes');
  693.         $adminNode
  694.             ->children()
  695.                 ->arrayNode('translations')
  696.                     ->addDefaultsIfNotSet()
  697.                     ->children()
  698.                         ->scalarNode('path')->defaultNull()->end()
  699.                     ->end()
  700.                 ->end()
  701.             ->end();
  702.     }
  703.     /**
  704.      * @param ArrayNodeDefinition $adminNode
  705.      */
  706.     private function addAdminSessionAttributeBags(ArrayNodeDefinition $adminNode)
  707.     {
  708.         // Normalizes session bag config. Allows the following formats (all formats will be
  709.         // normalized to the third format.
  710.         //
  711.         // attribute_bags:
  712.         //      - foo
  713.         //      - bar
  714.         //
  715.         // attribute_bags:
  716.         //      foo: _foo
  717.         //      bar: _bar
  718.         //
  719.         // attribute_bags:
  720.         //      foo:
  721.         //          storage_key: _foo
  722.         //      bar:
  723.         //          storage_key: _bar
  724.         $normalizers = [
  725.             'assoc' => function (array $array) {
  726.                 $result = [];
  727.                 foreach ($array as $name => $value) {
  728.                     if (null === $value) {
  729.                         $value = [
  730.                             'storage_key' => '_' $name
  731.                         ];
  732.                     }
  733.                     if (is_string($value)) {
  734.                         $value = [
  735.                             'storage_key' => $value
  736.                         ];
  737.                     }
  738.                     $result[$name] = $value;
  739.                 }
  740.                 return $result;
  741.             },
  742.             'sequential' => function (array $array) {
  743.                 $result = [];
  744.                 foreach ($array as $name) {
  745.                     $result[$name] = [
  746.                         'storage_key' => '_' $name
  747.                     ];
  748.                 }
  749.                 return $result;
  750.             }
  751.         ];
  752.         $adminNode
  753.             ->children()
  754.                 ->arrayNode('session')
  755.                     ->addDefaultsIfNotSet()
  756.                     ->children()
  757.                         ->arrayNode('attribute_bags')
  758.                             ->useAttributeAsKey('name')
  759.                             ->beforeNormalization()
  760.                                 ->ifArray()->then(function ($v) use ($normalizers) {
  761.                                     if (isAssocArray($v)) {
  762.                                         return $normalizers['assoc']($v);
  763.                                     } else {
  764.                                         return $normalizers['sequential']($v);
  765.                                     }
  766.                                 })
  767.                             ->end()
  768.                             ->example([
  769.                                 ['foo''bar'],
  770.                                 [
  771.                                     'foo' => '_foo',
  772.                                     'bar' => '_bar',
  773.                                 ],
  774.                                 [
  775.                                     'foo' => [
  776.                                         'storage_key' => '_foo'
  777.                                     ],
  778.                                     'bar' => [
  779.                                         'storage_key' => '_bar'
  780.                                     ]
  781.                                 ]
  782.                             ])
  783.                             ->prototype('array')
  784.                                 ->children()
  785.                                     ->scalarNode('storage_key')
  786.                                         ->defaultNull()
  787.                                     ->end()
  788.                                 ->end()
  789.                             ->end()
  790.                         ->end()
  791.                     ->end()
  792.                 ->end()
  793.             ->end();
  794.     }
  795.     private function addSecurityNode(ArrayNodeDefinition $rootNode)
  796.     {
  797.         $rootNode
  798.             ->children()
  799.                 ->arrayNode('security')
  800.                     ->addDefaultsIfNotSet()
  801.                     ->children()
  802.                         ->arrayNode('encoder_factories')
  803.                             ->info('Encoder factories to use as className => factory service ID mapping')
  804.                             ->example([
  805.                                 'AppBundle\Model\DataObject\User1' => [
  806.                                     'id' => 'website_demo.security.encoder_factory2'
  807.                                 ],
  808.                                 'AppBundle\Model\DataObject\User2' => 'website_demo.security.encoder_factory2'
  809.                             ])
  810.                             ->useAttributeAsKey('class')
  811.                             ->prototype('array')
  812.                             ->beforeNormalization()->ifString()->then(function ($v) {
  813.                                 return ['id' => $v];
  814.                             })->end()
  815.                             ->children()
  816.                                 ->scalarNode('id')->end()
  817.                             ->end()
  818.                         ->end()
  819.                     ->end()
  820.                 ->end()
  821.             ->end()
  822.         ;
  823.     }
  824.     /**
  825.      * Configure exclude paths for web profiler toolbar
  826.      *
  827.      * @param ArrayNodeDefinition $rootNode
  828.      */
  829.     private function addWebProfilerNode(ArrayNodeDefinition $rootNode)
  830.     {
  831.         $webProfilerNode $rootNode->children()
  832.             ->arrayNode('web_profiler')
  833.                 ->example([
  834.                     'toolbar' => [
  835.                         'excluded_routes' => [
  836.                             ['path' => '^/test/path']
  837.                         ]
  838.                     ]
  839.                 ])
  840.                 ->addDefaultsIfNotSet();
  841.         $toolbarNode $webProfilerNode->children()
  842.             ->arrayNode('toolbar')
  843.                 ->addDefaultsIfNotSet();
  844.         $this->addRoutesChild($toolbarNode'excluded_routes');
  845.     }
  846.     /**
  847.      * Add a route prototype child
  848.      *
  849.      * @param ArrayNodeDefinition $parent
  850.      * @param $name
  851.      */
  852.     private function addRoutesChild(ArrayNodeDefinition $parent$name)
  853.     {
  854.         $node $parent->children()->arrayNode($name);
  855.         /** @var ArrayNodeDefinition|NodeDefinition $prototype */
  856.         $prototype $node->prototype('array');
  857.         $prototype
  858.             ->beforeNormalization()
  859.                 ->ifNull()->then(function () {
  860.                     return [];
  861.                 })
  862.             ->end()
  863.             ->children()
  864.                 ->scalarNode('path')->defaultFalse()->end()
  865.                 ->scalarNode('route')->defaultFalse()->end()
  866.                 ->scalarNode('host')->defaultFalse()->end()
  867.                 ->arrayNode('methods')
  868.                     ->prototype('scalar')->end()
  869.                 ->end()
  870.             ->end();
  871.     }
  872.     /**
  873.      * Add cache config
  874.      *
  875.      * @param ArrayNodeDefinition $rootNode
  876.      */
  877.     private function addCacheNode(ArrayNodeDefinition $rootNode)
  878.     {
  879.         $defaultOptions ConnectionFactory::getDefaultOptions();
  880.         $rootNode->children()
  881.             ->arrayNode('cache')
  882.             ->ignoreExtraKeys()
  883.             ->canBeDisabled()
  884.             ->addDefaultsIfNotSet()
  885.                 ->children()
  886.                     ->scalarNode('lifetime')
  887.                         ->defaultNull()
  888.                     ->end()
  889.                     ->scalarNode('exclude_patterns')->end()
  890.                     ->scalarNode('exclude_cookie')->end()
  891.                     ->scalarNode('pool_service_id')
  892.                         ->defaultValue(null)
  893.                     ->end()
  894.                     ->integerNode('default_lifetime')
  895.                         ->defaultValue(2419200// 28 days
  896.                     ->end()
  897.                     ->arrayNode('pools')
  898.                         ->addDefaultsIfNotSet()
  899.                         ->children()
  900.                             ->arrayNode('doctrine')
  901.                                 ->canBeDisabled()
  902.                                 ->children()
  903.                                     ->scalarNode('connection')
  904.                                         ->defaultValue('default')
  905.                                     ->end()
  906.                                 ->end()
  907.                             ->end()
  908.                             ->arrayNode('redis')
  909.                                 ->canBeEnabled()
  910.                                 ->children()
  911.                                     ->arrayNode('connection')
  912.                                         ->info('Redis connection options. See ' ConnectionFactory::class)
  913.                                         ->children()
  914.                                             ->scalarNode('server')->end()
  915.                                             ->integerNode('port')
  916.                                                 ->defaultValue($defaultOptions['port'])
  917.                                             ->end()
  918.                                             ->scalarNode('database')
  919.                                                 ->defaultValue($defaultOptions['database'])
  920.                                             ->end()
  921.                                             ->scalarNode('password')
  922.                                                 ->defaultValue($defaultOptions['password'])
  923.                                             ->end()
  924.                                             ->scalarNode('persistent')
  925.                                                 ->defaultValue($defaultOptions['persistent'])
  926.                                             ->end()
  927.                                             ->booleanNode('force_standalone')
  928.                                                 ->defaultValue($defaultOptions['force_standalone'])
  929.                                             ->end()
  930.                                             ->integerNode('connect_retries')
  931.                                                 ->defaultValue($defaultOptions['connect_retries'])
  932.                                             ->end()
  933.                                             ->floatNode('timeout')
  934.                                                 ->defaultValue($defaultOptions['timeout'])
  935.                                             ->end()
  936.                                             ->floatNode('read_timeout')
  937.                                                 ->defaultValue($defaultOptions['read_timeout'])
  938.                                             ->end()
  939.                                         ->end()
  940.                                     ->end()
  941.                                     ->arrayNode('options')
  942.                                         ->info('Redis cache pool options. See ' Redis::class)
  943.                                         ->children()
  944.                                             ->booleanNode('notMatchingTags')->end()
  945.                                             ->integerNode('compress_tags')->end()
  946.                                             ->integerNode('compress_data')->end()
  947.                                             ->integerNode('compress_threshold')->end()
  948.                                             ->scalarNode('compression_lib')->end()
  949.                                             ->booleanNode('use_lua')->end()
  950.                                             ->integerNode('lua_max_c_stack')->end()
  951.                                         ->end()
  952.                                     ->end()
  953.                                 ->end()
  954.                             ->end()
  955.                         ->end()
  956.                     ->end()
  957.                 ->end();
  958.     }
  959.     /**
  960.      * Adds configuration for email source adapters
  961.      *
  962.      * @param ArrayNodeDefinition $rootNode
  963.      */
  964.     private function addEmailNode(ArrayNodeDefinition $rootNode)
  965.     {
  966.         $rootNode
  967.             ->children()
  968.                 ->arrayNode('email')
  969.                 ->addDefaultsIfNotSet()
  970.                     ->children()
  971.                         ->arrayNode('sender')
  972.                             ->children()
  973.                                 ->scalarNode('name')->end()
  974.                                 ->scalarNode('email')->end()
  975.                             ->end()
  976.                         ->end()
  977.                         ->arrayNode('return')
  978.                             ->children()
  979.                                 ->scalarNode('name')->end()
  980.                                 ->scalarNode('email')->end()
  981.                             ->end()
  982.                         ->end()
  983.                         ->scalarNode('method')
  984.                             ->defaultNull()
  985.                         ->end()
  986.                         ->arrayNode('debug')
  987.                             ->children()
  988.                                 ->scalarNode('email_addresses')
  989.                                     ->defaultValue('')
  990.                                 ->end()
  991.                             ->end()
  992.                         ->end()
  993.                         ->scalarNode('usespecific')
  994.                         ->end()
  995.                     ->end()
  996.                 ->end()
  997.             ->end();
  998.     }
  999.     /**
  1000.      * Adds configuration tree for newsletter source adapters
  1001.      *
  1002.      * @param ArrayNodeDefinition $rootNode
  1003.      */
  1004.     private function addNewsletterNode(ArrayNodeDefinition $rootNode)
  1005.     {
  1006.         $rootNode
  1007.             ->children()
  1008.                 ->arrayNode('newsletter')
  1009.                     ->addDefaultsIfNotSet()
  1010.                     ->children()
  1011.                         ->arrayNode('sender')
  1012.                             ->children()
  1013.                                 ->scalarNode('name')->end()
  1014.                                 ->scalarNode('email')->end()
  1015.                             ->end()
  1016.                         ->end()
  1017.                         ->arrayNode('return')
  1018.                             ->children()
  1019.                                 ->scalarNode('name')->end()
  1020.                                 ->scalarNode('email')->end()
  1021.                             ->end()
  1022.                         ->end()
  1023.                         ->scalarNode('method')
  1024.                             ->defaultNull()
  1025.                         ->end()
  1026.                         ->arrayNode('debug')
  1027.                             ->children()
  1028.                                 ->scalarNode('email_addresses')
  1029.                                     ->defaultValue('')
  1030.                                 ->end()
  1031.                             ->end()
  1032.                         ->end()
  1033.                         ->booleanNode('use_specific')
  1034.                             ->beforeNormalization()
  1035.                                 ->ifString()
  1036.                                 ->then(function ($v) {
  1037.                                     return (bool)$v;
  1038.                                 })
  1039.                             ->end()
  1040.                         ->end()
  1041.                         ->arrayNode('source_adapters')
  1042.                             ->useAttributeAsKey('name')
  1043.                                 ->prototype('scalar')
  1044.                             ->end()
  1045.                         ->end()
  1046.                     ->end()
  1047.                 ->end()
  1048.             ->end();
  1049.     }
  1050.     /**
  1051.      * Adds configuration tree for custom report adapters
  1052.      *
  1053.      * @param ArrayNodeDefinition $rootNode
  1054.      */
  1055.     private function addCustomReportsNode(ArrayNodeDefinition $rootNode)
  1056.     {
  1057.         $rootNode
  1058.             ->children()
  1059.                 ->arrayNode('custom_report')
  1060.                     ->addDefaultsIfNotSet()
  1061.                     ->children()
  1062.                         ->arrayNode('adapters')
  1063.                             ->useAttributeAsKey('name')
  1064.                                 ->prototype('scalar')
  1065.                             ->end()
  1066.                         ->end()
  1067.                     ->end()
  1068.                 ->end()
  1069.             ->end();
  1070.     }
  1071.     /**
  1072.      * Adds configuration tree node for migrations
  1073.      *
  1074.      * @param ArrayNodeDefinition $rootNode
  1075.      */
  1076.     private function addMigrationsNode(ArrayNodeDefinition $rootNode)
  1077.     {
  1078.         $rootNode
  1079.             ->children()
  1080.                 ->arrayNode('migrations')
  1081.                     ->addDefaultsIfNotSet()
  1082.                     ->children()
  1083.                         ->arrayNode('sets')
  1084.                             ->useAttributeAsKey('identifier')
  1085.                             ->defaultValue([])
  1086.                             ->info('Migration sets which can be used apart from bundle migrations. Use the -s option in migration commands to select a specific set.')
  1087.                             ->example([
  1088.                                 [
  1089.                                     'custom_set' => [
  1090.                                         'name' => 'Custom Migrations',
  1091.                                         'namespace' => 'App\\Migrations\\Custom',
  1092.                                         'directory' => 'src/App/Migrations/Custom'
  1093.                                     ],
  1094.                                     'custom_set_2' => [
  1095.                                         'name' => 'Custom Migrations 2',
  1096.                                         'namespace' => 'App\\Migrations\\Custom2',
  1097.                                         'directory' => 'src/App/Migrations/Custom2',
  1098.                                         'connection' => 'custom_connection'
  1099.                                     ],
  1100.                                 ]
  1101.                             ])
  1102.                             ->prototype('array')
  1103.                                 ->children()
  1104.                                     ->scalarNode('identifier')->end()
  1105.                                     ->scalarNode('name')
  1106.                                         ->isRequired()
  1107.                                         ->cannotBeEmpty()
  1108.                                     ->end()
  1109.                                     ->scalarNode('namespace')
  1110.                                         ->isRequired()
  1111.                                         ->cannotBeEmpty()
  1112.                                     ->end()
  1113.                                     ->scalarNode('directory')
  1114.                                         ->isRequired()
  1115.                                         ->cannotBeEmpty()
  1116.                                     ->end()
  1117.                                     ->scalarNode('connection')
  1118.                                         ->info('If defined, the DBAL connection defined here will be used')
  1119.                                         ->defaultNull()
  1120.                                         ->beforeNormalization()
  1121.                                             ->ifTrue(function ($v) {
  1122.                                                 return empty(trim($v));
  1123.                                             })
  1124.                                             ->then(function () {
  1125.                                                 return null;
  1126.                                             })
  1127.                                         ->end()
  1128.                                     ->end()
  1129.                                 ->end()
  1130.                             ->end()
  1131.                         ->end()
  1132.                     ->end()
  1133.                 ->end()
  1134.             ->end();
  1135.     }
  1136.     private function addTargetingNode(ArrayNodeDefinition $rootNode)
  1137.     {
  1138.         $rootNode
  1139.             ->children()
  1140.                 ->arrayNode('targeting')
  1141.                     ->canBeDisabled()
  1142.                     ->addDefaultsIfNotSet()
  1143.                     ->children()
  1144.                         ->scalarNode('storage_id')
  1145.                             ->info('Service ID of the targeting storage which should be used. This ID will be aliased to ' TargetingStorageInterface::class)
  1146.                             ->defaultValue(CookieStorage::class)
  1147.                             ->cannotBeEmpty()
  1148.                         ->end()
  1149.                         ->arrayNode('session')
  1150.                             ->info('Enables HTTP session support by configuring session bags and the full page cache')
  1151.                             ->canBeEnabled()
  1152.                         ->end()
  1153.                         ->arrayNode('data_providers')
  1154.                             ->useAttributeAsKey('key')
  1155.                                 ->prototype('scalar')
  1156.                             ->end()
  1157.                         ->end()
  1158.                         ->arrayNode('conditions')
  1159.                             ->useAttributeAsKey('key')
  1160.                                 ->prototype('scalar')
  1161.                             ->end()
  1162.                         ->end()
  1163.                         ->arrayNode('action_handlers')
  1164.                             ->useAttributeAsKey('name')
  1165.                                 ->prototype('scalar')
  1166.                             ->end()
  1167.                         ->end()
  1168.                     ->end()
  1169.                 ->end()
  1170.             ->end();
  1171.     }
  1172.     private function addSitemapsNode(ArrayNodeDefinition $rootNode)
  1173.     {
  1174.         $rootNode
  1175.             ->children()
  1176.                 ->arrayNode('sitemaps')
  1177.                     ->addDefaultsIfNotSet()
  1178.                     ->children()
  1179.                         ->arrayNode('generators')
  1180.                             ->useAttributeAsKey('name')
  1181.                             ->prototype('array')
  1182.                                 ->beforeNormalization()
  1183.                                     ->ifString()
  1184.                                     ->then(function ($v) {
  1185.                                         return [
  1186.                                             'enabled' => true,
  1187.                                             'generator_id' => $v,
  1188.                                             'priority' => 0
  1189.                                         ];
  1190.                                     })
  1191.                                 ->end()
  1192.                                 ->addDefaultsIfNotSet()
  1193.                                 ->canBeDisabled()
  1194.                                 ->children()
  1195.                                     ->scalarNode('generator_id')
  1196.                                         ->cannotBeEmpty()
  1197.                                     ->end()
  1198.                                     ->integerNode('priority')
  1199.                                         ->defaultValue(0)
  1200.                                     ->end()
  1201.                                 ->end()
  1202.                             ->end()
  1203.                         ->end()
  1204.                     ->end()
  1205.                 ->end()
  1206.             ->end()
  1207.         ->end();
  1208.     }
  1209.     private function addMimeNode(ArrayNodeDefinition $rootNode)
  1210.     {
  1211.         $rootNode
  1212.             ->children()
  1213.                 ->arrayNode('mime')
  1214.                     ->addDefaultsIfNotSet()
  1215.                     ->children()
  1216.                         ->arrayNode('extensions')
  1217.                             ->useAttributeAsKey('name')
  1218.                             ->prototype('scalar')
  1219.                         ->end()
  1220.                     ->end()
  1221.                 ->end()
  1222.             ->end()
  1223.         ->end();
  1224.     }
  1225.     private function addWorkflowNode(ArrayNodeDefinition $rootNode)
  1226.     {
  1227.         $rootNode
  1228.             ->children()
  1229.                  ->arrayNode('workflows')
  1230.                         ->useAttributeAsKey('name')
  1231.                         ->prototype('array')
  1232.                             ->children()
  1233.                                 ->arrayNode('placeholders')
  1234.                                     ->info('Placeholder values in this workflow configuration (locale: "%%locale%%") will be replaced by the given placeholder value (eg. "de_AT")')
  1235.                                     ->example([
  1236.                                         'placeholders' => [
  1237.                                             '%%locale%%' => 'de_AT'
  1238.                                         ]
  1239.                                     ])
  1240.                                     ->defaultValue([])
  1241.                                     ->beforeNormalization()
  1242.                                         ->castToArray()
  1243.                                         ->always()
  1244.                                         ->then(function ($placeholders) {
  1245.                                             $this->placeholders $placeholders;
  1246.                                             return $placeholders;
  1247.                                         })
  1248.                                     ->end()
  1249.                                     ->prototype('scalar')->end()
  1250.                                 ->end()
  1251.                                 ->booleanNode('enabled')
  1252.                                     ->defaultTrue()
  1253.                                     ->info('Can be used to enable or disable the workflow.')
  1254.                                 ->end()
  1255.                                 ->integerNode('priority')
  1256.                                     ->defaultValue(0)
  1257.                                     ->info('When multiple custom view or permission settings from different places in different workflows are valid, the workflow with the highest priority will be used.')
  1258.                                 ->end()
  1259.                                 ->scalarNode('label')
  1260.                                     ->info('Will be used in the backend interface as nice name for the workflow. If not set the technical workflow name will be used as label too.')
  1261.                                 ->end()
  1262.                                 ->arrayNode('audit_trail')
  1263.                                     ->canBeEnabled()
  1264.                                     ->info('Enable default audit trail feature provided by Symfony. Take a look at the Symfony docs for more details.')
  1265.                                 ->end()
  1266.                                 ->enumNode('type')
  1267.                                     ->values(['workflow''state_machine'])
  1268.                                     ->info('A workflow with type "workflow" can handle multiple places at one time whereas a state_machine provides a finite state_machine (only one place at one time). Take a look at the Symfony docs for more details.')
  1269.                                 ->end()
  1270.                                 ->arrayNode('marking_store')
  1271.                                     ->fixXmlConfig('argument')
  1272.                                     ->children()
  1273.                                         ->enumNode('type')
  1274.                                             ->values(['multiple_state''single_state''state_table''data_object_multiple_state''data_object_splitted_state'])
  1275.                                         ->end()
  1276.                                         ->arrayNode('arguments')
  1277.                                             ->beforeNormalization()
  1278.                                                 ->always()
  1279.                                                 ->then(function ($arguments) {
  1280.                                                     if (is_string($arguments)) {
  1281.                                                         $arguments = [$arguments];
  1282.                                                     }
  1283.                                                     if (!empty($this->placeholders)) {
  1284.                                                         $arguments $this->placeholderProcessor->mergePlaceholders($arguments$this->placeholders);
  1285.                                                     }
  1286.                                                     return $arguments;
  1287.                                                 })
  1288.                                             ->end()
  1289.                                             ->requiresAtLeastOneElement()
  1290.                                             ->prototype('variable')
  1291.                                             ->end()
  1292.                                         ->end()
  1293.                                         ->scalarNode('service')
  1294.                                             ->cannotBeEmpty()
  1295.                                         ->end()
  1296.                                     ->end()
  1297.                                     ->info('Handles the way how the state/place is stored. If not defined "state_table" will be used as default. Take a look at @TODO for a description of the different types.')
  1298.                                     ->validate()
  1299.                                         ->ifTrue(function ($v) {
  1300.                                             return isset($v['type']) && isset($v['service']);
  1301.                                         })
  1302.                                         ->thenInvalid('"type" and "service" cannot be used together.')
  1303.                                     ->end()
  1304.                                     ->validate()
  1305.                                         ->ifTrue(function ($v) {
  1306.                                             return !empty($v['arguments']) && isset($v['service']);
  1307.                                         })
  1308.                                         ->thenInvalid('"arguments" and "service" cannot be used together.')
  1309.                                     ->end()
  1310.                                 ->end()
  1311.                                 ->arrayNode('supports')
  1312.                                     ->beforeNormalization()
  1313.                                         ->ifString()
  1314.                                         ->then(function ($v) {
  1315.                                             return [$v];
  1316.                                         })
  1317.                                     ->end()
  1318.                                     ->prototype('scalar')
  1319.                                         ->cannotBeEmpty()
  1320.                                     ->end()
  1321.                                     ->info('List of supported entity classes. Take a look at the Symfony docs for more details.')
  1322.                                     ->example(['\Pimcore\Model\DataObject\Product'])
  1323.                                 ->end()
  1324.                                 ->arrayNode('support_strategy')
  1325.                                     ->fixXmlConfig('argument')
  1326.                                     ->children()
  1327.                                         ->enumNode('type')
  1328.                                             ->values(['expression'])
  1329.                                             ->info('Type "expression": a symfony expression to define a criteria.')
  1330.                                         ->end()
  1331.                                         ->arrayNode('arguments')
  1332.                                             ->beforeNormalization()
  1333.                                                 ->ifString()
  1334.                                                 ->then(function ($v) {
  1335.                                                     return [$v];
  1336.                                                 })
  1337.                                             ->end()
  1338.                                             ->requiresAtLeastOneElement()
  1339.                                             ->prototype('variable')
  1340.                                             ->end()
  1341.                                         ->end()
  1342.                                         ->scalarNode('service')
  1343.                                             ->cannotBeEmpty()
  1344.                                             ->info('Define a custom service to handle the logic. Take a look at the Symfony docs for more details.')
  1345.                                         ->end()
  1346.                                     ->end()
  1347.                                     ->validate()
  1348.                                         ->ifTrue(function ($v) {
  1349.                                             return isset($v['type']) && isset($v['service']);
  1350.                                         })
  1351.                                         ->thenInvalid('"type" and "service" cannot be used together.')
  1352.                                     ->end()
  1353.                                     ->validate()
  1354.                                         ->ifTrue(function ($v) {
  1355.                                             return !empty($v['arguments']) && isset($v['service']);
  1356.                                         })
  1357.                                         ->thenInvalid('"arguments" and "service" cannot be used together.')
  1358.                                     ->end()
  1359.                                     ->info('Can be used to implement a special logic which subjects are supported by the workflow. For example only products matching certain criteria.')
  1360.                                     ->example([
  1361.                                         'type' => 'expression',
  1362.                                         'arguments' => [
  1363.                                             '\Pimcore\Model\DataObject\Product',
  1364.                                             'subject.getProductType() == "article" and is_fully_authenticated() and "ROLE_PIMCORE_ADMIN" in roles'
  1365.                                         ]
  1366.                                     ])
  1367.                                 ->end()
  1368.                                 ->scalarNode('initial_place')
  1369.                                     ->defaultNull()
  1370.                                     ->info('Will be applied when the current place is empty.')
  1371.                                 ->end()
  1372.                                 ->arrayNode('places')
  1373.                                     ->prototype('array')
  1374.                                         ->children()
  1375.                                             ->scalarNode('label')->info('Nice name which will be used in the Pimcore backend.')->end()
  1376.                                             ->scalarNode('title')->info('Title/tooltip for this place when it is displayed in the header of the Pimcore element detail view in the backend.')->defaultValue('')->end()
  1377.                                             ->scalarNode('color')->info('Color of the place which will be used in the Pimcore backend.')->defaultValue('#bfdadc')->end()
  1378.                                             ->booleanNode('colorInverted')->info('If set to true the color will be used as border and font color otherwise as background color.')->defaultFalse()->end()
  1379.                                             ->booleanNode('visibleInHeader')->info('If set to false, the place will be hidden in the header of the Pimcore element detail view in the backend.')->defaultTrue()->end()
  1380.                                             ->arrayNode('permissions')
  1381.                                                 ->prototype('array')
  1382.                                                     ->children()
  1383.                                                         ->scalarNode('condition')->info('A symfony expression can be configured here. The first set of permissions which are matching the condition will be used.')->end()
  1384.                                                         ->booleanNode('save')->info('save permission as it can be configured in Pimcore workplaces')->end()
  1385.                                                         ->booleanNode('publish')->info('publish permission as it can be configured in Pimcore workplaces')->end()
  1386.                                                         ->booleanNode('unpublish')->info('unpublish permission as it can be configured in Pimcore workplaces')->end()
  1387.                                                         ->booleanNode('delete')->info('delete permission as it can be configured in Pimcore workplaces')->end()
  1388.                                                         ->booleanNode('rename')->info('rename permission as it can be configured in Pimcore workplaces')->end()
  1389.                                                         ->booleanNode('view')->info('view permission as it can be configured in Pimcore workplaces')->end()
  1390.                                                         ->booleanNode('settings')->info('settings permission as it can be configured in Pimcore workplaces')->end()
  1391.                                                         ->booleanNode('versions')->info('versions permission as it can be configured in Pimcore workplaces')->end()
  1392.                                                         ->booleanNode('properties')->info('properties permission as it can be configured in Pimcore workplaces')->end()
  1393.                                                         ->booleanNode('modify')->info('a short hand for save, publish, unpublish, delete + rename')->end()
  1394.                                                         ->scalarNode('objectLayout')->info('if set, the user will see the configured custom data object layout')->end()
  1395.                                                     ->end()
  1396.                                                 ->end()
  1397.                                             ->end()
  1398.                                         ->end()
  1399.                                     ->end()
  1400.                                     ->beforeNormalization()
  1401.                                         ->always()
  1402.                                         ->then(function ($places) {
  1403.                                             if (!empty($this->placeholders)) {
  1404.                                                 foreach ($places as $name => $place) {
  1405.                                                     $places[$name] = $this->placeholderProcessor->mergePlaceholders($place$this->placeholders);
  1406.                                                 }
  1407.                                             }
  1408.                                             return $places;
  1409.                                         })
  1410.                                     ->end()
  1411.                                     ->example([
  1412.                                         'places' => [
  1413.                                             'closed' => [
  1414.                                                 'label' => 'close product',
  1415.                                                 'permissions' => [
  1416.                                                     [
  1417.                                                         'condition' => "is_fully_authenticated() and 'ROLE_PIMCORE_ADMIN' in roles",
  1418.                                                         'modify' => false
  1419.                                                     ],
  1420.                                                     [
  1421.                                                         'modify' => false,
  1422.                                                         'objectLayout' => 2
  1423.                                                     ]
  1424.                                                 ]
  1425.                                             ]
  1426.                                         ]
  1427.                                     ])
  1428.                                 ->end()
  1429.                                 ->arrayNode('transitions')
  1430.                                     ->beforeNormalization()
  1431.                                         ->always()
  1432.                                         ->then(function ($transitions) {
  1433.                                             // It's an indexed array, we let the validation occurs
  1434.                                             if (isset($transitions[0])) {
  1435.                                                 return $transitions;
  1436.                                             }
  1437.                                             foreach ($transitions as $name => $transition) {
  1438.                                                 if (array_key_exists('name', (array) $transition)) {
  1439.                                                     continue;
  1440.                                                 }
  1441.                                                 $transition['name'] = $name;
  1442.                                                 $transitions[$name] = $transition;
  1443.                                             }
  1444.                                             return $transitions;
  1445.                                         })
  1446.                                     ->end()
  1447.                                     ->isRequired()
  1448.                                     ->requiresAtLeastOneElement()
  1449.                                     ->prototype('array')
  1450.                                         ->children()
  1451.                                             ->scalarNode('name')
  1452.                                                 ->isRequired()
  1453.                                                 ->cannotBeEmpty()
  1454.                                             ->end()
  1455.                                             ->scalarNode('guard')
  1456.                                                 ->cannotBeEmpty()
  1457.                                                 ->info('An expression to block the transition')
  1458.                                                 ->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
  1459.                                             ->end()
  1460.                                             ->arrayNode('from')
  1461.                                                 ->beforeNormalization()
  1462.                                                     ->ifString()
  1463.                                                     ->then(function ($v) {
  1464.                                                         return [$v];
  1465.                                                     })
  1466.                                                 ->end()
  1467.                                                 ->requiresAtLeastOneElement()
  1468.                                                 ->prototype('scalar')
  1469.                                                     ->cannotBeEmpty()
  1470.                                                 ->end()
  1471.                                             ->end()
  1472.                                             ->arrayNode('to')
  1473.                                                 ->beforeNormalization()
  1474.                                                     ->ifString()
  1475.                                                     ->then(function ($v) {
  1476.                                                         return [$v];
  1477.                                                     })
  1478.                                                 ->end()
  1479.                                                 ->requiresAtLeastOneElement()
  1480.                                                 ->prototype('scalar')
  1481.                                                     ->cannotBeEmpty()
  1482.                                                 ->end()
  1483.                                             ->end()
  1484.                                             ->arrayNode('options')
  1485.                                                 ->children()
  1486.                                                     ->scalarNode('label')->info('Nice name for the Pimcore backend.')->end()
  1487.                                                     ->arrayNode('notes')
  1488.                                                         ->children()
  1489.                                                             ->booleanNode('commentEnabled')->defaultFalse()->info('If enabled a detail window will open when the user executes the transition. In this detail view the user be asked to enter a "comment". This comment then will be used as comment for the notes/events feature.')->end()
  1490.                                                             ->booleanNode('commentRequired')->defaultFalse()->info('Set this to true if the comment should be a required field.')->end()
  1491.                                                             ->scalarNode('commentSetterFn')->info('Can be used for data objects. The comment will be saved to the data object additionally to the notes/events through this setter function.')->end()
  1492.                                                             ->scalarNode('commentGetterFn')->info('Can be used for data objects to prefill the comment field with data from the data object.')->end()
  1493.                                                             ->scalarNode('type')->defaultValue('Status update')->info('Set\'s the type string in the saved note.')->end()
  1494.                                                             ->scalarNode('title')->info('An optional alternative "title" for the note, if blank the actions transition result is used.')->end()
  1495.                                                             ->arrayNode('additionalFields')
  1496.                                                                 ->prototype('array')
  1497.                                                                     ->children()
  1498.                                                                         ->scalarNode('name')->isRequired()->info('The technical name used in the input form.')->end()
  1499.                                                                         ->enumNode('fieldType')
  1500.                                                                             ->isRequired()
  1501.                                                                             ->values(['input''textarea''select''datetime''date''user''checkbox'])
  1502.                                                                             ->info('The data component name/field type.')
  1503.                                                                         ->end()
  1504.                                                                         ->scalarNode('title')->info('The label used by the field')->end()
  1505.                                                                         ->booleanNode('required')->defaultFalse()->info('Whether or not the field is required.')->end()
  1506.                                                                         ->scalarNode('setterFn')->info('Optional setter function (available in the element, for example in the updated object), if not specified, data will be added to notes. The Workflow manager will call the function with the whole field data.')->end()
  1507.                                                                         ->arrayNode('fieldTypeSettings')
  1508.                                                                              ->prototype('variable')->end()
  1509.                                                                              ->info('Will be passed to the underlying Pimcore data object field type. Can be used to configure the options of a select box for example.')
  1510.                                                                         ->end()
  1511.                                                                     ->end()
  1512.                                                                 ->end()
  1513.                                                                 ->info('Add additional field to the transition detail window.')
  1514.                                                             ->end()
  1515.                                                         ->end()
  1516.                                                     ->end()
  1517.                                                     ->scalarNode('iconClass')->info('Css class to define the icon which will be used in the actions button in the backend.')->end()
  1518.                                                     ->arrayNode('notificationSettings')
  1519.                                                         ->prototype('array')
  1520.                                                             ->children()
  1521.                                                                 ->scalarNode('condition')->info('A symfony expression can be configured here. All sets of notification which are matching the condition will be used.')->end()
  1522.                                                                 ->arrayNode('notifyUsers')
  1523.                                                                     ->requiresAtLeastOneElement()
  1524.                                                                     ->prototype('scalar')
  1525.                                                                         ->cannotBeEmpty()
  1526.                                                                     ->end()
  1527.                                                                     ->info('Send a email notification to a list of users (user names) when the transition get\'s applied')
  1528.                                                                 ->end()
  1529.                                                                 ->arrayNode('notifyRoles')
  1530.                                                                     ->requiresAtLeastOneElement()
  1531.                                                                     ->prototype('scalar')
  1532.                                                                         ->cannotBeEmpty()
  1533.                                                                     ->end()
  1534.                                                                     ->info('Send a email notification to a list of user roles (role names) when the transition get\'s applied')
  1535.                                                                 ->end()
  1536.                                                                 ->arrayNode('channelType')
  1537.                                                                     ->requiresAtLeastOneElement()
  1538.                                                                     ->enumPrototype()
  1539.                                                                         ->values([NotificationSubscriber::NOTIFICATION_CHANNEL_MAILNotificationSubscriber::NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION])
  1540.                                                                         ->cannotBeEmpty()
  1541.                                                                         ->defaultValue(NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL)
  1542.                                                                     ->end()
  1543.                                                                     ->info('Define which channel notification should be sent to, possible values "' NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL '" and "' NotificationSubscriber::NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION '", default value is "' NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL '".')
  1544.                                                                     ->addDefaultChildrenIfNoneSet()
  1545.                                                                 ->end()
  1546.                                                                 ->enumNode('mailType')
  1547.                                                                     ->values([NotificationSubscriber::MAIL_TYPE_TEMPLATENotificationSubscriber::MAIL_TYPE_DOCUMENT])
  1548.                                                                     ->defaultValue(NotificationSubscriber::MAIL_TYPE_TEMPLATE)
  1549.                                                                     ->info('Type of mail source.')
  1550.                                                                 ->end()
  1551.                                                                 ->scalarNode('mailPath')
  1552.                                                                     ->defaultValue(NotificationSubscriber::DEFAULT_MAIL_TEMPLATE_PATH)
  1553.                                                                     ->info('Path to mail source - either Symfony path to template or fullpath to Pimcore document. Optional use ' NotificationEmailService::MAIL_PATH_LANGUAGE_PLACEHOLDER ' as placeholder for language.')
  1554.                                                                 ->end()
  1555.                                                             ->end()
  1556.                                                         ->end()
  1557.                                                     ->end()
  1558.                                                     ->enumNode('changePublishedState')
  1559.                                                         ->values([ChangePublishedStateSubscriber::NO_CHANGEChangePublishedStateSubscriber::FORCE_UNPUBLISHEDChangePublishedStateSubscriber::FORCE_PUBLISHED])
  1560.                                                         ->defaultValue(ChangePublishedStateSubscriber::NO_CHANGE)
  1561.                                                         ->info('Change published state of element while transition (only available for documents and data objects).')
  1562.                                                     ->end()
  1563.                                                 ->end()
  1564.                                             ->end()
  1565.                                         ->end()
  1566.                                     ->end()
  1567.                                     ->example([
  1568.                                         'close_product' => [
  1569.                                             'from' => 'open',
  1570.                                             'to' => 'closed',
  1571.                                             'options' => [
  1572.                                                 'label' => 'close product',
  1573.                                                 'notes' => [
  1574.                                                     'commentEnabled' => true,
  1575.                                                     'commentRequired' => true,
  1576.                                                     'additionalFields' => [
  1577.                                                         [
  1578.                                                             'name' => 'accept',
  1579.                                                             'title' => 'accept terms',
  1580.                                                             'required' => true,
  1581.                                                             'fieldType' => 'checkbox',
  1582.                                                         ],
  1583.                                                         [
  1584.                                                             'name' => 'select',
  1585.                                                             'title' => 'please select a type',
  1586.                                                             'setterFn' => 'setSpecialWorkflowType',
  1587.                                                             'fieldType' => 'select',
  1588.                                                             'fieldTypeSettings' => [
  1589.                                                                 'options' => [
  1590.                                                                     ['key' => 'Option A''value' => 'a'],
  1591.                                                                     ['key' => 'Option B''value' => 'b'],
  1592.                                                                     ['key' => 'Option C''value' => 'c'],
  1593.                                                                 ]
  1594.                                                             ],
  1595.                                                         ]
  1596.                                                     ],
  1597.                                                 ]
  1598.                                             ]
  1599.                                         ]
  1600.                                     ])
  1601.                                 ->end()
  1602.                                 ->arrayNode('globalActions')
  1603.                                     ->prototype('array')
  1604.                                         ->children()
  1605.                                             ->scalarNode('label')->info('Nice name for the Pimcore backend.')->end()
  1606.                                             ->scalarNode('iconClass')->info('Css class to define the icon which will be used in the actions button in the backend.')->end()
  1607.                                             ->scalarNode('guard')
  1608.                                                 ->cannotBeEmpty()
  1609.                                                 ->info('An expression to block the action')
  1610.                                                 ->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
  1611.                                             ->end()
  1612.                                             ->arrayNode('to')
  1613.                                                 ->beforeNormalization()
  1614.                                                     ->ifString()
  1615.                                                     ->then(function ($v) {
  1616.                                                         return [$v];
  1617.                                                     })
  1618.                                                 ->end()
  1619.                                                 ->requiresAtLeastOneElement()
  1620.                                                 ->prototype('scalar')
  1621.                                                     ->cannotBeEmpty()
  1622.                                                 ->end()
  1623.                                                 ->info('Optionally set the current place of the workflow. Can be used for example to reset the workflow to the initial place.')
  1624.                                             ->end()
  1625.                                             ->arrayNode('notes')
  1626.                                                 ->children()
  1627.                                                     ->booleanNode('commentEnabled')->defaultFalse()->end()
  1628.                                                     ->booleanNode('commentRequired')->defaultFalse()->end()
  1629.                                                     ->scalarNode('commentSetterFn')->end()
  1630.                                                     ->scalarNode('commentGetterFn')->end()
  1631.                                                     ->scalarNode('type')->defaultValue('Status update')->end()
  1632.                                                     ->scalarNode('title')->end()
  1633.                                                     ->arrayNode('additionalFields')
  1634.                                                         ->prototype('array')
  1635.                                                             ->children()
  1636.                                                                 ->scalarNode('name')->isRequired()->end()
  1637.                                                                 ->enumNode('fieldType')
  1638.                                                                     ->isRequired()
  1639.                                                                     ->values(['input''textarea''select''datetime''date''user''checkbox'])
  1640.                                                                 ->end()
  1641.                                                                 ->scalarNode('title')->end()
  1642.                                                                 ->booleanNode('required')->defaultFalse()->end()
  1643.                                                                 ->scalarNode('setterFn')->end()
  1644.                                                                 ->arrayNode('fieldTypeSettings')
  1645.                                                                      ->prototype('variable')->end()
  1646.                                                                 ->end()
  1647.                                                             ->end()
  1648.                                                         ->end()
  1649.                                                     ->end()
  1650.                                                 ->end()
  1651.                                                 ->info('See notes section of transitions. It works exactly the same way.')
  1652.                                             ->end()
  1653.                                         ->end()
  1654.                                     ->end()
  1655.                                     ->info('Actions which will be added to actions button independently of the current workflow place.')
  1656.                                 ->end()
  1657.                             ->end()
  1658.                             ->validate()
  1659.                                 ->ifTrue(function ($v) {
  1660.                                     return $v['supports'] && isset($v['support_strategy']);
  1661.                                 })
  1662.                                 ->thenInvalid('"supports" and "support_strategy" cannot be used together.')
  1663.                             ->end()
  1664.                             ->validate()
  1665.                                 ->ifTrue(function ($v) {
  1666.                                     return !$v['supports'] && !isset($v['support_strategy']);
  1667.                                 })
  1668.                                 ->thenInvalid('"supports" or "support_strategy" should be configured.')
  1669.                             ->end()
  1670.                         ->end()
  1671.                     ->end()
  1672.                 ->end()
  1673.                 ->addDefaultsIfNotSet()
  1674.             ->end();
  1675.     }
  1676. }