Completed
Push — asset_dump_sf_env ( 7179db...758bb0 )
by André
16:06
created

Configuration::addRepositoriesSection()   D

Complexity

Conditions 10
Paths 1

Size

Total Lines 120
Code Lines 90

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 120
rs 4.8196
cc 10
eloc 90
nc 1
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
 * @version //autogentag//
10
 */
11
namespace eZ\Bundle\EzPublishCoreBundle\DependencyInjection;
12
13
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface;
14
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAccessAware\Configuration as SiteAccessConfiguration;
15
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\Suggestion\Collector\SuggestionCollectorInterface;
16
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
17
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
18
19
class Configuration extends SiteAccessConfiguration
20
{
21
    /**
22
     * @var \eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface
23
     */
24
    private $mainConfigParser;
25
26
    /**
27
     * @var Configuration\Suggestion\Collector\SuggestionCollectorInterface
28
     */
29
    private $suggestionCollector;
30
31
    public function __construct(ParserInterface $mainConfigParser, SuggestionCollectorInterface $suggestionCollector)
32
    {
33
        $this->suggestionCollector = $suggestionCollector;
34
        $this->mainConfigParser = $mainConfigParser;
35
    }
36
37
    /**
38
     * Generates the configuration tree builder.
39
     *
40
     * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
41
     */
42
    public function getConfigTreeBuilder()
43
    {
44
        $treeBuilder = new TreeBuilder();
45
        $rootNode = $treeBuilder->root('ezpublish');
46
47
        $this->addRepositoriesSection($rootNode);
48
        $this->addSiteaccessSection($rootNode);
49
        $this->addImageMagickSection($rootNode);
50
        $this->addHttpCacheSection($rootNode);
51
        $this->addPageSection($rootNode);
52
        $this->addRouterSection($rootNode);
53
54
        // Delegate SiteAccess config to configuration parsers
55
        $this->mainConfigParser->addSemanticConfig($this->generateScopeBaseNode($rootNode));
56
57
        return $treeBuilder;
58
    }
59
60
    public function addRepositoriesSection(ArrayNodeDefinition $rootNode)
61
    {
62
        $rootNode
63
            ->children()
64
                ->arrayNode('repositories')
65
                    ->info('Content repositories configuration')
66
                    ->example(
67
                        array(
68
                            'main' => array(
69
                                'storage' => array(
70
                                    'engine' => 'legacy',
71
                                    'connection' => 'my_doctrine_connection_name',
72
                                ),
73
                            ),
74
                        )
75
                    )
76
                    ->useAttributeAsKey('alias')
77
                    ->prototype('array')
78
                        ->beforeNormalization()
79
                            ->always(
80
                                // Handling deprecated structure by mapping it to new one
81
                                function ($v) {
82
                                    if (isset($v['storage'])) {
83
                                        return $v;
84
                                    }
85
86
                                    if (isset($v['engine'])) {
87
                                        $v['storage']['engine'] = $v['engine'];
88
                                        unset($v['engine']);
89
                                    }
90
91
                                    if (isset($v['connection'])) {
92
                                        $v['storage']['connection'] = $v['connection'];
93
                                        unset($v['connection']);
94
                                    }
95
96
                                    if (isset($v['config'])) {
97
                                        $v['storage']['config'] = $v['config'];
98
                                        unset($v['config']);
99
                                    }
100
101
                                    return $v;
102
                                }
103
                            )
104
                        ->end()
105
                        ->beforeNormalization()
106
                            ->always(
107
                                // Setting default values
108
                                function ($v) {
109
                                    if ($v === null) {
110
                                        $v = array();
111
                                    }
112
113
                                    if (!isset($v['storage'])) {
114
                                        $v['storage'] = array();
115
                                    }
116
117
                                    if (!isset($v['search'])) {
118
                                        $v['search'] = array();
119
                                    }
120
121
                                    if (!isset($v['fields_groups']['list'])) {
122
                                        $v['fields_groups']['list'] = ['content'];
123
                                    }
124
125
                                    if (!isset($v['fields_groups']['default'])) {
126
                                        $v['fields_groups']['default'] = 'content';
127
                                    }
128
129
                                    return $v;
130
                                }
131
                            )
132
                        ->end()
133
                        ->children()
134
                            ->arrayNode('storage')
135
                                ->children()
136
                                    ->scalarNode('engine')
137
                                        ->defaultValue('%ezpublish.api.storage_engine.default%')
138
                                        ->info('The storage engine to use')
139
                                    ->end()
140
                                    ->scalarNode('connection')
141
                                        ->defaultNull()
142
                                        ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.')
143
                                    ->end()
144
                                    ->arrayNode('config')
145
                                        ->info('Arbitrary configuration options, supported by your storage engine')
146
                                        ->useAttributeAsKey('key')
147
                                        ->prototype('variable')->end()
148
                                    ->end()
149
                                ->end()
150
                            ->end()
151
                            ->arrayNode('search')
152
                                ->children()
153
                                    ->scalarNode('engine')
154
                                        ->defaultValue('%ezpublish.api.search_engine.default%')
155
                                        ->info('The search engine to use')
156
                                    ->end()
157
                                    ->scalarNode('connection')
158
                                        ->defaultNull()
159
                                        ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.')
160
                                    ->end()
161
                                    ->arrayNode('config')
162
                                        ->info('Arbitrary configuration options, supported by your search engine')
163
                                        ->useAttributeAsKey('key')
164
                                        ->prototype('variable')->end()
165
                                    ->end()
166
                                ->end()
167
                            ->end()
168
                            ->arrayNode('fields_groups')
169
                                ->info('Definitions of fields groups.')
170
                                ->children()
171
                                    ->arrayNode('list')->prototype('scalar')->end()->end()
172
                                    ->scalarNode('default')->defaultValue('content')->end()
173
                                ->end()
174
                            ->end()
175
                        ->end()
176
                    ->end()
177
                ->end()
178
            ->end();
179
    }
180
181
    public function addSiteaccessSection(ArrayNodeDefinition $rootNode)
182
    {
183
        $rootNode
184
            ->children()
185
                ->arrayNode('siteaccess')
186
                    ->info('SiteAccess configuration')
187
                    ->children()
188
                        ->arrayNode('list')
189
                            ->info('Available SiteAccess list')
190
                            ->example(array('ezdemo_site', 'ezdemo_site_admin'))
191
                            ->isRequired()
192
                            ->requiresAtLeastOneElement()
193
                            ->prototype('scalar')->end()
194
                        ->end()
195
                        ->arrayNode('groups')
196
                            ->useAttributeAsKey('key')
197
                            ->info('SiteAccess groups. Useful to share settings between Siteaccess')
198
                            ->example(array('ezdemo_group' => array('ezdemo_site', 'ezdemo_site_admin')))
199
                            ->prototype('array')
200
                                ->requiresAtLeastOneElement()
201
                                ->prototype('scalar')->end()
202
                            ->end()
203
                        ->end()
204
                        ->scalarNode('default_siteaccess')->isRequired()->info('Name of the default siteaccess')->end()
205
                        ->arrayNode('match')
206
                            ->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 "\\")')
207
                            ->example(
208
                                array(
209
                                    'Map\\URI' => array(
210
                                        'foo' => 'ezdemo_site',
211
                                        'ezdemo_site' => 'ezdemo_site',
212
                                        'ezdemo_site_admin' => 'ezdemo_site_admin',
213
                                    ),
214
                                    'Map\\Host' => array(
215
                                        'ezpublish.dev' => 'ezdemo_site',
216
                                        'admin.ezpublish.dev' => 'ezdemo_site_admin',
217
                                    ),
218
                                    '\\My\\Custom\\Matcher' => array(
219
                                        'some' => 'configuration',
220
                                    ),
221
                                    '@my.custom.matcher' => array(
222
                                        'some' => 'other_configuration',
223
                                    ),
224
                                )
225
                            )
226
                            ->isRequired()
227
                            ->useAttributeAsKey('key')
228
                            ->normalizeKeys(false)
229
                            ->prototype('array')
230
                                ->useAttributeAsKey('key')
231
                                ->beforeNormalization()
232
                                    ->always(
233
                                        function ($v) {
234
                                            // Value passed to the matcher should always be an array.
235
                                            // If value is not an array, we transform it to a hash, with 'value' as key.
236
                                            if (!is_array($v)) {
237
                                                return array('value' => $v);
238
                                            }
239
240
                                            // If passed value is a numerically indexed array, we must convert it into a hash.
241
                                            // See https://jira.ez.no/browse/EZP-21876
242
                                            if (array_keys($v) === range(0, count($v) - 1)) {
243
                                                $final = array();
244
                                                foreach ($v as $i => $val) {
245
                                                    $final["i$i"] = $val;
246
                                                }
247
248
                                                return $final;
249
                                            }
250
251
                                            return $v;
252
                                        }
253
                                    )
254
                                ->end()
255
                                ->normalizeKeys(false)
256
                                ->prototype('variable')->end()
257
                            ->end()
258
                        ->end()
259
                    ->end()
260
                ->end()
261
                ->arrayNode('locale_conversion')
262
                    ->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.')
263
                    ->example(array('fre-FR' => 'fr_FR'))
264
                    ->useAttributeAsKey('key')
265
                    ->normalizeKeys(false)
266
                    ->prototype('scalar')->end()
267
                ->end()
268
            ->end();
269
    }
270
271
    private function addImageMagickSection(ArrayNodeDefinition $rootNode)
272
    {
273
        $filtersInfo =
274
<<<EOT
275
DEPRECATED.
276
This is only used for legacy injection.
277
You may use imagick/gmagick liip_imagine bundle drivers.
278
279
Hash of filters to be used for your image variations config.
280
#   Key is the filter name, value is an argument passed to "convert" binary.
281
#   You can use numbered placeholders (aka input variables) that will be replaced by defined parameters in your image variations config
282
EOT;
283
284
        $rootNode
285
            ->children()
286
                ->arrayNode('imagemagick')
287
                    ->info('ImageMagick configuration')
288
                    ->children()
289
                        ->booleanNode('enabled')->defaultTrue()->end()
290
                        ->scalarNode('path')
291
                            ->info('Absolute path of ImageMagick / GraphicsMagick "convert" binary.')
292
                            ->beforeNormalization()
293
                                ->ifTrue(
294
                                    function ($v) {
295
                                        $basename = basename($v);
296
                                        // If there is a space in the basename, just drop it and everything after it.
297
                                        if (($wsPos = strpos($basename, ' ')) !== false) {
298
                                            $basename = substr($basename, 0, $wsPos);
299
                                        }
300
301
                                        return !is_executable(dirname($v) . DIRECTORY_SEPARATOR . $basename);
302
                                    }
303
                                )
304
                                ->thenInvalid('Please provide full path to ImageMagick / GraphicsMagick  "convert" binary. Please also check that it is executable.')
305
                            ->end()
306
                        ->end()
307
                        ->arrayNode('filters')
308
                            ->info($filtersInfo)
309
                            ->example(array('geometry/scaledownonly' => '"-geometry {1}x{2}>"'))
310
                            ->prototype('scalar')->end()
311
                        ->end()
312
                    ->end()
313
                ->end()
314
            ->end();
315
    }
316
317
    private function addHttpCacheSection(ArrayNodeDefinition $rootNode)
318
    {
319
        $purgeTypeInfo = <<<EOT
320
Http cache purge type.
321
322
Cache purge for content/locations is triggered when needed (e.g. on publish) and will result in one or several Http PURGE requests.
323
Can be "local" or "http" or a valid service ID:
324
- If "local" is used, an Http PURGE request will be emulated when needed (e.g. when using Symfony internal reverse proxy).
325
- If "http" is used, only one Http BAN request will be sent, with X-Location-Id header containing locationIds to ban.
326
  X-Location-Id consists in a Regexp containing locationIds to ban.
327
  Examples:
328
   - (123|456|789) => Purge locations #123, #456, #789.
329
   - .* => Purge all locations.
330
- If a serviceId is provided, it must be defined in the ServiceContainer and must implement eZ\Publish\Core\MVC\Symfony\Cache\PurgeClientInterface.
331
EOT;
332
333
        $rootNode
334
            ->children()
335
                ->arrayNode('http_cache')
336
                    ->children()
337
                        ->scalarNode('purge_type')
338
                            ->info($purgeTypeInfo)
339
                            ->defaultValue('local')
340
                            ->beforeNormalization()
341
                                ->ifTrue(
342
                                    function ($v) {
343
                                        $http = array('multiple_http' => true, 'single_http' => true);
344
345
                                        return isset($http[$v]);
346
                                    }
347
                                )
348
                                ->then(
349
                                    function () {
350
                                        return 'http';
351
                                    }
352
                                )
353
                            ->end()
354
                        ->end()
355
                        ->scalarNode('timeout')->info('DEPRECATED')->end()
356
                    ->end()
357
                ->end()
358
            ->end();
359
    }
360
361
    private function addPageSection(ArrayNodeDefinition $rootNode)
362
    {
363
        $pageInfo = <<<EOT
364
List of globally registered layouts and blocks used by the Page fieldtype
365
EOT;
366
367
        $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...
368
            ->children()
369
                ->arrayNode('ezpage')
370
                    ->info($pageInfo)
371
                    ->children()
372
                        ->arrayNode('layouts')
373
                            ->info('List of registered layouts, the key is the identifier of the layout')
374
                            ->useAttributeAsKey('key')
375
                            ->normalizeKeys(false)
376
                            ->prototype('array')
377
                                ->children()
378
                                    ->scalarNode('name')->isRequired()->info('Name of the layout')->end()
379
                                    ->scalarNode('template')->isRequired()->info('Template to use to render this layout')->end()
380
                                ->end()
381
                            ->end()
382
                        ->end()
383
                        ->arrayNode('blocks')
384
                            ->info('List of registered blocks, the key is the identifier of the block')
385
                            ->useAttributeAsKey('key')
386
                            ->normalizeKeys(false)
387
                            ->prototype('array')
388
                                ->children()
389
                                    ->scalarNode('name')->isRequired()->info('Name of the block')->end()
390
                                ->end()
391
                            ->end()
392
                        ->end()
393
                        ->arrayNode('enabledBlocks')
394
                            ->prototype('scalar')
395
                            ->end()
396
                            ->info('List of enabled blocks by default')
397
                        ->end()
398
                        ->arrayNode('enabledLayouts')
399
                            ->prototype('scalar')
400
                            ->end()
401
                            ->info('List of enabled layouts by default')
402
                        ->end()
403
                    ->end()
404
                ->end()
405
            ->end();
406
    }
407
408
    private function addRouterSection(ArrayNodeDefinition $rootNode)
409
    {
410
        $nonSAAwareInfo = <<<EOT
411
Route names that are not supposed to be SiteAccess aware, i.e. Routes pointing to asset generation (like assetic).
412
Note that you can just specify a prefix to match a selection of routes.
413
e.g. "_assetic_" will match "_assetic_*"
414
Defaults to ['_assetic_', '_wdt', '_profiler', '_configurator_']
415
EOT;
416
        $rootNode
417
            ->children()
418
                ->arrayNode('router')
419
                    ->children()
420
                        ->arrayNode('default_router')
421
                            ->children()
422
                                ->arrayNode('non_siteaccess_aware_routes')
423
                                    ->prototype('scalar')->end()
424
                                    ->info($nonSAAwareInfo)
425
                                    ->example(array('my_route_name', 'some_prefix_'))
426
                                ->end()
427
                            ->end()
428
                        ->end()
429
                    ->end()
430
                    ->info('Router related settings')
431
                ->end()
432
            ->end();
433
    }
434
}
435