Completed
Push — 6.7 ( b24229...92b24b )
by André
36:36 queued 21:55
created

Configuration::addRepositoriesSection()   D

Complexity

Conditions 10
Paths 1

Size

Total Lines 129
Code Lines 99

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 99
nc 1
nop 1
dl 0
loc 129
rs 4.8196
c 0
b 0
f 0

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