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

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 Commercial License (PCL)
  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 PCL
  13.  */
  14. namespace Pimcore\Bundle\CoreBundle\DependencyInjection;
  15. use Pimcore\Bundle\CoreBundle\DependencyInjection\Config\Processor\PlaceholderProcessor;
  16. use Pimcore\Targeting\Storage\CookieStorage;
  17. use Pimcore\Targeting\Storage\TargetingStorageInterface;
  18. use Pimcore\Workflow\EventSubscriber\ChangePublishedStateSubscriber;
  19. use Pimcore\Workflow\EventSubscriber\NotificationSubscriber;
  20. use Pimcore\Workflow\Notification\NotificationEmailService;
  21. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  22. use Symfony\Component\Config\Definition\Builder\NodeDefinition;
  23. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  24. use Symfony\Component\Config\Definition\ConfigurationInterface;
  25. /**
  26.  * @internal
  27.  */
  28. final class Configuration implements ConfigurationInterface
  29. {
  30.     /**
  31.      * @var PlaceholderProcessor
  32.      */
  33.     private PlaceholderProcessor $placeholderProcessor;
  34.     /**
  35.      * @var array
  36.      */
  37.     private array $placeholders = [];
  38.     public function __construct()
  39.     {
  40.         $this->placeholderProcessor = new PlaceholderProcessor();
  41.         $this->placeholders = [];
  42.     }
  43.     /**
  44.      * {@inheritdoc}
  45.      */
  46.     public function getConfigTreeBuilder(): TreeBuilder
  47.     {
  48.         $treeBuilder = new TreeBuilder('pimcore');
  49.         /** @var ArrayNodeDefinition $rootNode */
  50.         $rootNode $treeBuilder->getRootNode();
  51.         $rootNode->addDefaultsIfNotSet();
  52.         $rootNode
  53.             ->children()
  54.                 ->arrayNode('error_handling')
  55.                     ->addDefaultsIfNotSet()
  56.                     ->children()
  57.                         ->booleanNode('render_error_document')
  58.                             ->info('Render error document in case of an error instead of showing Symfony\'s error page')
  59.                             ->defaultTrue()
  60.                             ->beforeNormalization()
  61.                                 ->ifString()
  62.                                 ->then(function ($v) {
  63.                                     return (bool)$v;
  64.                                 })
  65.                             ->end()
  66.                         ->end()
  67.                     ->end()
  68.                     ->setDeprecated(
  69.                         'pimcore/pimcore',
  70.                         '10.1',
  71.                         'The "%node%" option is deprecated since Pimcore 10.1, it will be removed in Pimcore 11.'
  72.                     )
  73.                 ->end()
  74.                 ->arrayNode('bundles')
  75.                     ->addDefaultsIfNotSet()
  76.                     ->children()
  77.                         ->arrayNode('search_paths')
  78.                             ->prototype('scalar')->end()
  79.                         ->end()
  80.                         ->booleanNode('handle_composer')
  81.                             ->defaultTrue()
  82.                         ->end()
  83.                     ->end()
  84.                 ->end()
  85.                 ->arrayNode('flags')
  86.                     ->info('Generic map for feature flags')
  87.                     ->prototype('scalar')->end()
  88.                 ->end()
  89.                 ->arrayNode('translations')
  90.                     ->addDefaultsIfNotSet()
  91.                     ->children()
  92.                         ->arrayNode('admin_translation_mapping')
  93.                             ->useAttributeAsKey('locale')
  94.                             ->prototype('scalar')->end()
  95.                         ->end()
  96.                         ->arrayNode('debugging')
  97.                             ->info('If debugging is enabled, the translator will return the plain translation key instead of the translated message.')
  98.                             ->addDefaultsIfNotSet()
  99.                             ->canBeDisabled()
  100.                             ->children()
  101.                                 ->scalarNode('parameter')
  102.                                     ->defaultValue('pimcore_debug_translations')
  103.                                 ->end()
  104.                             ->end()
  105.                         ->end()
  106.                         ->arrayNode('data_object')
  107.                             ->addDefaultsIfNotSet()
  108.                             ->children()
  109.                                 ->arrayNode('translation_extractor')
  110.                                     ->children()
  111.                                         ->arrayNode('attributes')
  112.                                             ->info('Can be used to restrict the extracted localized fields (e.g. used by XLIFF exporter in the Pimcore backend)')
  113.                                             ->prototype('array')
  114.                                                 ->prototype('scalar')->end()
  115.                                             ->end()
  116.                                             ->example(
  117.                                                 [
  118.                                                     'Product' => ['name''description'],
  119.                                                     'Brand' => ['name'],
  120.                                                 ]
  121.                                             )
  122.                                         ->end()
  123.                                     ->end()
  124.                                 ->end()
  125.                             ->end()
  126.                         ->end()
  127.                     ->end()
  128.                 ->end()
  129.                 ->arrayNode('maps')
  130.                     ->addDefaultsIfNotSet()
  131.                     ->children()
  132.                         ->scalarNode('tile_layer_url_template')
  133.                             ->defaultValue('https://a.tile.openstreetmap.org/{z}/{x}/{y}.png')
  134.                         ->end()
  135.                         ->scalarNode('geocoding_url_template')
  136.                             ->defaultValue('https://nominatim.openstreetmap.org/search?q={q}&addressdetails=1&format=json&limit=1')
  137.                         ->end()
  138.                         ->scalarNode('reverse_geocoding_url_template')
  139.                             ->defaultValue('https://nominatim.openstreetmap.org/reverse?format=json&lat={lat}&lon={lon}&addressdetails=1')
  140.                         ->end()
  141.                     ->end()
  142.                 ->end()
  143.             ->end();
  144.         $this->addGeneralNode($rootNode);
  145.         $this->addMaintenanceNode($rootNode);
  146.         $this->addServicesNode($rootNode);
  147.         $this->addObjectsNode($rootNode);
  148.         $this->addAssetNode($rootNode);
  149.         $this->addDocumentsNode($rootNode);
  150.         $this->addEncryptionNode($rootNode);
  151.         $this->addModelsNode($rootNode);
  152.         $this->addRoutingNode($rootNode);
  153.         $this->addCacheNode($rootNode);
  154.         $this->addContextNode($rootNode);
  155.         $this->addAdminNode($rootNode);
  156.         $this->addWebProfilerNode($rootNode);
  157.         $this->addSecurityNode($rootNode);
  158.         $this->addEmailNode($rootNode);
  159.         $this->addNewsletterNode($rootNode);
  160.         $this->addCustomReportsNode($rootNode);
  161.         $this->addTargetingNode($rootNode);
  162.         $this->addSitemapsNode($rootNode);
  163.         $this->addWorkflowNode($rootNode);
  164.         $this->addHttpClientNode($rootNode);
  165.         $this->addApplicationLogNode($rootNode);
  166.         $this->addPredefinedPropertiesNode($rootNode);
  167.         $this->addStaticRoutesNode($rootNode);
  168.         $this->addPerspectivesNode($rootNode);
  169.         $this->addCustomViewsNode($rootNode);
  170.         return $treeBuilder;
  171.     }
  172.     /**
  173.      * Add maintenance config
  174.      *
  175.      * @param ArrayNodeDefinition $rootNode
  176.      */
  177.     private function addMaintenanceNode(ArrayNodeDefinition $rootNode)
  178.     {
  179.         $rootNode
  180.             ->children()
  181.             ->arrayNode('maintenance')
  182.             ->addDefaultsIfNotSet()
  183.             ->children()
  184.                 ->arrayNode('housekeeping')
  185.                 ->addDefaultsIfNotSet()
  186.                 ->children()
  187.                     ->integerNode('cleanup_tmp_files_atime_older_than')
  188.                         ->defaultValue(7776000// 90 days
  189.                     ->end()
  190.                     ->integerNode('cleanup_profiler_files_atime_older_than')
  191.                         ->defaultValue(1800)
  192.                     ->end()
  193.         ;
  194.     }
  195.     /**
  196.      * Add general config
  197.      *
  198.      * @param ArrayNodeDefinition $rootNode
  199.      */
  200.     private function addGeneralNode(ArrayNodeDefinition $rootNode)
  201.     {
  202.         $rootNode
  203.             ->children()
  204.             ->arrayNode('general')
  205.             ->addDefaultsIfNotSet()
  206.             ->children()
  207.                 ->scalarNode('timezone')
  208.                     ->defaultValue('')
  209.                 ->end()
  210.                 ->scalarNode('path_variable')
  211.                     ->info('Additional $PATH variable (: separated) (/x/y:/foo/bar):')
  212.                     ->defaultNull()
  213.                 ->end()
  214.                 ->scalarNode('domain')
  215.                     ->defaultValue('')
  216.                 ->end()
  217.                 ->booleanNode('redirect_to_maindomain')
  218.                     ->beforeNormalization()
  219.                         ->ifString()
  220.                         ->then(function ($v) {
  221.                             return (bool)$v;
  222.                         })
  223.                     ->end()
  224.                     ->defaultFalse()
  225.                 ->end()
  226.                 ->scalarNode('language')
  227.                     ->defaultValue('en')
  228.                 ->end()
  229.                 ->scalarNode('valid_languages')
  230.                     ->defaultValue('en')
  231.                 ->end()
  232.                 ->arrayNode('fallback_languages')
  233.                     ->performNoDeepMerging()
  234.                     ->beforeNormalization()
  235.                     ->ifArray()
  236.                         ->then(function ($v) {
  237.                             return $v;
  238.                         })
  239.                     ->end()
  240.                     ->prototype('scalar')
  241.                     ->end()
  242.                 ->end()
  243.                 ->scalarNode('default_language')
  244.                     ->defaultValue('en')
  245.                 ->end()
  246.                 ->booleanNode('disable_usage_statistics')
  247.                     ->beforeNormalization()
  248.                         ->ifString()
  249.                         ->then(function ($v) {
  250.                             return (bool)$v;
  251.                         })
  252.                     ->end()
  253.                     ->defaultFalse()
  254.                 ->end()
  255.                 ->booleanNode('debug_admin_translations')
  256.                     ->info('Debug Admin-Translations (displayed wrapped in +)')
  257.                     ->beforeNormalization()
  258.                         ->ifString()
  259.                         ->then(function ($v) {
  260.                             return (bool)$v;
  261.                         })
  262.                     ->end()
  263.                     ->defaultFalse()
  264.                 ->end()
  265.                 ->scalarNode('instance_identifier')
  266.                     ->defaultNull()
  267.                     ->info('UUID instance identifier. Has to be unique throughout multiple Pimcore instances. UUID generation will be automatically enabled if a Instance identifier is provided (do not change the instance identifier afterwards - this will cause invalid UUIDs)')
  268.                     ->end()
  269.                 ->end()
  270.             ->end();
  271.     }
  272.     /**
  273.      * @param ArrayNodeDefinition $rootNode
  274.      */
  275.     private function addServicesNode(ArrayNodeDefinition $rootNode)
  276.     {
  277.         $rootNode
  278.             ->children()
  279.             ->arrayNode('services')
  280.                 ->addDefaultsIfNotSet()
  281.                 ->children()
  282.                     ->arrayNode('google')
  283.                     ->addDefaultsIfNotSet()
  284.                     ->children()
  285.                         ->scalarNode('client_id')
  286.                             ->info('This is required for the Google API integrations. Only use a `Service Account´ from the Google Cloud Console.')
  287.                             ->defaultNull()
  288.                         ->end()
  289.                         ->scalarNode('email')
  290.                             ->info('Email address of the Google service account')
  291.                             ->defaultNull()
  292.                         ->end()
  293.                         ->scalarNode('simple_api_key')
  294.                             ->info('Server API key')
  295.                             ->defaultNull()
  296.                         ->end()
  297.                         ->scalarNode('browser_api_key')
  298.                             ->info('Browser API key')
  299.                             ->defaultNull()
  300.                         ->end()
  301.                     ->end()
  302.                     ->end()
  303.                 ->end()
  304.             ->end();
  305.     }
  306.     /**
  307.      * @param ArrayNodeDefinition $rootNode
  308.      */
  309.     private function addModelsNode(ArrayNodeDefinition $rootNode)
  310.     {
  311.         $rootNode
  312.             ->children()
  313.                 ->arrayNode('models')
  314.                     ->addDefaultsIfNotSet()
  315.                     ->children()
  316.                         ->arrayNode('class_overrides')
  317.                             ->useAttributeAsKey('name')
  318.                             ->prototype('scalar');
  319.     }
  320.     /**
  321.      * @param ArrayNodeDefinition $rootNode
  322.      */
  323.     private function addHttpClientNode(ArrayNodeDefinition $rootNode)
  324.     {
  325.         $rootNode
  326.             ->children()
  327.                 ->arrayNode('httpclient')
  328.                 ->addDefaultsIfNotSet()
  329.                     ->children()
  330.                         ->scalarNode('adapter')
  331.                             ->info('Set to `Proxy` if proxy server should be used')
  332.                             ->defaultValue('Socket')
  333.                         ->end()
  334.                         ->scalarNode('proxy_host')
  335.                             ->defaultNull()
  336.                         ->end()
  337.                         ->scalarNode('proxy_port')
  338.                             ->defaultNull()
  339.                         ->end()
  340.                         ->scalarNode('proxy_user')
  341.                             ->defaultNull()
  342.                         ->end()
  343.                         ->scalarNode('proxy_pass')
  344.                             ->defaultNull()
  345.                         ->end()
  346.                     ->end()
  347.                 ->end()
  348.             ->end();
  349.     }
  350.     /**
  351.      * @param ArrayNodeDefinition $rootNode
  352.      */
  353.     private function addApplicationLogNode(ArrayNodeDefinition $rootNode)
  354.     {
  355.         $rootNode
  356.             ->children()
  357.                 ->arrayNode('applicationlog')
  358.                 ->addDefaultsIfNotSet()
  359.                     ->children()
  360.                         ->arrayNode('mail_notification')
  361.                             ->children()
  362.                                 ->booleanNode('send_log_summary')
  363.                                     ->info('Send log summary via email')
  364.                                     ->beforeNormalization()
  365.                                         ->ifString()
  366.                                         ->then(function ($v) {
  367.                                             return (bool)$v;
  368.                                         })
  369.                                     ->end()
  370.                                     ->defaultFalse()
  371.                                 ->end()
  372.                                 ->scalarNode('filter_priority')
  373.                                     ->info('Filter threshold for email summary, choose one of: 7 (debug), 6 (info), 5 (notice), 4 (warning), 3 (error), 2 (critical), 1 (alert) ,0 (emerg)')
  374.                                     ->defaultNull()
  375.                                 ->end()
  376.                                 ->scalarNode('mail_receiver')
  377.                                 ->info('Log summary receivers. Separate multiple email receivers by using ;')
  378.                                 ->end()
  379.                             ->end()
  380.                         ->end()
  381.                         ->scalarNode('archive_treshold')
  382.                             ->info('Archive threshold in days')
  383.                             ->defaultValue(30)
  384.                         ->end()
  385.                         ->scalarNode('archive_alternative_database')
  386.                             ->info('Archive database name (optional). Tables will get archived to a different database, recommended when huge amounts of logs will be generated')
  387.                             ->defaultValue('')
  388.                         ->end()
  389.                         ->scalarNode('delete_archive_threshold')
  390.                             ->info('Threshold for deleting application log archive tables (in months)')
  391.                             ->defaultValue('6')
  392.                         ->end()
  393.                     ->end()
  394.             ->end();
  395.     }
  396.     /**
  397.      * Add asset specific extension config
  398.      *
  399.      * @param ArrayNodeDefinition $rootNode
  400.      */
  401.     private function addAssetNode(ArrayNodeDefinition $rootNode)
  402.     {
  403.         $assetsNode $rootNode
  404.             ->children()
  405.                 ->arrayNode('assets')
  406.                 ->addDefaultsIfNotSet()
  407.                 ->children()
  408.                     ->arrayNode('frontend_prefixes')
  409.                         ->addDefaultsIfNotSet()
  410.                         ->children()
  411.                             ->scalarNode('source')
  412.                                 ->defaultValue('')
  413.                                 ->end()
  414.                             ->scalarNode('thumbnail')
  415.                                 ->defaultValue('')
  416.                                 ->end()
  417.                             ->scalarNode('thumbnail_deferred')
  418.                                 ->defaultValue('')
  419.                                 ->end()
  420.                         ->end()
  421.                     ->end()
  422.                     ->scalarNode('preview_image_thumbnail')
  423.                         ->defaultNull()
  424.                         ->end()
  425.                     ->scalarNode('default_upload_path')
  426.                         ->defaultValue('_default_upload_bucket')
  427.                         ->end()
  428.                     ->integerNode('tree_paging_limit')
  429.                         ->defaultValue(100)
  430.                         ->end()
  431.                     ->arrayNode('image')
  432.                         ->addDefaultsIfNotSet()
  433.                         ->children()
  434.                             ->integerNode('max_pixels')
  435.                                 ->defaultValue(40000000)
  436.                             ->end()
  437.                             ->arrayNode('low_quality_image_preview')
  438.                                 ->addDefaultsIfNotSet()
  439.                                 ->canBeDisabled()
  440.                             ->end()
  441.                             ->arrayNode('focal_point_detection')
  442.                                 ->addDefaultsIfNotSet()
  443.                                 ->canBeDisabled()
  444.                             ->end()
  445.                             ->arrayNode('thumbnails')
  446.                                 ->addDefaultsIfNotSet()
  447.                                 ->children()
  448.                                     ->arrayNode('definitions')
  449.                                         ->normalizeKeys(false)
  450.                                         ->prototype('array')
  451.                                             ->children()
  452.                                                 ->scalarNode('id')->end()
  453.                                                 ->scalarNode('name')->end()
  454.                                                 ->scalarNode('description')->end()
  455.                                                 ->scalarNode('group')->end()
  456.                                                 ->scalarNode('format')->end()
  457.                                                 ->scalarNode('quality')->end()
  458.                                                 ->scalarNode('highResolution')->end()
  459.                                                 ->booleanNode('preserveColor')->end()
  460.                                                 ->booleanNode('preserveMetaData')->end()
  461.                                                 ->booleanNode('rasterizeSVG')->end()
  462.                                                 ->booleanNode('downloadable')->end()
  463.                                                 ->integerNode('modificationDate')->end()
  464.                                                 ->integerNode('creationDate')->end()
  465.                                                 ->booleanNode('preserveAnimation')->end()
  466.                                                 ->arrayNode('items')
  467.                                                     ->prototype('array')
  468.                                                         ->children()
  469.                                                             ->scalarNode('method')->end()
  470.                                                             ->arrayNode('arguments')
  471.                                                                 ->prototype('variable')->end()
  472.                                                             ->end()
  473.                                                         ->end()
  474.                                                     ->end()
  475.                                                 ->end()
  476.                                                 ->arrayNode('medias')
  477.                                                     ->normalizeKeys(false)
  478.                                                     ->prototype('array')
  479.                                                         ->arrayProtoType()
  480.                                                             ->children()
  481.                                                                 ->scalarNode('method')->end()
  482.                                                                 ->arrayNode('arguments')
  483.                                                                     ->prototype('variable')->end()
  484.                                                                 ->end()
  485.                                                             ->end()
  486.                                                         ->end()
  487.                                                     ->end()
  488.                                                 ->end()
  489.                                             ->end()
  490.                                         ->end()
  491.                                     ->end()
  492.                                     ->booleanNode('clip_auto_support')
  493.                                         ->beforeNormalization()
  494.                                             ->ifString()
  495.                                             ->then(function ($v) {
  496.                                                 return (bool)$v;
  497.                                             })
  498.                                         ->end()
  499.                                         ->defaultTrue()
  500.                                     ->end()
  501.                                     ->arrayNode('image_optimizers')
  502.                                         ->addDefaultsIfNotSet()
  503.                                         ->canBeDisabled()
  504.                                     ->end()
  505.                                     ->arrayNode('auto_formats')
  506.                                         ->prototype('array')
  507.                                             ->canBeDisabled()
  508.                                             ->children()
  509.                                                 ->scalarNode('quality')->end()
  510.                                             ->end()
  511.                                         ->end()
  512.                                         ->defaultValue([
  513.                                             'avif' => [
  514.                                                 'enabled' => true,
  515.                                                 'quality' => 15,
  516.                                             ],
  517.                                             'webp' => [
  518.                                                 'enabled' => true,
  519.                                                 'quality' => null,
  520.                                             ],
  521.                                         ])
  522.                                     ->end()
  523.                                     ->booleanNode('auto_clear_temp_files')
  524.                                         ->beforeNormalization()
  525.                                             ->ifString()
  526.                                             ->then(function ($v) {
  527.                                                 return (bool)$v;
  528.                                             })
  529.                                         ->end()
  530.                                         ->defaultTrue()
  531.                                     ->end()
  532.                                 ->end()
  533.                             ->end()
  534.                         ->end()
  535.                     ->end()
  536.                     ->arrayNode('video')
  537.                         ->addDefaultsIfNotSet()
  538.                         ->children()
  539.                             ->arrayNode('thumbnails')
  540.                                 ->addDefaultsIfNotSet()
  541.                                 ->children()
  542.                                     ->arrayNode('definitions')
  543.                                         ->normalizeKeys(false)
  544.                                         ->prototype('array')
  545.                                             ->children()
  546.                                                 ->scalarNode('id')->end()
  547.                                                 ->scalarNode('name')->end()
  548.                                                 ->scalarNode('description')->end()
  549.                                                 ->scalarNode('group')->end()
  550.                                                 ->scalarNode('videoBitrate')->end()
  551.                                                 ->scalarNode('audioBitrate')->end()
  552.                                                 ->scalarNode('quality')->end()
  553.                                                 ->integerNode('modificationDate')->end()
  554.                                                 ->integerNode('creationDate')->end()
  555.                                                 ->arrayNode('items')
  556.                                                     ->prototype('array')
  557.                                                         ->children()
  558.                                                             ->scalarNode('method')->end()
  559.                                                             ->arrayNode('arguments')
  560.                                                                 ->prototype('variable')->end()
  561.                                                             ->end()
  562.                                                         ->end()
  563.                                                     ->end()
  564.                                                 ->end()
  565.                                                 ->arrayNode('medias')
  566.                                                     ->normalizeKeys(false)
  567.                                                     ->prototype('array')
  568.                                                         ->arrayProtoType()
  569.                                                             ->children()
  570.                                                                 ->scalarNode('method')->end()
  571.                                                                 ->arrayNode('arguments')
  572.                                                                     ->prototype('variable')->end()
  573.                                                                 ->end()
  574.                                                             ->end()
  575.                                                         ->end()
  576.                                                     ->end()
  577.                                                 ->end()
  578.                                             ->end()
  579.                                         ->end()
  580.                                     ->end()
  581.                                     ->booleanNode('auto_clear_temp_files')
  582.                                     ->defaultTrue()
  583.                                     ->end()
  584.                                 ->end()
  585.                             ->end()
  586.                         ->end()
  587.                     ->end()
  588.                     ->arrayNode('versions')
  589.                         ->addDefaultsIfNotSet()
  590.                         ->children()
  591.                             ->scalarNode('days')
  592.                                 ->defaultNull()
  593.                             ->end()
  594.                             ->scalarNode('steps')
  595.                                 ->defaultNull()
  596.                             ->end()
  597.                             ->booleanNode('use_hardlinks')
  598.                                 ->beforeNormalization()
  599.                                     ->ifString()
  600.                                     ->then(function ($v) {
  601.                                         return (bool)$v;
  602.                                     })
  603.                                 ->end()
  604.                                 ->defaultTrue()
  605.                             ->end()
  606.                             ->booleanNode('disable_stack_trace')
  607.                                 ->beforeNormalization()
  608.                                     ->ifString()
  609.                                     ->then(function ($v) {
  610.                                         return (bool)$v;
  611.                                     })
  612.                                 ->end()
  613.                                 ->defaultFalse()
  614.                             ->end()
  615.                         ->end()
  616.                     ->end()
  617.                     ->scalarNode('icc_rgb_profile')
  618.                         ->info('Absolute path to default ICC RGB profile (if no embedded profile is given)')
  619.                         ->defaultNull()
  620.                     ->end()
  621.                     ->scalarNode('icc_cmyk_profile')
  622.                         ->info('Absolute path to default ICC CMYK profile (if no embedded profile is given)')
  623.                         ->defaultNull()
  624.                     ->end()
  625.                     ->booleanNode('hide_edit_image')
  626.                         ->defaultFalse()
  627.                     ->end()
  628.                     ->booleanNode('disable_tree_preview')
  629.                         ->defaultTrue()
  630.                     ->end()
  631.                 ->end();
  632.         $assetsNode
  633.             ->children()
  634.                 ->arrayNode('metadata')
  635.                 ->addDefaultsIfNotSet()
  636.                     ->children()
  637.                         ->arrayNode('predefined')
  638.                             ->children()
  639.                                 ->arrayNode('definitions')
  640.                                 ->normalizeKeys(false)
  641.                                     ->prototype('array')
  642.                                         ->children()
  643.                                             ->scalarNode('name')->end()
  644.                                             ->scalarNode('description')->end()
  645.                                             ->scalarNode('group')->end()
  646.                                             ->scalarNode('language')->end()
  647.                                             ->scalarNode('type')->end()
  648.                                             ->scalarNode('data')->end()
  649.                                             ->scalarNode('targetSubtype')->end()
  650.                                             ->scalarNode('config')->end()
  651.                                             ->booleanNode('inheritable')
  652.                                                 ->beforeNormalization()
  653.                                                 ->ifString()
  654.                                                 ->then(function ($v) {
  655.                                                     return (bool)$v;
  656.                                                 })
  657.                                                 ->end()
  658.                                             ->end()
  659.                                             ->integerNode('creationDate')->end()
  660.                                             ->integerNode('modificationDate')->end()
  661.                                         ->end()
  662.                                     ->end()
  663.                                 ->end()
  664.                             ->end()
  665.                         ->end()
  666.                         ->arrayNode('class_definitions')
  667.                             ->children()
  668.                                 ->arrayNode('data')
  669.                                     ->children()
  670.                                         ->arrayNode('map')
  671.                                             ->useAttributeAsKey('name')
  672.                                             ->prototype('scalar')->end()
  673.                                         ->end()
  674.                                         ->arrayNode('prefixes')
  675.                                             ->prototype('scalar')->end()
  676.                                         ->end()
  677.                                     ->end()
  678.                                 ->end()
  679.                             ->end()
  680.                         ->end();
  681.     }
  682.     /**
  683.      * Add object specific extension config
  684.      *
  685.      * @param ArrayNodeDefinition $rootNode
  686.      */
  687.     private function addObjectsNode(ArrayNodeDefinition $rootNode)
  688.     {
  689.         $objectsNode $rootNode
  690.             ->children()
  691.                 ->arrayNode('objects')
  692.                     ->ignoreExtraKeys()
  693.                     ->addDefaultsIfNotSet()
  694.                     ->children()
  695.                         ->booleanNode('ignore_localized_query_fallback')
  696.                             ->beforeNormalization()
  697.                             ->ifString()
  698.                                 ->then(function ($v) {
  699.                                     return (bool)$v;
  700.                                 })
  701.                                 ->end()
  702.                             ->defaultFalse()
  703.                         ->end()
  704.                         ->integerNode('tree_paging_limit')
  705.                             ->defaultValue(30)
  706.                         ->end()
  707.                         ->integerNode('auto_save_interval')
  708.                             ->defaultValue(60)
  709.                         ->end()
  710.                         ->arrayNode('versions')
  711.                             ->children()
  712.                                 ->scalarNode('days')->defaultNull()->end()
  713.                                 ->scalarNode('steps')->defaultNull()->end()
  714.                                 ->booleanNode('disable_stack_trace')
  715.                                     ->beforeNormalization()
  716.                                     ->ifString()
  717.                                         ->then(function ($v) {
  718.                                             return (bool)$v;
  719.                                         })
  720.                                     ->end()
  721.                                     ->defaultFalse()
  722.                                 ->end()
  723.                             ->end()
  724.                         ->end()
  725.                     ->end();
  726.         $classDefinitionsNode $objectsNode
  727.             ->children()
  728.                 ->arrayNode('class_definitions')
  729.                     ->addDefaultsIfNotSet();
  730.         $this->addImplementationLoaderNode($classDefinitionsNode'data');
  731.         $this->addImplementationLoaderNode($classDefinitionsNode'layout');
  732.     }
  733.     /**
  734.      * Add encryption specific extension config
  735.      *
  736.      * @param ArrayNodeDefinition $rootNode
  737.      */
  738.     private function addEncryptionNode(ArrayNodeDefinition $rootNode)
  739.     {
  740.         $encryptionNode $rootNode
  741.             ->children()
  742.             ->arrayNode('encryption')->addDefaultsIfNotSet();
  743.         $encryptionNode
  744.             ->children()
  745.             ->scalarNode('secret')->defaultNull();
  746.     }
  747.     /**
  748.      * Add document specific extension config
  749.      *
  750.      * @param ArrayNodeDefinition $rootNode
  751.      */
  752.     private function addDocumentsNode(ArrayNodeDefinition $rootNode)
  753.     {
  754.         $documentsNode $rootNode
  755.             ->children()
  756.                 ->arrayNode('documents')
  757.                     ->ignoreExtraKeys()
  758.                     ->addDefaultsIfNotSet();
  759.         $documentsNode
  760.             ->children()
  761.                  ->arrayNode('doc_types')
  762.                     ->addDefaultsIfNotSet()
  763.                     ->children()
  764.                         ->arrayNode('definitions')
  765.                         ->normalizeKeys(false)
  766.                             ->prototype('array')
  767.                                 ->children()
  768.                                     ->scalarNode('name')->end()
  769.                                     ->scalarNode('group')->end()
  770.                                     ->scalarNode('module')->end()
  771.                                     ->scalarNode('controller')->end()
  772.                                     ->scalarNode('template')->end()
  773.                                     ->scalarNode('type')->end()
  774.                                     ->integerNode('priority')->end()
  775.                                     ->integerNode('creationDate')->end()
  776.                                     ->integerNode('modificationDate')->end()
  777.                                     ->scalarNode('staticGeneratorEnabled')->end()
  778.                                 ->end()
  779.                             ->end()
  780.                         ->end()
  781.                     ->end()
  782.                 ->end()
  783.                 ->arrayNode('versions')
  784.                     ->children()
  785.                         ->scalarNode('days')
  786.                             ->defaultNull()
  787.                         ->end()
  788.                         ->scalarNode('steps')
  789.                             ->defaultNull()
  790.                         ->end()
  791.                         ->booleanNode('disable_stack_trace')
  792.                             ->beforeNormalization()
  793.                             ->ifString()
  794.                                 ->then(function ($v) {
  795.                                     return (bool)$v;
  796.                                 })
  797.                             ->end()
  798.                             ->defaultFalse()
  799.                         ->end()
  800.                     ->end()
  801.                 ->end()
  802.                 ->scalarNode('default_controller')
  803.                     ->defaultValue('App\\Controller\\DefaultController::defaultAction')
  804.                 ->end()
  805.                 ->arrayNode('error_pages')
  806.                     ->children()
  807.                         ->scalarNode('default')
  808.                             ->defaultNull()
  809.                         ->end()
  810.                         ->arrayNode('localized')
  811.                             ->performNoDeepMerging()
  812.                             ->beforeNormalization()
  813.                                 ->ifArray()
  814.                                     ->then(function ($v) {
  815.                                         return $v;
  816.                                     })
  817.                             ->end()
  818.                             ->prototype('scalar')
  819.                             ->end()
  820.                         ->end()
  821.                     ->end()
  822.                 ->end()
  823.                 ->scalarNode('allow_trailing_slash')
  824.                     ->defaultValue('no')
  825.                 ->end()
  826.                 ->booleanNode('generate_preview')
  827.                     ->beforeNormalization()
  828.                         ->ifString()
  829.                         ->then(function ($v) {
  830.                             return (bool)$v;
  831.                         })
  832.                     ->end()
  833.                     ->defaultFalse()
  834.                 ->end()
  835.                 ->scalarNode('preview_url_prefix')
  836.                     ->defaultValue('')
  837.                 ->end()
  838.                 ->integerNode('tree_paging_limit')
  839.                     ->defaultValue(50)
  840.                 ->end()
  841.                 ->arrayNode('editables')
  842.                     ->addDefaultsIfNotSet()
  843.                     ->children()
  844.                         ->arrayNode('map')
  845.                             ->useAttributeAsKey('name')
  846.                             ->prototype('scalar')->end()
  847.                         ->end()
  848.                         ->arrayNode('prefixes')
  849.                             ->prototype('scalar')->end()
  850.                         ->end()
  851.                     ->end()
  852.                 ->end()
  853.                 ->arrayNode('types')
  854.                     ->info('list of supported document types')
  855.                     ->scalarPrototype()->end()
  856.                 ->end()
  857.                 ->arrayNode('valid_tables')
  858.                     ->info('list of supported documents_* tables')
  859.                     ->scalarPrototype()->end()
  860.                 ->end()
  861.                 ->arrayNode('areas')
  862.                     ->addDefaultsIfNotSet()
  863.                     ->children()
  864.                         ->booleanNode('autoload')
  865.                             ->beforeNormalization()
  866.                                 ->ifString()
  867.                                 ->then(function ($v) {
  868.                                     return (bool)$v;
  869.                                 })
  870.                             ->end()
  871.                             ->defaultTrue()
  872.                         ->end()
  873.                     ->end()
  874.                 ->end()
  875.                 ->arrayNode('newsletter')
  876.                     ->addDefaultsIfNotSet()
  877.                     ->children()
  878.                         ->scalarNode('defaultUrlPrefix')
  879.                             ->defaultNull()
  880.                         ->end()
  881.                     ->end()
  882.                 ->end()
  883.                 ->arrayNode('web_to_print')
  884.                     ->addDefaultsIfNotSet()
  885.                         ->children()
  886.                             ->scalarNode('pdf_creation_php_memory_limit')
  887.                                 ->defaultValue('2048M')
  888.                             ->end()
  889.                             ->scalarNode('default_controller_print_page')
  890.                                 ->defaultValue('App\\Controller\\Web2printController::defaultAction')
  891.                             ->end()
  892.                             ->scalarNode('default_controller_print_container')
  893.                                 ->defaultValue('App\\Controller\\Web2printController::containerAction')
  894.                             ->end()
  895.                             ->booleanNode('enableInDefaultView')->end()
  896.                             ->scalarNode('generalTool')->end()
  897.                             ->scalarNode('generalDocumentSaveMode')->end()
  898.                             ->scalarNode('pdfreactorVersion')->end()
  899.                             ->scalarNode('pdfreactorProtocol')->end()
  900.                             ->scalarNode('pdfreactorServer')->end()
  901.                             ->scalarNode('pdfreactorServerPort')->end()
  902.                             ->scalarNode('pdfreactorBaseUrl')->end()
  903.                             ->scalarNode('pdfreactorApiKey')->end()
  904.                             ->scalarNode('pdfreactorLicence')->end()
  905.                             ->booleanNode('pdfreactorEnableLenientHttpsMode')->end()
  906.                             ->booleanNode('pdfreactorEnableDebugMode')->end()
  907.                             ->scalarNode('wkhtmltopdfBin')->end()
  908.                             ->variableNode('wkhtml2pdfOptions')->end()
  909.                             ->scalarNode('wkhtml2pdfHostname')->end()
  910.                             ->scalarNode('headlessChromeSettings')->end()
  911.                         ->end()
  912.                 ->end()
  913.                 ->integerNode('auto_save_interval')
  914.                     ->defaultValue(60)
  915.                 ->end()
  916.                 ->arrayNode('static_page_router')
  917.                     ->addDefaultsIfNotSet()
  918.                     ->children()
  919.                         ->booleanNode('enabled')
  920.                             ->defaultFalse()
  921.                             ->info('Enable Static Page router for document when using remote storage for generated pages')
  922.                         ->end()
  923.                         ->scalarNode('route_pattern')
  924.                             ->defaultNull()
  925.                             ->info('Optionally define route patterns to lookup static pages. Regular Expressions like: /^\/en\/Magazine/')
  926.                         ->end()
  927.                 ->end()
  928.             ->end();
  929.     }
  930.     /**
  931.      * Add implementation node config (map, prefixes)
  932.      *
  933.      * @param ArrayNodeDefinition $node
  934.      * @param string $name
  935.      */
  936.     private function addImplementationLoaderNode(ArrayNodeDefinition $node$name)
  937.     {
  938.         $node
  939.             ->children()
  940.                 ->arrayNode($name)
  941.                     ->addDefaultsIfNotSet()
  942.                     ->children()
  943.                         ->arrayNode('map')
  944.                             ->useAttributeAsKey('name')
  945.                             ->prototype('scalar')->end()
  946.                         ->end()
  947.                         ->arrayNode('prefixes')
  948.                             ->prototype('scalar')->end()
  949.                         ->end()
  950.                     ->end()
  951.                 ->end()
  952.             ->end();
  953.     }
  954.     private function addRoutingNode(ArrayNodeDefinition $rootNode)
  955.     {
  956.         $rootNode
  957.             ->children()
  958.                 ->arrayNode('routing')
  959.                     ->addDefaultsIfNotSet()
  960.                     ->children()
  961.                         ->booleanNode('allow_processing_unpublished_fallback_document')
  962.                             ->beforeNormalization()
  963.                                 ->ifString()
  964.                                 ->then(function ($v) {
  965.                                     return (bool)$v;
  966.                                 })
  967.                             ->end()
  968.                             ->defaultFalse()
  969.                             ->setDeprecated(
  970.                                 'pimcore/pimcore',
  971.                                 '10.1',
  972.                                 'The "%node%" option is deprecated since Pimcore 10.1, it will be removed in Pimcore 11.'
  973.                             )
  974.                         ->end()
  975.                         ->arrayNode('direct_route_document_types')
  976.                             ->scalarPrototype()->end()
  977.                         ->end()
  978.                         ->arrayNode('static')
  979.                             ->addDefaultsIfNotSet()
  980.                             ->children()
  981.                                 ->arrayNode('locale_params')
  982.                                     ->info('Route params from this list will be mapped to _locale if _locale is not set explicitely')
  983.                                     ->prototype('scalar')
  984.                                     ->defaultValue([])
  985.                                 ->end()
  986.                             ->end()
  987.                         ->end()
  988.                     ->end()
  989.                 ->end();
  990.     }
  991.     /**
  992.      * Add context config
  993.      *
  994.      * @param ArrayNodeDefinition $rootNode
  995.      */
  996.     private function addContextNode(ArrayNodeDefinition $rootNode)
  997.     {
  998.         $contextNode $rootNode->children()
  999.             ->arrayNode('context')
  1000.             ->useAttributeAsKey('name');
  1001.         /** @var ArrayNodeDefinition|NodeDefinition $prototype */
  1002.         $prototype $contextNode->prototype('array');
  1003.         // define routes child on each context entry
  1004.         $this->addRoutesChild($prototype'routes');
  1005.     }
  1006.     /**
  1007.      * Add admin config
  1008.      *
  1009.      * @param ArrayNodeDefinition $rootNode
  1010.      */
  1011.     private function addAdminNode(ArrayNodeDefinition $rootNode)
  1012.     {
  1013.         $adminNode $rootNode->children()
  1014.             ->arrayNode('admin')
  1015.             ->ignoreExtraKeys()
  1016.             ->addDefaultsIfNotSet();
  1017.         // add session attribute bag config
  1018.         $this->addAdminSessionAttributeBags($adminNode);
  1019.         // unauthenticated routes won't be double checked for authentication in AdminControllerListener
  1020.         $this->addRoutesChild($adminNode'unauthenticated_routes');
  1021.         $adminNode
  1022.             ->children()
  1023.                 ->arrayNode('translations')
  1024.                     ->addDefaultsIfNotSet()
  1025.                     ->children()
  1026.                         ->scalarNode('path')->defaultNull()->end()
  1027.                     ->end()
  1028.                 ->end()
  1029.             ->end();
  1030.     }
  1031.     /**
  1032.      * @param ArrayNodeDefinition $adminNode
  1033.      */
  1034.     private function addAdminSessionAttributeBags(ArrayNodeDefinition $adminNode)
  1035.     {
  1036.         // Normalizes session bag config. Allows the following formats (all formats will be
  1037.         // normalized to the third format.
  1038.         //
  1039.         // attribute_bags:
  1040.         //      - foo
  1041.         //      - bar
  1042.         //
  1043.         // attribute_bags:
  1044.         //      foo: _foo
  1045.         //      bar: _bar
  1046.         //
  1047.         // attribute_bags:
  1048.         //      foo:
  1049.         //          storage_key: _foo
  1050.         //      bar:
  1051.         //          storage_key: _bar
  1052.         $normalizers = [
  1053.             'assoc' => function (array $array) {
  1054.                 $result = [];
  1055.                 foreach ($array as $name => $value) {
  1056.                     if (null === $value) {
  1057.                         $value = [
  1058.                             'storage_key' => '_' $name,
  1059.                         ];
  1060.                     }
  1061.                     if (is_string($value)) {
  1062.                         $value = [
  1063.                             'storage_key' => $value,
  1064.                         ];
  1065.                     }
  1066.                     $result[$name] = $value;
  1067.                 }
  1068.                 return $result;
  1069.             },
  1070.             'sequential' => function (array $array) {
  1071.                 $result = [];
  1072.                 foreach ($array as $name) {
  1073.                     $result[$name] = [
  1074.                         'storage_key' => '_' $name,
  1075.                     ];
  1076.                 }
  1077.                 return $result;
  1078.             },
  1079.         ];
  1080.         $adminNode
  1081.             ->children()
  1082.                 ->arrayNode('session')
  1083.                     ->addDefaultsIfNotSet()
  1084.                     ->children()
  1085.                         ->arrayNode('attribute_bags')
  1086.                             ->useAttributeAsKey('name')
  1087.                             ->beforeNormalization()
  1088.                                 ->ifArray()->then(function ($v) use ($normalizers) {
  1089.                                     if (isAssocArray($v)) {
  1090.                                         return $normalizers['assoc']($v);
  1091.                                     } else {
  1092.                                         return $normalizers['sequential']($v);
  1093.                                     }
  1094.                                 })
  1095.                             ->end()
  1096.                             ->example([
  1097.                                 ['foo''bar'],
  1098.                                 [
  1099.                                     'foo' => '_foo',
  1100.                                     'bar' => '_bar',
  1101.                                 ],
  1102.                                 [
  1103.                                     'foo' => [
  1104.                                         'storage_key' => '_foo',
  1105.                                     ],
  1106.                                     'bar' => [
  1107.                                         'storage_key' => '_bar',
  1108.                                     ],
  1109.                                 ],
  1110.                             ])
  1111.                             ->prototype('array')
  1112.                                 ->children()
  1113.                                     ->scalarNode('storage_key')
  1114.                                         ->defaultNull()
  1115.                                     ->end()
  1116.                                 ->end()
  1117.                             ->end()
  1118.                         ->end()
  1119.                     ->end()
  1120.                 ->end()
  1121.             ->end();
  1122.     }
  1123.     private function addSecurityNode(ArrayNodeDefinition $rootNode)
  1124.     {
  1125.         $rootNode
  1126.             ->children()
  1127.                 ->arrayNode('security')
  1128.                     ->addDefaultsIfNotSet()
  1129.                     ->children()
  1130.                         ->enumNode('factory_type')
  1131.                             ->values(['encoder''password_hasher'])
  1132.                             ->defaultValue('encoder')
  1133.                         ->end()
  1134.                         ->arrayNode('encoder_factories')
  1135.                             ->info('Encoder factories to use as className => factory service ID mapping')
  1136.                             ->example([
  1137.                                 'App\Model\DataObject\User1' => [
  1138.                                     'id' => 'website_demo.security.encoder_factory2',
  1139.                                 ],
  1140.                                 'App\Model\DataObject\User2' => 'website_demo.security.encoder_factory2',
  1141.                             ])
  1142.                             ->useAttributeAsKey('class')
  1143.                             ->prototype('array')
  1144.                             ->beforeNormalization()->ifString()->then(function ($v) {
  1145.                                 return ['id' => $v];
  1146.                             })->end()
  1147.                             ->children()
  1148.                                 ->scalarNode('id')->end()
  1149.                             ->end()
  1150.                             ->end()
  1151.                         ->end()
  1152.                         ->arrayNode('password_hasher_factories')
  1153.                             ->info('Password hasher factories to use as className => factory service ID mapping')
  1154.                             ->example([
  1155.                                 'App\Model\DataObject\User1' => [
  1156.                                     'id' => 'website_demo.security.encoder_factory2',
  1157.                                 ],
  1158.                                 'App\Model\DataObject\User2' => 'website_demo.security.encoder_factory2',
  1159.                             ])
  1160.                             ->useAttributeAsKey('class')
  1161.                             ->prototype('array')
  1162.                             ->beforeNormalization()->ifString()->then(function ($v) {
  1163.                                 return ['id' => $v];
  1164.                             })->end()
  1165.                             ->children()
  1166.                             ->scalarNode('id')->end()
  1167.                             ->end()
  1168.                         ->end()
  1169.                     ->end()
  1170.                 ->end()
  1171.             ->end();
  1172.     }
  1173.     /**
  1174.      * Configure exclude paths for web profiler toolbar
  1175.      *
  1176.      * @param ArrayNodeDefinition $rootNode
  1177.      */
  1178.     private function addWebProfilerNode(ArrayNodeDefinition $rootNode)
  1179.     {
  1180.         $webProfilerNode $rootNode->children()
  1181.             ->arrayNode('web_profiler')
  1182.                 ->example([
  1183.                     'toolbar' => [
  1184.                         'excluded_routes' => [
  1185.                             ['path' => '^/test/path'],
  1186.                         ],
  1187.                     ],
  1188.                 ])
  1189.                 ->addDefaultsIfNotSet();
  1190.         $toolbarNode $webProfilerNode->children()
  1191.             ->arrayNode('toolbar')
  1192.                 ->addDefaultsIfNotSet();
  1193.         $this->addRoutesChild($toolbarNode'excluded_routes');
  1194.     }
  1195.     /**
  1196.      * Add a route prototype child
  1197.      *
  1198.      * @param ArrayNodeDefinition $parent
  1199.      * @param string $name
  1200.      */
  1201.     private function addRoutesChild(ArrayNodeDefinition $parent$name)
  1202.     {
  1203.         $node $parent->children()->arrayNode($name);
  1204.         /** @var ArrayNodeDefinition $prototype */
  1205.         $prototype $node->prototype('array');
  1206.         $prototype
  1207.             ->beforeNormalization()
  1208.                 ->ifNull()->then(function () {
  1209.                     return [];
  1210.                 })
  1211.             ->end()
  1212.             ->children()
  1213.                 ->scalarNode('path')->defaultFalse()->end()
  1214.                 ->scalarNode('route')->defaultFalse()->end()
  1215.                 ->scalarNode('host')->defaultFalse()->end()
  1216.                 ->arrayNode('methods')
  1217.                     ->prototype('scalar')->end()
  1218.                 ->end()
  1219.             ->end();
  1220.     }
  1221.     /**
  1222.      * Add cache config
  1223.      *
  1224.      * @param ArrayNodeDefinition $rootNode
  1225.      */
  1226.     private function addCacheNode(ArrayNodeDefinition $rootNode)
  1227.     {
  1228.         $rootNode->children()
  1229.             ->arrayNode('full_page_cache')
  1230.                 ->ignoreExtraKeys()
  1231.                 ->canBeDisabled()
  1232.                 ->addDefaultsIfNotSet()
  1233.                 ->children()
  1234.                     ->scalarNode('lifetime')
  1235.                         ->info('Optional output-cache lifetime (in seconds) after the cache expires, if not defined the cache will be cleaned on every action inside the CMS, otherwise not (for high traffic sites)')
  1236.                         ->defaultNull()
  1237.                     ->end()
  1238.                     ->scalarNode('exclude_patterns')
  1239.                         ->info('Regular Expressions like: /^\/dir\/toexclude/')
  1240.                     ->end()
  1241.                     ->scalarNode('exclude_cookie')
  1242.                         ->info('Comma separated list of cookie names, that will automatically disable the full-page cache')
  1243.                     ->end()
  1244.                 ->end()
  1245.             ->end();
  1246.     }
  1247.     /**
  1248.      * Adds configuration for email source adapters
  1249.      *
  1250.      * @param ArrayNodeDefinition $rootNode
  1251.      */
  1252.     private function addEmailNode(ArrayNodeDefinition $rootNode)
  1253.     {
  1254.         $rootNode
  1255.             ->children()
  1256.                 ->arrayNode('email')
  1257.                 ->addDefaultsIfNotSet()
  1258.                     ->children()
  1259.                         ->arrayNode('sender')
  1260.                             ->addDefaultsIfNotSet()
  1261.                             ->children()
  1262.                                 ->scalarNode('name')
  1263.                                     ->defaultValue('')
  1264.                                 ->end()
  1265.                                 ->scalarNode('email')
  1266.                                     ->defaultValue('')
  1267.                                 ->end()
  1268.                             ->end()
  1269.                         ->end()
  1270.                         ->arrayNode('return')
  1271.                             ->addDefaultsIfNotSet()
  1272.                             ->children()
  1273.                                 ->scalarNode('name')
  1274.                                     ->defaultValue('')
  1275.                                 ->end()
  1276.                                 ->scalarNode('email')
  1277.                                     ->defaultValue('')
  1278.                                 ->end()
  1279.                             ->end()
  1280.                         ->end()
  1281.                         ->arrayNode('debug')
  1282.                             ->addDefaultsIfNotSet()
  1283.                             ->children()
  1284.                                 ->scalarNode('email_addresses')
  1285.                                     ->defaultValue('')
  1286.                                 ->end()
  1287.                             ->end()
  1288.                         ->end()
  1289.                         ->scalarNode('usespecific')
  1290.                             ->defaultFalse()
  1291.                         ->end()
  1292.                     ->end()
  1293.                 ->end()
  1294.             ->end();
  1295.     }
  1296.     /**
  1297.      * Adds configuration tree for newsletter source adapters
  1298.      *
  1299.      * @param ArrayNodeDefinition $rootNode
  1300.      */
  1301.     private function addNewsletterNode(ArrayNodeDefinition $rootNode)
  1302.     {
  1303.         $rootNode
  1304.             ->children()
  1305.                 ->arrayNode('newsletter')
  1306.                     ->addDefaultsIfNotSet()
  1307.                     ->children()
  1308.                         ->arrayNode('sender')
  1309.                             ->children()
  1310.                                 ->scalarNode('name')->end()
  1311.                                 ->scalarNode('email')->end()
  1312.                             ->end()
  1313.                         ->end()
  1314.                         ->arrayNode('return')
  1315.                             ->children()
  1316.                                 ->scalarNode('name')->end()
  1317.                                 ->scalarNode('email')->end()
  1318.                             ->end()
  1319.                         ->end()
  1320.                         ->scalarNode('method')
  1321.                             ->defaultNull()
  1322.                         ->end()
  1323.                         ->arrayNode('debug')
  1324.                             ->children()
  1325.                                 ->scalarNode('email_addresses')
  1326.                                     ->defaultValue('')
  1327.                                 ->end()
  1328.                             ->end()
  1329.                         ->end()
  1330.                         ->booleanNode('use_specific')
  1331.                             ->beforeNormalization()
  1332.                                 ->ifString()
  1333.                                 ->then(function ($v) {
  1334.                                     return (bool)$v;
  1335.                                 })
  1336.                             ->end()
  1337.                         ->end()
  1338.                         ->arrayNode('source_adapters')
  1339.                             ->useAttributeAsKey('name')
  1340.                                 ->prototype('scalar')
  1341.                             ->end()
  1342.                         ->end()
  1343.                     ->end()
  1344.                 ->end()
  1345.             ->end();
  1346.     }
  1347.     /**
  1348.      * Adds configuration tree for custom report adapters
  1349.      *
  1350.      * @param ArrayNodeDefinition $rootNode
  1351.      */
  1352.     private function addCustomReportsNode(ArrayNodeDefinition $rootNode)
  1353.     {
  1354.         $rootNode
  1355.             ->children()
  1356.                 ->arrayNode('custom_report')
  1357.                     ->addDefaultsIfNotSet()
  1358.                     ->children()
  1359.                         ->arrayNode('definitions')
  1360.                                 ->normalizeKeys(false)
  1361.                                 ->prototype('array')
  1362.                                     ->children()
  1363.                                         ->scalarNode('id')->end()
  1364.                                         ->scalarNode('name')->end()
  1365.                                         ->scalarNode('niceName')->end()
  1366.                                         ->scalarNode('sql')->end()
  1367.                                         ->scalarNode('group')->end()
  1368.                                         ->scalarNode('groupIconClass')->end()
  1369.                                         ->scalarNode('iconClass')->end()
  1370.                                         ->booleanNode('menuShortcut')->end()
  1371.                                         ->scalarNode('reportClass')->end()
  1372.                                         ->scalarNode('chartType')->end()
  1373.                                         ->scalarNode('pieColumn')->end()
  1374.                                         ->scalarNode('pieLabelColumn')->end()
  1375.                                         ->variableNode('xAxis')->end()
  1376.                                         ->variableNode('yAxis')->end()
  1377.                                         ->integerNode('modificationDate')->end()
  1378.                                         ->integerNode('creationDate')->end()
  1379.                                         ->booleanNode('shareGlobally')->end()
  1380.                                         ->variableNode('sharedUserNames')->end()
  1381.                                         ->variableNode('sharedRoleNames')->end()
  1382.                                         ->arrayNode('dataSourceConfig')
  1383.                                             ->prototype('variable')
  1384.                                             ->end()
  1385.                                         ->end()
  1386.                                         ->arrayNode('columnConfiguration')
  1387.                                             ->prototype('variable')
  1388.                                             ->end()
  1389.                                         ->end()
  1390.                                     ->end()
  1391.                                 ->end()
  1392.                         ->end()
  1393.                         ->arrayNode('adapters')
  1394.                             ->useAttributeAsKey('name')
  1395.                                 ->prototype('scalar')
  1396.                             ->end()
  1397.                         ->end()
  1398.                     ->end()
  1399.                 ->end()
  1400.             ->end();
  1401.     }
  1402.     private function addTargetingNode(ArrayNodeDefinition $rootNode)
  1403.     {
  1404.         $rootNode
  1405.             ->children()
  1406.                 ->arrayNode('targeting')
  1407.                     ->canBeDisabled()
  1408.                     ->addDefaultsIfNotSet()
  1409.                     ->children()
  1410.                         ->scalarNode('storage_id')
  1411.                             ->info('Service ID of the targeting storage which should be used. This ID will be aliased to ' TargetingStorageInterface::class)
  1412.                             ->defaultValue(CookieStorage::class)
  1413.                             ->cannotBeEmpty()
  1414.                         ->end()
  1415.                         ->arrayNode('session')
  1416.                             ->info('Enables HTTP session support by configuring session bags and the full page cache')
  1417.                             ->canBeEnabled()
  1418.                         ->end()
  1419.                         ->arrayNode('data_providers')
  1420.                             ->useAttributeAsKey('key')
  1421.                                 ->prototype('scalar')
  1422.                             ->end()
  1423.                         ->end()
  1424.                         ->arrayNode('conditions')
  1425.                             ->useAttributeAsKey('key')
  1426.                                 ->prototype('scalar')
  1427.                             ->end()
  1428.                         ->end()
  1429.                         ->arrayNode('action_handlers')
  1430.                             ->useAttributeAsKey('name')
  1431.                                 ->prototype('scalar')
  1432.                             ->end()
  1433.                         ->end()
  1434.                     ->end()
  1435.                 ->end()
  1436.             ->end();
  1437.     }
  1438.     private function addSitemapsNode(ArrayNodeDefinition $rootNode)
  1439.     {
  1440.         $rootNode
  1441.             ->children()
  1442.                 ->arrayNode('sitemaps')
  1443.                     ->addDefaultsIfNotSet()
  1444.                     ->children()
  1445.                         ->arrayNode('generators')
  1446.                             ->useAttributeAsKey('name')
  1447.                             ->prototype('array')
  1448.                                 ->beforeNormalization()
  1449.                                     ->ifString()
  1450.                                     ->then(function ($v) {
  1451.                                         return [
  1452.                                             'enabled' => true,
  1453.                                             'generator_id' => $v,
  1454.                                             'priority' => 0,
  1455.                                         ];
  1456.                                     })
  1457.                                 ->end()
  1458.                                 ->addDefaultsIfNotSet()
  1459.                                 ->canBeDisabled()
  1460.                                 ->children()
  1461.                                     ->scalarNode('generator_id')
  1462.                                         ->cannotBeEmpty()
  1463.                                     ->end()
  1464.                                     ->integerNode('priority')
  1465.                                         ->defaultValue(0)
  1466.                                     ->end()
  1467.                                 ->end()
  1468.                             ->end()
  1469.                         ->end()
  1470.                     ->end()
  1471.                 ->end()
  1472.             ->end()
  1473.         ->end();
  1474.     }
  1475.     private function addWorkflowNode(ArrayNodeDefinition $rootNode)
  1476.     {
  1477.         $rootNode
  1478.             ->children()
  1479.                  ->arrayNode('workflows')
  1480.                         ->useAttributeAsKey('name')
  1481.                         ->prototype('array')
  1482.                             ->children()
  1483.                                 ->arrayNode('placeholders')
  1484.                                     ->info('Placeholder values in this workflow configuration (locale: "%%locale%%") will be replaced by the given placeholder value (eg. "de_AT")')
  1485.                                     ->example([
  1486.                                         'placeholders' => [
  1487.                                             '%%locale%%' => 'de_AT',
  1488.                                         ],
  1489.                                     ])
  1490.                                     ->defaultValue([])
  1491.                                     ->beforeNormalization()
  1492.                                         ->castToArray()
  1493.                                         ->always()
  1494.                                         ->then(function ($placeholders) {
  1495.                                             $this->placeholders $placeholders;
  1496.                                             return $placeholders;
  1497.                                         })
  1498.                                     ->end()
  1499.                                     ->prototype('scalar')->end()
  1500.                                 ->end()
  1501.                                 ->arrayNode('custom_extensions')->ignoreExtraKeys(false)->info('Use this key to attach additional config information to a workflow, for example via bundles, etc.')->end()
  1502.                                 ->booleanNode('enabled')
  1503.                                     ->defaultTrue()
  1504.                                     ->info('Can be used to enable or disable the workflow.')
  1505.                                 ->end()
  1506.                                 ->integerNode('priority')
  1507.                                     ->defaultValue(0)
  1508.                                     ->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.')
  1509.                                 ->end()
  1510.                                 ->scalarNode('label')
  1511.                                     ->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.')
  1512.                                 ->end()
  1513.                                 ->arrayNode('audit_trail')
  1514.                                     ->canBeEnabled()
  1515.                                     ->info('Enable default audit trail feature provided by Symfony. Take a look at the Symfony docs for more details.')
  1516.                                 ->end()
  1517.                                 ->enumNode('type')
  1518.                                     ->values(['workflow''state_machine'])
  1519.                                     ->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.')
  1520.                                 ->end()
  1521.                                 ->arrayNode('marking_store')
  1522.                                     ->fixXmlConfig('argument')
  1523.                                     ->children()
  1524.                                         ->enumNode('type')
  1525.                                             ->values(['multiple_state''single_state''state_table''data_object_multiple_state''data_object_splitted_state'])
  1526.                                         ->end()
  1527.                                         ->arrayNode('arguments')
  1528.                                             ->beforeNormalization()
  1529.                                                 ->always()
  1530.                                                 ->then(function ($arguments) {
  1531.                                                     if (is_string($arguments)) {
  1532.                                                         $arguments = [$arguments];
  1533.                                                     }
  1534.                                                     if (!empty($this->placeholders)) {
  1535.                                                         $arguments $this->placeholderProcessor->mergePlaceholders($arguments$this->placeholders);
  1536.                                                     }
  1537.                                                     return $arguments;
  1538.                                                 })
  1539.                                             ->end()
  1540.                                             ->requiresAtLeastOneElement()
  1541.                                             ->prototype('variable')
  1542.                                             ->end()
  1543.                                         ->end()
  1544.                                         ->scalarNode('service')
  1545.                                             ->cannotBeEmpty()
  1546.                                         ->end()
  1547.                                     ->end()
  1548.                                     ->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.')
  1549.                                     ->validate()
  1550.                                         ->ifTrue(function ($v) {
  1551.                                             return isset($v['type']) && isset($v['service']);
  1552.                                         })
  1553.                                         ->thenInvalid('"type" and "service" cannot be used together.')
  1554.                                     ->end()
  1555.                                     ->validate()
  1556.                                         ->ifTrue(function ($v) {
  1557.                                             return !empty($v['arguments']) && isset($v['service']);
  1558.                                         })
  1559.                                         ->thenInvalid('"arguments" and "service" cannot be used together.')
  1560.                                     ->end()
  1561.                                 ->end()
  1562.                                 ->arrayNode('supports')
  1563.                                     ->beforeNormalization()
  1564.                                         ->ifString()
  1565.                                         ->then(function ($v) {
  1566.                                             return [$v];
  1567.                                         })
  1568.                                     ->end()
  1569.                                     ->prototype('scalar')
  1570.                                         ->cannotBeEmpty()
  1571.                                     ->end()
  1572.                                     ->info('List of supported entity classes. Take a look at the Symfony docs for more details.')
  1573.                                     ->example(['\Pimcore\Model\DataObject\Product'])
  1574.                                 ->end()
  1575.                                 ->arrayNode('support_strategy')
  1576.                                     ->fixXmlConfig('argument')
  1577.                                     ->children()
  1578.                                         ->enumNode('type')
  1579.                                             ->values(['expression'])
  1580.                                             ->info('Type "expression": a symfony expression to define a criteria.')
  1581.                                         ->end()
  1582.                                         ->arrayNode('arguments')
  1583.                                             ->beforeNormalization()
  1584.                                                 ->ifString()
  1585.                                                 ->then(function ($v) {
  1586.                                                     return [$v];
  1587.                                                 })
  1588.                                             ->end()
  1589.                                             ->requiresAtLeastOneElement()
  1590.                                             ->prototype('variable')
  1591.                                             ->end()
  1592.                                         ->end()
  1593.                                         ->scalarNode('service')
  1594.                                             ->cannotBeEmpty()
  1595.                                             ->info('Define a custom service to handle the logic. Take a look at the Symfony docs for more details.')
  1596.                                         ->end()
  1597.                                     ->end()
  1598.                                     ->validate()
  1599.                                         ->ifTrue(function ($v) {
  1600.                                             return isset($v['type']) && isset($v['service']);
  1601.                                         })
  1602.                                         ->thenInvalid('"type" and "service" cannot be used together.')
  1603.                                     ->end()
  1604.                                     ->validate()
  1605.                                         ->ifTrue(function ($v) {
  1606.                                             return !empty($v['arguments']) && isset($v['service']);
  1607.                                         })
  1608.                                         ->thenInvalid('"arguments" and "service" cannot be used together.')
  1609.                                     ->end()
  1610.                                     ->info('Can be used to implement a special logic which subjects are supported by the workflow. For example only products matching certain criteria.')
  1611.                                     ->example([
  1612.                                         'type' => 'expression',
  1613.                                         'arguments' => [
  1614.                                             '\Pimcore\Model\DataObject\Product',
  1615.                                             'subject.getProductType() == "article" and is_fully_authenticated() and "ROLE_PIMCORE_ADMIN" in roles',
  1616.                                         ],
  1617.                                     ])
  1618.                                 ->end()
  1619.                                 ->arrayNode('initial_markings')
  1620.                                     ->info('Can be used to set the initial places (markings) for a workflow. Note that this option is Symfony 4.3+ only')
  1621.                                     ->beforeNormalization()
  1622.                                         ->ifString()
  1623.                                             ->then(function ($v) {
  1624.                                                 return [$v];
  1625.                                             })
  1626.                                         ->end()
  1627.                                         ->requiresAtLeastOneElement()
  1628.                                         ->prototype('scalar')
  1629.                                         ->cannotBeEmpty()
  1630.                                     ->end()
  1631.                                 ->end()
  1632.                                 ->arrayNode('places')
  1633.                                     ->prototype('array')
  1634.                                         ->children()
  1635.                                             ->scalarNode('label')->info('Nice name which will be used in the Pimcore backend.')->end()
  1636.                                             ->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()
  1637.                                             ->scalarNode('color')->info('Color of the place which will be used in the Pimcore backend.')->defaultValue('#bfdadc')->end()
  1638.                                             ->booleanNode('colorInverted')->info('If set to true the color will be used as border and font color otherwise as background color.')->defaultFalse()->end()
  1639.                                             ->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()
  1640.                                             ->arrayNode('permissions')
  1641.                                                 ->prototype('array')
  1642.                                                     ->children()
  1643.                                                         ->scalarNode('condition')->info('A symfony expression can be configured here. The first set of permissions which are matching the condition will be used.')->end()
  1644.                                                         ->booleanNode('save')->info('save permission as it can be configured in Pimcore workplaces')->end()
  1645.                                                         ->booleanNode('publish')->info('publish permission as it can be configured in Pimcore workplaces')->end()
  1646.                                                         ->booleanNode('unpublish')->info('unpublish permission as it can be configured in Pimcore workplaces')->end()
  1647.                                                         ->booleanNode('delete')->info('delete permission as it can be configured in Pimcore workplaces')->end()
  1648.                                                         ->booleanNode('rename')->info('rename permission as it can be configured in Pimcore workplaces')->end()
  1649.                                                         ->booleanNode('view')->info('view permission as it can be configured in Pimcore workplaces')->end()
  1650.                                                         ->booleanNode('settings')->info('settings permission as it can be configured in Pimcore workplaces')->end()
  1651.                                                         ->booleanNode('versions')->info('versions permission as it can be configured in Pimcore workplaces')->end()
  1652.                                                         ->booleanNode('properties')->info('properties permission as it can be configured in Pimcore workplaces')->end()
  1653.                                                         ->booleanNode('modify')->info('a short hand for save, publish, unpublish, delete + rename')->end()
  1654.                                                         ->scalarNode('objectLayout')->info('if set, the user will see the configured custom data object layout')->end()
  1655.                                                     ->end()
  1656.                                                 ->end()
  1657.                                             ->end()
  1658.                                         ->end()
  1659.                                     ->end()
  1660.                                     ->beforeNormalization()
  1661.                                         ->always()
  1662.                                         ->then(function ($places) {
  1663.                                             if (!empty($this->placeholders)) {
  1664.                                                 foreach ($places as $name => $place) {
  1665.                                                     $places[$name] = $this->placeholderProcessor->mergePlaceholders($place$this->placeholders);
  1666.                                                 }
  1667.                                             }
  1668.                                             return $places;
  1669.                                         })
  1670.                                     ->end()
  1671.                                     ->example([
  1672.                                         'places' => [
  1673.                                             'closed' => [
  1674.                                                 'label' => 'close product',
  1675.                                                 'permissions' => [
  1676.                                                     [
  1677.                                                         'condition' => "is_fully_authenticated() and 'ROLE_PIMCORE_ADMIN' in roles",
  1678.                                                         'modify' => false,
  1679.                                                     ],
  1680.                                                     [
  1681.                                                         'modify' => false,
  1682.                                                         'objectLayout' => 2,
  1683.                                                     ],
  1684.                                                 ],
  1685.                                             ],
  1686.                                         ],
  1687.                                     ])
  1688.                                 ->end()
  1689.                                 ->arrayNode('transitions')
  1690.                                     ->beforeNormalization()
  1691.                                         ->always()
  1692.                                         ->then(function ($transitions) {
  1693.                                             // It's an indexed array, we let the validation occurs
  1694.                                             if (isset($transitions[0])) {
  1695.                                                 return $transitions;
  1696.                                             }
  1697.                                             foreach ($transitions as $name => $transition) {
  1698.                                                 if (array_key_exists('name', (array) $transition)) {
  1699.                                                     continue;
  1700.                                                 }
  1701.                                                 $transition['name'] = $name;
  1702.                                                 $transitions[$name] = $transition;
  1703.                                             }
  1704.                                             return $transitions;
  1705.                                         })
  1706.                                     ->end()
  1707.                                     ->isRequired()
  1708.                                     ->requiresAtLeastOneElement()
  1709.                                     ->prototype('array')
  1710.                                         ->children()
  1711.                                             ->scalarNode('name')
  1712.                                                 ->isRequired()
  1713.                                                 ->cannotBeEmpty()
  1714.                                             ->end()
  1715.                                             ->scalarNode('guard')
  1716.                                                 ->cannotBeEmpty()
  1717.                                                 ->info('An expression to block the transition')
  1718.                                                 ->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
  1719.                                             ->end()
  1720.                                             ->arrayNode('from')
  1721.                                                 ->beforeNormalization()
  1722.                                                     ->ifString()
  1723.                                                     ->then(function ($v) {
  1724.                                                         return [$v];
  1725.                                                     })
  1726.                                                 ->end()
  1727.                                                 ->requiresAtLeastOneElement()
  1728.                                                 ->prototype('scalar')
  1729.                                                     ->cannotBeEmpty()
  1730.                                                 ->end()
  1731.                                             ->end()
  1732.                                             ->arrayNode('to')
  1733.                                                 ->beforeNormalization()
  1734.                                                     ->ifString()
  1735.                                                     ->then(function ($v) {
  1736.                                                         return [$v];
  1737.                                                     })
  1738.                                                 ->end()
  1739.                                                 ->requiresAtLeastOneElement()
  1740.                                                 ->prototype('scalar')
  1741.                                                     ->cannotBeEmpty()
  1742.                                                 ->end()
  1743.                                             ->end()
  1744.                                             ->arrayNode('options')
  1745.                                                 ->children()
  1746.                                                     ->scalarNode('label')->info('Nice name for the Pimcore backend.')->end()
  1747.                                                     ->arrayNode('notes')
  1748.                                                         ->children()
  1749.                                                             ->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()
  1750.                                                             ->booleanNode('commentRequired')->defaultFalse()->info('Set this to true if the comment should be a required field.')->end()
  1751.                                                             ->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()
  1752.                                                             ->scalarNode('commentGetterFn')->info('Can be used for data objects to prefill the comment field with data from the data object.')->end()
  1753.                                                             ->scalarNode('type')->defaultValue('Status update')->info('Set\'s the type string in the saved note.')->end()
  1754.                                                             ->scalarNode('title')->info('An optional alternative "title" for the note, if blank the actions transition result is used.')->end()
  1755.                                                             ->arrayNode('additionalFields')
  1756.                                                                 ->prototype('array')
  1757.                                                                     ->children()
  1758.                                                                         ->scalarNode('name')->isRequired()->info('The technical name used in the input form.')->end()
  1759.                                                                         ->enumNode('fieldType')
  1760.                                                                             ->isRequired()
  1761.                                                                             ->values(['input''numeric''textarea''select''datetime''date''user''checkbox'])
  1762.                                                                             ->info('The data component name/field type.')
  1763.                                                                         ->end()
  1764.                                                                         ->scalarNode('title')->info('The label used by the field')->end()
  1765.                                                                         ->booleanNode('required')->defaultFalse()->info('Whether or not the field is required.')->end()
  1766.                                                                         ->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()
  1767.                                                                         ->arrayNode('fieldTypeSettings')
  1768.                                                                              ->prototype('variable')->end()
  1769.                                                                              ->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.')
  1770.                                                                         ->end()
  1771.                                                                     ->end()
  1772.                                                                 ->end()
  1773.                                                                 ->info('Add additional field to the transition detail window.')
  1774.                                                             ->end()
  1775.                                                             ->arrayNode('customHtml')
  1776.                                                                 ->children()
  1777.                                                                     ->enumNode('position')
  1778.                                                                         ->values(['top''center''bottom'])
  1779.                                                                         ->defaultValue('top')
  1780.                                                                         ->info('Set position of custom HTML inside modal (top, center, bottom).')
  1781.                                                                     ->end()
  1782.                                                                     ->scalarNode('service')
  1783.                                                                         ->cannotBeEmpty()
  1784.                                                                         ->info('Define a custom service for rendering custom HTML within the note modal.')
  1785.                                                                     ->end()
  1786.                                                                 ->end()
  1787.                                                             ->end()
  1788.                                                         ->end()
  1789.                                                     ->end()
  1790.                                                     ->scalarNode('iconClass')->info('Css class to define the icon which will be used in the actions button in the backend.')->end()
  1791.                                                     ->scalarNode('objectLayout')->defaultValue(false)->info('Forces an object layout after the transition was performed. This objectLayout setting overrules all objectLayout settings within the places configs.')->end()
  1792.                                                     ->arrayNode('notificationSettings')
  1793.                                                         ->prototype('array')
  1794.                                                             ->children()
  1795.                                                                 ->scalarNode('condition')->info('A symfony expression can be configured here. All sets of notification which are matching the condition will be used.')->end()
  1796.                                                                 ->arrayNode('notifyUsers')
  1797.                                                                     ->prototype('scalar')
  1798.                                                                         ->cannotBeEmpty()
  1799.                                                                     ->end()
  1800.                                                                     ->info('Send an email notification to a list of users (user names) when the transition get\'s applied')
  1801.                                                                 ->end()
  1802.                                                                 ->arrayNode('notifyRoles')
  1803.                                                                     ->prototype('scalar')
  1804.                                                                         ->cannotBeEmpty()
  1805.                                                                     ->end()
  1806.                                                                     ->info('Send an email notification to a list of user roles (role names) when the transition get\'s applied')
  1807.                                                                 ->end()
  1808.                                                                 ->arrayNode('channelType')
  1809.                                                                     ->requiresAtLeastOneElement()
  1810.                                                                     ->enumPrototype()
  1811.                                                                         ->values([NotificationSubscriber::NOTIFICATION_CHANNEL_MAILNotificationSubscriber::NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION])
  1812.                                                                         ->cannotBeEmpty()
  1813.                                                                         ->defaultValue(NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL)
  1814.                                                                     ->end()
  1815.                                                                     ->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 '".')
  1816.                                                                     ->addDefaultChildrenIfNoneSet()
  1817.                                                                 ->end()
  1818.                                                                 ->enumNode('mailType')
  1819.                                                                     ->values([NotificationSubscriber::MAIL_TYPE_TEMPLATENotificationSubscriber::MAIL_TYPE_DOCUMENT])
  1820.                                                                     ->defaultValue(NotificationSubscriber::MAIL_TYPE_TEMPLATE)
  1821.                                                                     ->info('Type of mail source.')
  1822.                                                                 ->end()
  1823.                                                                 ->scalarNode('mailPath')
  1824.                                                                     ->defaultValue(NotificationSubscriber::DEFAULT_MAIL_TEMPLATE_PATH)
  1825.                                                                     ->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.')
  1826.                                                                 ->end()
  1827.                                                             ->end()
  1828.                                                         ->end()
  1829.                                                     ->end()
  1830.                                                     ->enumNode('changePublishedState')
  1831.                                                         ->values([ChangePublishedStateSubscriber::NO_CHANGEChangePublishedStateSubscriber::FORCE_UNPUBLISHEDChangePublishedStateSubscriber::FORCE_PUBLISHEDChangePublishedStateSubscriber::SAVE_VERSION])
  1832.                                                         ->defaultValue(ChangePublishedStateSubscriber::NO_CHANGE)
  1833.                                                         ->info('Change published state of element while transition (only available for documents and data objects).')
  1834.                                                     ->end()
  1835.                                                 ->end()
  1836.                                             ->end()
  1837.                                         ->end()
  1838.                                     ->end()
  1839.                                     ->example([
  1840.                                         'close_product' => [
  1841.                                             'from' => 'open',
  1842.                                             'to' => 'closed',
  1843.                                             'options' => [
  1844.                                                 'label' => 'close product',
  1845.                                                 'notes' => [
  1846.                                                     'commentEnabled' => true,
  1847.                                                     'commentRequired' => true,
  1848.                                                     'additionalFields' => [
  1849.                                                         [
  1850.                                                             'name' => 'accept',
  1851.                                                             'title' => 'accept terms',
  1852.                                                             'required' => true,
  1853.                                                             'fieldType' => 'checkbox',
  1854.                                                         ],
  1855.                                                         [
  1856.                                                             'name' => 'select',
  1857.                                                             'title' => 'please select a type',
  1858.                                                             'setterFn' => 'setSpecialWorkflowType',
  1859.                                                             'fieldType' => 'select',
  1860.                                                             'fieldTypeSettings' => [
  1861.                                                                 'options' => [
  1862.                                                                     ['key' => 'Option A''value' => 'a'],
  1863.                                                                     ['key' => 'Option B''value' => 'b'],
  1864.                                                                     ['key' => 'Option C''value' => 'c'],
  1865.                                                                 ],
  1866.                                                             ],
  1867.                                                         ],
  1868.                                                     ],
  1869.                                                 ],
  1870.                                             ],
  1871.                                         ],
  1872.                                     ])
  1873.                                 ->end()
  1874.                                 ->arrayNode('globalActions')
  1875.                                     ->prototype('array')
  1876.                                         ->children()
  1877.                                             ->scalarNode('label')->info('Nice name for the Pimcore backend.')->end()
  1878.                                             ->scalarNode('iconClass')->info('Css class to define the icon which will be used in the actions button in the backend.')->end()
  1879.                                             ->scalarNode('objectLayout')->defaultValue(false)->info('Forces an object layout after the global action was performed. This objectLayout setting overrules all objectLayout settings within the places configs.')->end()
  1880.                                             ->scalarNode('guard')
  1881.                                                 ->cannotBeEmpty()
  1882.                                                 ->info('An expression to block the action')
  1883.                                                 ->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
  1884.                                             ->end()
  1885.                                             ->arrayNode('to')
  1886.                                                 ->beforeNormalization()
  1887.                                                     ->ifString()
  1888.                                                     ->then(function ($v) {
  1889.                                                         return [$v];
  1890.                                                     })
  1891.                                                 ->end()
  1892.                                                 ->requiresAtLeastOneElement()
  1893.                                                 ->prototype('scalar')
  1894.                                                     ->cannotBeEmpty()
  1895.                                                 ->end()
  1896.                                                 ->info('Optionally set the current place of the workflow. Can be used for example to reset the workflow to the initial place.')
  1897.                                             ->end()
  1898.                                             ->arrayNode('notes')
  1899.                                                 ->children()
  1900.                                                     ->booleanNode('commentEnabled')->defaultFalse()->end()
  1901.                                                     ->booleanNode('commentRequired')->defaultFalse()->end()
  1902.                                                     ->scalarNode('commentSetterFn')->end()
  1903.                                                     ->scalarNode('commentGetterFn')->end()
  1904.                                                     ->scalarNode('type')->defaultValue('Status update')->end()
  1905.                                                     ->scalarNode('title')->end()
  1906.                                                     ->arrayNode('additionalFields')
  1907.                                                         ->prototype('array')
  1908.                                                             ->children()
  1909.                                                                 ->scalarNode('name')->isRequired()->end()
  1910.                                                                 ->enumNode('fieldType')
  1911.                                                                     ->isRequired()
  1912.                                                                     ->values(['input''textarea''select''datetime''date''user''checkbox'])
  1913.                                                                 ->end()
  1914.                                                                 ->scalarNode('title')->end()
  1915.                                                                 ->booleanNode('required')->defaultFalse()->end()
  1916.                                                                 ->scalarNode('setterFn')->end()
  1917.                                                                 ->arrayNode('fieldTypeSettings')
  1918.                                                                      ->prototype('variable')->end()
  1919.                                                                 ->end()
  1920.                                                             ->end()
  1921.                                                         ->end()
  1922.                                                     ->end()
  1923.                                                     ->arrayNode('customHtml')
  1924.                                                         ->children()
  1925.                                                             ->enumNode('position')
  1926.                                                                 ->values(['top''center''bottom'])
  1927.                                                                 ->defaultValue('top')
  1928.                                                                 ->info('Set position of custom HTML inside modal (top, center, bottom).')
  1929.                                                             ->end()
  1930.                                                             ->scalarNode('service')
  1931.                                                                 ->cannotBeEmpty()
  1932.                                                                 ->info('Define a custom service for rendering custom HTML within the note modal.')
  1933.                                                             ->end()
  1934.                                                         ->end()
  1935.                                                     ->end()
  1936.                                                 ->end()
  1937.                                                 ->info('See notes section of transitions. It works exactly the same way.')
  1938.                                             ->end()
  1939.                                         ->end()
  1940.                                     ->end()
  1941.                                     ->info('Actions which will be added to actions button independently of the current workflow place.')
  1942.                                 ->end()
  1943.                             ->end()
  1944.                             ->validate()
  1945.                                 ->ifTrue(function ($v) {
  1946.                                     return $v['supports'] && isset($v['support_strategy']);
  1947.                                 })
  1948.                                 ->thenInvalid('"supports" and "support_strategy" cannot be used together.')
  1949.                             ->end()
  1950.                             ->validate()
  1951.                                 ->ifTrue(function ($v) {
  1952.                                     return !$v['supports'] && !isset($v['support_strategy']);
  1953.                                 })
  1954.                                 ->thenInvalid('"supports" or "support_strategy" should be configured.')
  1955.                             ->end()
  1956.                             ->validate()
  1957.                                 ->ifTrue(function ($v) {
  1958.                                     if (($v['type'] ?? 'workflow') === 'state_machine') {
  1959.                                         foreach ($v['transitions'] ?? [] as $transition) {
  1960.                                             if (count($transition['to']) > 1) {
  1961.                                                 return true;
  1962.                                             }
  1963.                                         }
  1964.                                         foreach ($v['globalActions'] ?? [] as $transition) {
  1965.                                             if (count($transition['to']) > 1) {
  1966.                                                 return true;
  1967.                                             }
  1968.                                         }
  1969.                                     }
  1970.                                     return false;
  1971.                                 })
  1972.                                 ->thenInvalid('Type `state_machine` does not support multiple `to` definitions for transitions and global actions. Change definition or type to `workflow`.')
  1973.                             ->end()
  1974.                         ->end()
  1975.                     ->end()
  1976.                 ->end()
  1977.                 ->addDefaultsIfNotSet()
  1978.             ->end();
  1979.     }
  1980.     /**
  1981.      * Add predefined properties specific extension config
  1982.      *
  1983.      * @param ArrayNodeDefinition $rootNode
  1984.      */
  1985.     private function addPredefinedPropertiesNode(ArrayNodeDefinition $rootNode)
  1986.     {
  1987.         $predefinedPropertiesNode $rootNode
  1988.             ->children()
  1989.             ->arrayNode('properties')
  1990.             ->ignoreExtraKeys()
  1991.             ->addDefaultsIfNotSet();
  1992.         $predefinedPropertiesNode
  1993.         ->children()
  1994.             ->arrayNode('predefined')
  1995.                 ->addDefaultsIfNotSet()
  1996.                 ->children()
  1997.                     ->arrayNode('definitions')
  1998.                     ->normalizeKeys(false)
  1999.                         ->prototype('array')
  2000.                             ->children()
  2001.                                 ->scalarNode('name')->end()
  2002.                                 ->scalarNode('description')->end()
  2003.                                 ->scalarNode('key')->end()
  2004.                                 ->scalarNode('type')->end()
  2005.                                 ->scalarNode('data')->end()
  2006.                                 ->scalarNode('config')->end()
  2007.                                 ->scalarNode('ctype')->end()
  2008.                                 ->booleanNode('inheritable')
  2009.                                     ->beforeNormalization()
  2010.                                         ->ifString()
  2011.                                         ->then(function ($v) {
  2012.                                             return (bool)$v;
  2013.                                         })
  2014.                                         ->end()
  2015.                                 ->end()
  2016.                                 ->integerNode('creationDate')->end()
  2017.                                 ->integerNode('modificationDate')->end()
  2018.                             ->end()
  2019.                         ->end()
  2020.                     ->end()
  2021.                 ->end()
  2022.             ->end()
  2023.         ->end();
  2024.     }
  2025.     /**
  2026.      * Add static routes specific extension config
  2027.      *
  2028.      * @param ArrayNodeDefinition $rootNode
  2029.      */
  2030.     private function addStaticroutesNode(ArrayNodeDefinition $rootNode)
  2031.     {
  2032.         $rootNode
  2033.         ->children()
  2034.             ->arrayNode('staticroutes')
  2035.                 ->ignoreExtraKeys()
  2036.                 ->addDefaultsIfNotSet()
  2037.                 ->children()
  2038.                     ->arrayNode('definitions')
  2039.                     ->normalizeKeys(false)
  2040.                         ->prototype('array')
  2041.                             ->children()
  2042.                                 ->scalarNode('name')->end()
  2043.                                 ->scalarNode('pattern')->end()
  2044.                                 ->scalarNode('reverse')->end()
  2045.                                 ->scalarNode('controller')->end()
  2046.                                 ->scalarNode('variables')->end()
  2047.                                 ->scalarNode('defaults')->end()
  2048.                                 ->arrayNode('siteId')
  2049.                                     ->integerPrototype()->end()
  2050.                                 ->end()
  2051.                                 ->arrayNode('methods')
  2052.                                     ->scalarPrototype()->end()
  2053.                                 ->end()
  2054.                                 ->integerNode('priority')->end()
  2055.                                 ->integerNode('creationDate')->end()
  2056.                                 ->integerNode('modificationDate')->end()
  2057.                             ->end()
  2058.                         ->end()
  2059.                     ->end()
  2060.                 ->end()
  2061.             ->end()
  2062.         ->end();
  2063.     }
  2064.     /**
  2065.      * Add perspectives specific extension config
  2066.      *
  2067.      * @param ArrayNodeDefinition $rootNode
  2068.      */
  2069.     private function addPerspectivesNode(ArrayNodeDefinition $rootNode)
  2070.     {
  2071.         $rootNode
  2072.             ->children()
  2073.                 ->arrayNode('perspectives')
  2074.                     ->ignoreExtraKeys()
  2075.                     ->addDefaultsIfNotSet()
  2076.                     ->children()
  2077.                         ->arrayNode('definitions')
  2078.                         ->normalizeKeys(false)
  2079.                             ->prototype('array')
  2080.                                 ->children()
  2081.                                     ->scalarNode('iconCls')->end()
  2082.                                     ->scalarNode('icon')->end()
  2083.                                     ->variableNode('toolbar')->end()
  2084.                                     ->arrayNode('dashboards')
  2085.                                         ->children()
  2086.                                             ->variableNode('predefined')->end()
  2087.                                         ->end()
  2088.                                     ->end()
  2089.                                     ->arrayNode('elementTree')
  2090.                                         ->prototype('array')
  2091.                                             ->children()
  2092.                                                 ->scalarNode('type')->end()
  2093.                                                 ->scalarNode('position')->end()
  2094.                                                 ->scalarNode('name')->end()
  2095.                                                 ->booleanNode('expanded')->end()
  2096.                                                 ->scalarNode('hidden')->end()
  2097.                                                 ->integerNode('sort')->end()
  2098.                                                 ->scalarNode('id')->end()
  2099.                                                 ->variableNode('treeContextMenu')->end()
  2100.                                             ->end()
  2101.                                         ->end()
  2102.                                     ->end()
  2103.                                 ->end()
  2104.                             ->end()
  2105.                         ->end()
  2106.                     ->end()
  2107.                 ->end()
  2108.             ->end()
  2109.         ->end();
  2110.     }
  2111.     /**
  2112.      * Add custom views specific extension config
  2113.      *
  2114.      * @param ArrayNodeDefinition $rootNode
  2115.      */
  2116.     private function addCustomViewsNode(ArrayNodeDefinition $rootNode)
  2117.     {
  2118.         $rootNode
  2119.             ->children()
  2120.                 ->arrayNode('custom_views')
  2121.                     ->ignoreExtraKeys()
  2122.                     ->addDefaultsIfNotSet()
  2123.                     ->children()
  2124.                         ->arrayNode('definitions')
  2125.                         ->normalizeKeys(false)
  2126.                             ->prototype('array')
  2127.                             ->children()
  2128.                                 ->scalarNode('id')->end()
  2129.                                 ->scalarNode('treetype')->end()
  2130.                                 ->scalarNode('name')->end()
  2131.                                 ->scalarNode('condition')->end()
  2132.                                 ->scalarNode('icon')->end()
  2133.                                 ->scalarNode('rootfolder')->end()
  2134.                                 ->scalarNode('showroot')->end()
  2135.                                 ->variableNode('classes')->end()
  2136.                                 ->scalarNode('position')->end()
  2137.                                 ->scalarNode('sort')->end()
  2138.                                 ->booleanNode('expanded')->end()
  2139.                                 ->scalarNode('having')->end()
  2140.                                 ->scalarNode('where')->end()
  2141.                                 ->variableNode('treeContextMenu')->end()
  2142.                                 ->arrayNode('joins')
  2143.                                     ->protoType('array')
  2144.                                         ->children()
  2145.                                             ->scalarNode('type')->end()
  2146.                                             ->scalarNode('condition')->end()
  2147.                                             ->variableNode('name')->end()
  2148.                                             ->variableNode('columns')->end()
  2149.                                         ->end()
  2150.                                     ->end()
  2151.                                 ->end()
  2152.                             ->end()
  2153.                         ->end()
  2154.                     ->end()
  2155.                 ->end()
  2156.             ->end();
  2157.     }
  2158. }