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

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