Completed
Push — 7.5 ( f79096...9972f5 )
by
unknown
27:34
created

Configuration::addUrlWildcardsSection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the Configuration class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Bundle\EzPublishCoreBundle\DependencyInjection;
10
11
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface;
12
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAccessAware\Configuration as SiteAccessConfiguration;
13
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\Suggestion\Collector\SuggestionCollectorInterface;
14
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
15
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
17
18
class Configuration extends SiteAccessConfiguration
19
{
20
    const CUSTOM_TAG_ATTRIBUTE_TYPES = ['number', 'string', 'boolean', 'choice'];
21
22
    /**
23
     * @var \eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface
24
     */
25
    private $mainConfigParser;
26
27
    /**
28
     * @var Configuration\Suggestion\Collector\SuggestionCollectorInterface
29
     */
30
    private $suggestionCollector;
31
32
    /**
33
     * @var \eZ\Bundle\EzPublishCoreBundle\SiteAccess\SiteAccessConfigurationFilter[]
34
     */
35
    private $siteAccessConfigurationFilters;
36
37
    public function __construct(ParserInterface $mainConfigParser, SuggestionCollectorInterface $suggestionCollector)
38
    {
39
        $this->suggestionCollector = $suggestionCollector;
40
        $this->mainConfigParser = $mainConfigParser;
41
    }
42
43
    public function setSiteAccessConfigurationFilters(array $filters)
44
    {
45
        $this->siteAccessConfigurationFilters = $filters;
46
    }
47
48
    /**
49
     * Generates the configuration tree builder.
50
     *
51
     * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
52
     */
53
    public function getConfigTreeBuilder()
54
    {
55
        $treeBuilder = new TreeBuilder();
56
        $rootNode = $treeBuilder->root('ezpublish');
57
58
        $this->addRepositoriesSection($rootNode);
59
        $this->addSiteaccessSection($rootNode);
60
        $this->addImageMagickSection($rootNode);
61
        $this->addHttpCacheSection($rootNode);
62
        $this->addPageSection($rootNode);
63
        $this->addRouterSection($rootNode);
64
        $this->addRichTextSection($rootNode);
65
        $this->addUrlAliasSection($rootNode);
66
        $this->addImagePlaceholderSection($rootNode);
67
        $this->addUrlWildcardsSection($rootNode);
68
69
        // Delegate SiteAccess config to configuration parsers
70
        $this->mainConfigParser->addSemanticConfig($this->generateScopeBaseNode($rootNode));
71
72
        return $treeBuilder;
73
    }
74
75
    public function addRepositoriesSection(ArrayNodeDefinition $rootNode)
76
    {
77
        $rootNode
78
            ->children()
79
                ->arrayNode('repositories')
80
                    ->info('Content repositories configuration')
81
                    ->example(
82
                        array(
83
                            'main' => array(
84
                                'storage' => array(
85
                                    'engine' => 'legacy',
86
                                    'connection' => 'my_doctrine_connection_name',
87
                                ),
88
                            ),
89
                        )
90
                    )
91
                    ->useAttributeAsKey('alias')
92
                    ->prototype('array')
93
                        ->beforeNormalization()
94
                            ->always(
95
                                // Handling deprecated structure by mapping it to new one
96
                                function ($v) {
97
                                    if (isset($v['storage'])) {
98
                                        return $v;
99
                                    }
100
101
                                    if (isset($v['engine'])) {
102
                                        $v['storage']['engine'] = $v['engine'];
103
                                        unset($v['engine']);
104
                                    }
105
106
                                    if (isset($v['connection'])) {
107
                                        $v['storage']['connection'] = $v['connection'];
108
                                        unset($v['connection']);
109
                                    }
110
111
                                    if (isset($v['config'])) {
112
                                        $v['storage']['config'] = $v['config'];
113
                                        unset($v['config']);
114
                                    }
115
116
                                    return $v;
117
                                }
118
                            )
119
                        ->end()
120
                        ->beforeNormalization()
121
                            ->always(
122
                                // Setting default values
123
                                function ($v) {
124
                                    if ($v === null) {
125
                                        $v = array();
126
                                    }
127
128
                                    if (!isset($v['storage'])) {
129
                                        $v['storage'] = array();
130
                                    }
131
132
                                    if (!isset($v['search'])) {
133
                                        $v['search'] = array();
134
                                    }
135
136
                                    if (!isset($v['fields_groups']['list'])) {
137
                                        $v['fields_groups']['list'] = [];
138
                                    }
139
140
                                    if (!isset($v['options'])) {
141
                                        $v['options'] = [];
142
                                    }
143
144
                                    return $v;
145
                                }
146
                            )
147
                        ->end()
148
                        ->children()
149
                            ->arrayNode('storage')
150
                                ->children()
151
                                    ->scalarNode('engine')
152
                                        ->defaultValue('%ezpublish.api.storage_engine.default%')
153
                                        ->info('The storage engine to use')
154
                                    ->end()
155
                                    ->scalarNode('connection')
156
                                        ->defaultNull()
157
                                        ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.')
158
                                    ->end()
159
                                    ->arrayNode('config')
160
                                        ->info('Arbitrary configuration options, supported by your storage engine')
161
                                        ->useAttributeAsKey('key')
162
                                        ->prototype('variable')->end()
163
                                    ->end()
164
                                ->end()
165
                            ->end()
166
                            ->arrayNode('search')
167
                                ->children()
168
                                    ->scalarNode('engine')
169
                                        ->defaultValue('%ezpublish.api.search_engine.default%')
170
                                        ->info('The search engine to use')
171
                                    ->end()
172
                                    ->scalarNode('connection')
173
                                        ->defaultNull()
174
                                        ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.')
175
                                    ->end()
176
                                    ->arrayNode('config')
177
                                        ->info('Arbitrary configuration options, supported by your search engine')
178
                                        ->useAttributeAsKey('key')
179
                                        ->prototype('variable')->end()
180
                                    ->end()
181
                                ->end()
182
                            ->end()
183
                            ->arrayNode('fields_groups')
184
                                ->info('Definitions of fields groups.')
185
                                ->children()
186
                                    ->arrayNode('list')->prototype('scalar')->end()->end()
187
                                    ->scalarNode('default')->defaultValue('%ezsettings.default.content.field_groups.default%')->end()
188
                                ->end()
189
                            ->end()
190
                            ->arrayNode('options')
191
                                ->info('Options for repository.')
192
                                ->children()
193
                                    ->scalarNode('default_version_archive_limit')
194
                                        ->defaultValue(5)
195
                                        ->info('Default version archive limit (0-50), only enforced on publish, not on un-publish.')
196
                                    ->end()
197
                                ->end()
198
                            ->end()
199
                        ->end()
200
                    ->end()
201
                ->end()
202
            ->end();
203
    }
204
205
    public function addSiteaccessSection(ArrayNodeDefinition $rootNode)
206
    {
207
        $rootNode
208
            ->children()
209
                ->arrayNode('siteaccess')
210
                    ->info('SiteAccess configuration')
211
                    ->children()
212
                        ->arrayNode('list')
213
                            ->info('Available SiteAccess list')
214
                            ->example(array('ezdemo_site', 'ezdemo_site_admin'))
215
                            ->isRequired()
216
                            ->requiresAtLeastOneElement()
217
                            ->prototype('scalar')->end()
218
                        ->end()
219
                        ->arrayNode('groups')
220
                            ->useAttributeAsKey('key')
221
                            ->info('SiteAccess groups. Useful to share settings between Siteaccess')
222
                            ->example(array('ezdemo_group' => array('ezdemo_site', 'ezdemo_site_admin')))
223
                            ->prototype('array')
224
                                ->requiresAtLeastOneElement()
225
                                ->prototype('scalar')->end()
226
                            ->end()
227
                        ->end()
228
                        ->scalarNode('default_siteaccess')->isRequired()->info('Name of the default siteaccess')->end()
229
                        ->arrayNode('match')
230
                            ->info('Siteaccess match configuration. First key is the matcher class, value is passed to the matcher. Key can be a service identifier (prepended by "@"), or a FQ class name (prepended by "\\")')
231
                            ->example(
232
                                array(
233
                                    'Map\\URI' => array(
234
                                        'foo' => 'ezdemo_site',
235
                                        'ezdemo_site' => 'ezdemo_site',
236
                                        'ezdemo_site_admin' => 'ezdemo_site_admin',
237
                                    ),
238
                                    'Map\\Host' => array(
239
                                        'ezpublish.dev' => 'ezdemo_site',
240
                                        'admin.ezpublish.dev' => 'ezdemo_site_admin',
241
                                    ),
242
                                    '\\My\\Custom\\Matcher' => array(
243
                                        'some' => 'configuration',
244
                                    ),
245
                                    '@my.custom.matcher' => array(
246
                                        'some' => 'other_configuration',
247
                                    ),
248
                                )
249
                            )
250
                            ->isRequired()
251
                            ->useAttributeAsKey('key')
252
                            ->normalizeKeys(false)
253
                            ->prototype('array')
254
                                ->useAttributeAsKey('key')
255
                                ->beforeNormalization()
256
                                    ->always(
257
                                        function ($v) {
258
                                            // Value passed to the matcher should always be an array.
259
                                            // If value is not an array, we transform it to a hash, with 'value' as key.
260
                                            if (!is_array($v)) {
261
                                                return array('value' => $v);
262
                                            }
263
264
                                            // If passed value is a numerically indexed array, we must convert it into a hash.
265
                                            // See https://jira.ez.no/browse/EZP-21876
266
                                            if (array_keys($v) === range(0, count($v) - 1)) {
267
                                                $final = array();
268
                                                foreach ($v as $i => $val) {
269
                                                    $final["i$i"] = $val;
270
                                                }
271
272
                                                return $final;
273
                                            }
274
275
                                            return $v;
276
                                        }
277
                                    )
278
                                ->end()
279
                                ->normalizeKeys(false)
280
                                ->prototype('variable')->end()
281
                            ->end()
282
                        ->end()
283
                    ->end()
284
                    ->beforeNormalization()
285
                        ->always()->then(function ($v) {
286
                            if (isset($this->siteAccessConfigurationFilters)) {
287
                                foreach ($this->siteAccessConfigurationFilters as $filter) {
288
                                    $v = $filter->filter($v);
289
                                }
290
                            }
291
292
                            return $v;
293
                        })
294
                    ->end()
295
                ->end()
296
                ->arrayNode('locale_conversion')
297
                    ->info('Locale conversion map between eZ Publish format (i.e. fre-FR) to POSIX (i.e. fr_FR). The key is the eZ Publish locale. Check locale.yml in EzPublishCoreBundle to see natively supported locales.')
298
                    ->example(array('fre-FR' => 'fr_FR'))
299
                    ->useAttributeAsKey('key')
300
                    ->normalizeKeys(false)
301
                    ->prototype('scalar')->end()
302
                ->end()
303
            ->end();
304
    }
305
306
    private function addImageMagickSection(ArrayNodeDefinition $rootNode)
307
    {
308
        $filtersInfo =
309
<<<EOT
310
DEPRECATED.
311
This is only used for legacy injection.
312
You may use imagick/gmagick liip_imagine bundle drivers.
313
314
Hash of filters to be used for your image variations config.
315
#   Key is the filter name, value is an argument passed to "convert" binary.
316
#   You can use numbered placeholders (aka input variables) that will be replaced by defined parameters in your image variations config
317
EOT;
318
319
        $rootNode
320
            ->children()
321
                ->arrayNode('imagemagick')
322
                    ->info('ImageMagick configuration')
323
                    ->children()
324
                        ->booleanNode('enabled')->defaultTrue()->end()
325
                        ->scalarNode('path')
326
                            ->info('Absolute path of ImageMagick / GraphicsMagick "convert" binary.')
327
                            ->beforeNormalization()
328
                                ->ifTrue(
329
                                    function ($v) {
330
                                        $basename = basename($v);
331
                                        // If there is a space in the basename, just drop it and everything after it.
332
                                        if (($wsPos = strpos($basename, ' ')) !== false) {
333
                                            $basename = substr($basename, 0, $wsPos);
334
                                        }
335
336
                                        return !is_executable(dirname($v) . DIRECTORY_SEPARATOR . $basename);
337
                                    }
338
                                )
339
                                ->thenInvalid('Please provide full path to ImageMagick / GraphicsMagick  "convert" binary. Please also check that it is executable.')
340
                            ->end()
341
                        ->end()
342
                        ->arrayNode('filters')
343
                            ->info($filtersInfo)
344
                            ->example(array('geometry/scaledownonly' => '"-geometry {1}x{2}>"'))
345
                            ->prototype('scalar')->end()
346
                        ->end()
347
                    ->end()
348
                ->end()
349
            ->end();
350
    }
351
352
    private function addHttpCacheSection(ArrayNodeDefinition $rootNode)
353
    {
354
        $purgeTypeInfo = <<<EOT
355
Http cache purge type.
356
357
Cache purge for content/locations is triggered when needed (e.g. on publish) and will result in one or several Http PURGE requests.
358
Can be "local", "http" or a valid symfony service id:
359
- If "local" is used, an Http PURGE request will be emulated when needed (e.g. when using Symfony internal reverse proxy).
360
- If "http" is used, a full HTTP PURGE/BAN is done to a real reverse proxy (Varnish, ..) depending on your config
361
- If custom symfony service id is used, then check documentation on that service for how it behaves and how you need to configure your system for it.
362
363
If ezplatform-http-cache package is enabled (default as of 1.12 and up), then go to documentation on this package for further
364
info on how it supports multiple response tagging, purges and allow plugins for custom purge types.
365
366
If that is not enabled, then the (deprecated as of 1.8) default BAN based system will be used instead.
367
Where ressponses can be tagged by a single  X-Location-Id header, and for purges a single Http BAN request will be sent,
368
where X-Location-Id header consists of a Regexp containing locationIds to ban.
369
  BAN Examples:
370
   - (123|456|789) => Purge locations #123, #456, #789.
371
   - .* => Purge all locations.
372
EOT;
373
374
        $rootNode
375
            ->children()
376
                ->arrayNode('http_cache')
377
                    ->children()
378
                        ->scalarNode('purge_type')
379
                            ->info($purgeTypeInfo)
380
                            ->defaultValue('local')
381
                            ->beforeNormalization()
382
                                ->ifTrue(
383
                                    function ($v) {
384
                                        $http = array('multiple_http' => true, 'single_http' => true);
385
386
                                        return isset($http[$v]);
387
                                    }
388
                                )
389
                                ->then(
390
                                    function () {
391
                                        return 'http';
392
                                    }
393
                                )
394
                            ->end()
395
                        ->end()
396
                        ->scalarNode('timeout')->info('DEPRECATED')->end()
397
                    ->end()
398
                ->end()
399
            ->end();
400
    }
401
402
    private function addPageSection(ArrayNodeDefinition $rootNode)
403
    {
404
        $pageInfo = <<<EOT
405
List of globally registered layouts and blocks used by the Page fieldtype
406
EOT;
407
408
        $rootNode
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method children() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
409
            ->children()
410
                ->arrayNode('ezpage')
411
                    ->info($pageInfo)
412
                    ->children()
413
                        ->arrayNode('layouts')
414
                            ->info('List of registered layouts, the key is the identifier of the layout')
415
                            ->useAttributeAsKey('key')
416
                            ->normalizeKeys(false)
417
                            ->prototype('array')
418
                                ->children()
419
                                    ->scalarNode('name')->isRequired()->info('Name of the layout')->end()
420
                                    ->scalarNode('template')->isRequired()->info('Template to use to render this layout')->end()
421
                                ->end()
422
                            ->end()
423
                        ->end()
424
                        ->arrayNode('blocks')
425
                            ->info('List of registered blocks, the key is the identifier of the block')
426
                            ->useAttributeAsKey('key')
427
                            ->normalizeKeys(false)
428
                            ->prototype('array')
429
                                ->children()
430
                                    ->scalarNode('name')->isRequired()->info('Name of the block')->end()
431
                                ->end()
432
                            ->end()
433
                        ->end()
434
                        ->arrayNode('enabledBlocks')
435
                            ->prototype('scalar')
436
                            ->end()
437
                            ->info('List of enabled blocks by default')
438
                        ->end()
439
                        ->arrayNode('enabledLayouts')
440
                            ->prototype('scalar')
441
                            ->end()
442
                            ->info('List of enabled layouts by default')
443
                        ->end()
444
                    ->end()
445
                ->end()
446
            ->end();
447
    }
448
449
    private function addRouterSection(ArrayNodeDefinition $rootNode)
450
    {
451
        $nonSAAwareInfo = <<<EOT
452
Route names that are not supposed to be SiteAccess aware, i.e. Routes pointing to asset generation (like assetic).
453
Note that you can just specify a prefix to match a selection of routes.
454
e.g. "_assetic_" will match "_assetic_*"
455
Defaults to ['_assetic_', '_wdt', '_profiler', '_configurator_']
456
EOT;
457
        $rootNode
458
            ->children()
459
                ->arrayNode('router')
460
                    ->children()
461
                        ->arrayNode('default_router')
462
                            ->children()
463
                                ->arrayNode('non_siteaccess_aware_routes')
464
                                    ->prototype('scalar')->end()
465
                                    ->info($nonSAAwareInfo)
466
                                    ->example(array('my_route_name', 'some_prefix_'))
467
                                ->end()
468
                            ->end()
469
                        ->end()
470
                    ->end()
471
                    ->info('Router related settings')
472
                ->end()
473
            ->end();
474
    }
475
476
    /**
477
     * Define global Semantic Configuration for RichText.
478
     *
479
     * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $rootNode
480
     */
481
    private function addRichTextSection(ArrayNodeDefinition $rootNode)
482
    {
483
        $ezRichTextNode = $rootNode->children()->arrayNode('ezrichtext')->children();
484
        $this->addCustomTagsSection($ezRichTextNode);
485
        $this->addCustomStylesSection($ezRichTextNode);
486
        $ezRichTextNode->end()->end()->end();
487
    }
488
489
    /**
490
     * Define RichText Custom Tags Semantic Configuration.
491
     *
492
     * The configuration is available at:
493
     * <code>
494
     * ezpublish:
495
     *     ezrichtext:
496
     *         custom_tags:
497
     * </code>
498
     *
499
     * @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $ezRichTextNode
500
     *
501
     * @return \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
502
     */
503
    private function addCustomTagsSection(NodeBuilder $ezRichTextNode)
504
    {
505
        return $ezRichTextNode
506
                ->arrayNode('custom_tags')
507
                // workaround: take into account Custom Tag names when merging configs
508
                ->useAttributeAsKey('tag')
509
                ->arrayPrototype()
510
                    ->children()
511
                        ->scalarNode('template')
512
                            ->isRequired()
513
                        ->end()
514
                        ->scalarNode('icon')
515
                            ->defaultNull()
516
                        ->end()
517
                        ->arrayNode('attributes')
518
                            ->useAttributeAsKey('attribute')
519
                            ->isRequired()
520
                            ->arrayPrototype()
521
                                ->beforeNormalization()
522
                                    ->always(
523
                                        function ($v) {
524
                                            // Workaround: set empty value to be able to unset it later on (see validation for "choices")
525
                                            if (!isset($v['choices'])) {
526
                                                $v['choices'] = [];
527
                                            }
528
529
                                            return $v;
530
                                        }
531
                                    )
532
                                ->end()
533
                                ->validate()
534
                                    ->ifTrue(
535
                                        function ($v) {
536
                                            return $v['type'] === 'choice' && !empty($v['required']) && empty($v['choices']);
537
                                        }
538
                                    )
539
                                    ->thenInvalid('List of choices for required choice type attribute has to be non-empty')
540
                                ->end()
541
                                ->validate()
542
                                    ->ifTrue(
543
                                        function ($v) {
544
                                            return !empty($v['choices']) && $v['type'] !== 'choice';
545
                                        }
546
                                    )
547
                                    ->thenInvalid('List of choices is supported by choices type only.')
548
                                ->end()
549
                                ->children()
550
                                    ->enumNode('type')
551
                                        ->isRequired()
552
                                        ->values(static::CUSTOM_TAG_ATTRIBUTE_TYPES)
553
                                    ->end()
554
                                    ->booleanNode('required')
555
                                        ->defaultFalse()
556
                                    ->end()
557
                                    ->scalarNode('default_value')
558
                                        ->defaultNull()
559
                                    ->end()
560
                                    ->arrayNode('choices')
561
                                        ->scalarPrototype()->end()
562
                                        ->performNoDeepMerging()
563
                                        ->validate()
564
                                            ->ifEmpty()->thenUnset()
565
                                        ->end()
566
                                    ->end()
567
                                ->end()
568
                            ->end()
569
                        ->end()
570
                    ->end()
571
                ->end()
572
            ->end()
573
        ;
574
    }
575
576
    /**
577
     * Define RichText Custom Styles Semantic Configuration.
578
     *
579
     * The configuration is available at:
580
     * <code>
581
     * ezpublish:
582
     *     ezrichtext:
583
     *         custom_styles:
584
     * </code>
585
     *
586
     * @param \Symfony\Component\Config\Definition\Builder\NodeBuilder $ezRichTextNode
587
     *
588
     * @return \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
589
     */
590
    private function addCustomStylesSection(NodeBuilder $ezRichTextNode)
591
    {
592
        return $ezRichTextNode
593
                ->arrayNode('custom_styles')
594
                // workaround: take into account Custom Styles names when merging configs
595
                ->useAttributeAsKey('style')
596
                ->arrayPrototype()
597
                    ->children()
598
                        ->scalarNode('template')
599
                            ->defaultNull()
600
                        ->end()
601
                        ->scalarNode('inline')
602
                            ->defaultFalse()
603
                        ->end()
604
                    ->end()
605
                ->end()
606
            ->end()
607
        ;
608
    }
609
610
    /**
611
     * Defines configuration the images placeholder generation.
612
     *
613
     * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $rootNode
614
     */
615
    private function addImagePlaceholderSection(ArrayNodeDefinition $rootNode)
616
    {
617
        $rootNode
618
            ->children()
619
                ->arrayNode('image_placeholder')
620
                    ->info('Configuration for strategy of replacing missing images')
621
                    ->useAttributeAsKey('name')
622
                    ->arrayPrototype()
623
                        ->children()
624
                            ->scalarNode('provider')
625
                            ->end()
626
                            ->variableNode('options')
627
                                ->defaultValue([])
628
                            ->end()
629
                        ->end()
630
                    ->end()
631
                ->end()
632
            ->end();
633
    }
634
635
    /**
636
     * Define Url Alias Slug converter Semantic Configuration.
637
     *
638
     * The configuration is available at:
639
     * <code>
640
     * ezpublish:
641
     *     url_alias:
642
     *         slug_converter:
643
     *             transformation: name_of_transformation_group_to_use
644
     *             separator:  name_of_separator_to_use
645
     *             transformation_groups:
646
     *                 transformation_group_name: name of existing or new transformation group
647
     *                     commands : [] array of commands which will be added to group
648
     *                     cleanup_method: name_of_cleanup_method
649
     * </code>
650
     *
651
     * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $rootNode
652
     *
653
     * @return \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
654
     */
655
    private function addUrlAliasSection(ArrayNodeDefinition $rootNode)
656
    {
657
        return $rootNode
658
            ->children()
659
                ->arrayNode('url_alias')
660
                    ->children()
661
                        ->arrayNode('slug_converter')
662
                            ->children()
663
                                ->scalarNode('transformation')->end()
664
                                ->scalarNode('separator')->end()
665
                                ->arrayNode('transformation_groups')
666
                                    ->arrayPrototype()
667
                                        ->children()
668
                                            ->arrayNode('commands')
669
                                                ->scalarPrototype()->end()
670
                                            ->end()
671
                                            ->scalarNode('cleanup_method')->end()
672
                                        ->end()
673
                                    ->end()
674
                                ->end()
675
                            ->end()
676
                        ->end()
677
                    ->end()
678
                ->end()
679
            ->end();
680
    }
681
682
    /**
683
     * Defines configuration for Url Wildcards.
684
     *
685
     * The configuration is available at:
686
     * <code>
687
     * ezpublish:
688
     *     url_wildcards:
689
     *         enabled: true
690
     * </code>
691
     *
692
     * @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $rootNode
693
     *
694
     * @return \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition
695
     */
696
    private function addUrlWildcardsSection($rootNode): ArrayNodeDefinition
697
    {
698
        return $rootNode
699
            ->children()
700
                ->arrayNode('url_wildcards')
701
                    ->children()
702
                        ->booleanNode('enabled')
703
                            ->info('Enable UrlWildcards support')
704
                            ->defaultFalse()
705
                        ->end()
706
                    ->end()
707
                ->end()
708
            ->end();
709
    }
710
}
711