Completed
Push — dynamic_siteaccesses ( 16c7ff )
by
unknown
20:23
created

Contextualizer   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 349
Duplicated Lines 1.72 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 6
loc 349
rs 4.08
c 0
b 0
f 0
wmc 59
lcom 1
cbo 1

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 1
A setContextualParameter() 0 4 1
A mapSetting() 0 8 3
F mapConfigArray() 6 155 32
A getContainerParameter() 0 8 2
B groupsArraySetting() 0 32 6
A mapReservedScopeArray() 0 17 4
A setContainer() 0 4 1
A getContainer() 0 4 1
A setSiteAccessNodeName() 0 4 1
A getSiteAccessNodeName() 0 4 1
A setNamespace() 0 4 1
A getNamespace() 0 4 1
A setAvailableSiteAccesses() 0 4 1
A getAvailableSiteAccesses() 0 4 1
A setGroupsBySiteAccess() 0 4 1
A getGroupsBySiteAccess() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Contextualizer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Contextualizer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * File containing the Contextualizer 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\Configuration\SiteAccessAware;
10
11
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ConfigResolver;
12
use Symfony\Component\DependencyInjection\ContainerInterface;
13
14
class Contextualizer implements ContextualizerInterface
15
{
16
    /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
17
    private $container;
18
19
    /** @var string */
20
    private $namespace;
21
22
    /**
23
     * Name of the node under which scope based (semantic) configuration takes place.
24
     *
25
     * @var string
26
     */
27
    private $siteAccessNodeName;
28
29
    /** @var array */
30
    private $availableSiteAccesses;
31
32
    /** @var array */
33
    private $groupsBySiteAccess;
34
35
    /**
36
     * @var array
37
     */
38
    private $availableSiteAccessGroups;
39
40
    public function __construct(
41
        ContainerInterface $containerBuilder,
42
        $namespace,
43
        $siteAccessNodeName,
44
        array $availableSiteAccesses,
45
        array $availableSiteAccessGroups,
46
        array $groupsBySiteAccess
47
    ) {
48
        $this->container = $containerBuilder;
49
        $this->namespace = $namespace;
50
        $this->siteAccessNodeName = $siteAccessNodeName;
51
        $this->availableSiteAccesses = $availableSiteAccesses;
52
        $this->availableSiteAccessGroups = $availableSiteAccessGroups;
53
        $this->groupsBySiteAccess = $groupsBySiteAccess;
54
    }
55
56
    public function setContextualParameter($parameterName, $scope, $value)
57
    {
58
        $this->container->setParameter("$this->namespace.$scope.$parameterName", $value);
59
    }
60
61
    public function mapSetting($id, array $config)
62
    {
63
        foreach ($config[$this->siteAccessNodeName] as $currentScope => $scopeSettings) {
64
            if (isset($scopeSettings[$id])) {
65
                $this->setContextualParameter($id, $currentScope, $scopeSettings[$id]);
66
            }
67
        }
68
    }
69
70
    public function mapConfigArray($id, array $config, $options = 0)
71
    {
72
        $this->mapReservedScopeArray($id, $config, ConfigResolver::SCOPE_DEFAULT);
73
        $this->mapReservedScopeArray($id, $config, ConfigResolver::SCOPE_GLOBAL);
74
        $defaultSettings = $this->getContainerParameter(
75
            $this->namespace . '.' . ConfigResolver::SCOPE_DEFAULT . '.' . $id,
76
            []
77
        );
78
        $globalSettings = $this->getContainerParameter(
79
            $this->namespace . '.' . ConfigResolver::SCOPE_GLOBAL . '.' . $id,
80
            []
81
        );
82
83
        // (!) Keep siteaccess group settings
84
        foreach (array_keys($this->availableSiteAccessGroups) as $scope) {
85
            $scopeSettings = array();
86 View Code Duplication
            if (isset($config[$this->siteAccessNodeName][$scope][$id])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
87
                $scopeSettings = $config[$this->siteAccessNodeName][$scope][$id];
88
            }
89
90
            if (empty($scopeSettings)) {
91
                continue;
92
            }
93
94
            if ($options & static::MERGE_FROM_SECOND_LEVEL) {
95
                // array_merge() has to be used because we don't
96
                // know whether we have a hash or a plain array
97
                $keys1 = array_unique(
98
                    array_merge(
99
                        array_keys($defaultSettings),
100
                        array_keys($scopeSettings),
101
                        array_keys($globalSettings)
102
                    )
103
                );
104
                $mergedSettings = array();
105
                foreach ($keys1 as $key) {
106
                    // Only merge if actual setting is an array.
107
                    // We assume default setting to be a clear reference for this.
108
                    // If the setting is not an array, we copy the right value, in respect to the precedence:
109
                    // 1. global
110
                    // 3. Group
111
                    // 4. default
112
                    if (array_key_exists($key, $defaultSettings) && !is_array($defaultSettings[$key])) {
113
                        if (array_key_exists($key, $globalSettings)) {
114
                            $mergedSettings[$key] = $globalSettings[$key];
115
                        } elseif (array_key_exists($key, $scopeSettings)) {
116
                            $mergedSettings[$key] = $scopeSettings[$key];
117
                        } else {
118
                            $mergedSettings[$key] = $defaultSettings[$key];
119
                        }
120
                    } else {
121
                        $mergedSettings[$key] = array_merge(
122
                            isset($defaultSettings[$key]) ? $defaultSettings[$key] : array(),
123
                            isset($scopeSettings[$key]) ? $scopeSettings[$key] : array(),
124
                            isset($globalSettings[$key]) ? $globalSettings[$key] : array()
125
                        );
126
                    }
127
                }
128
            } else {
129
                $mergedSettings = array_merge(
130
                    $defaultSettings,
131
                    $scopeSettings,
132
                    $globalSettings
133
                );
134
            }
135
136
            if ($options & static::UNIQUE) {
137
                $mergedSettings = array_values(
138
                    array_unique($mergedSettings)
139
                );
140
            }
141
142
            $this->container->setParameter("$this->namespace.$scope.$id", $mergedSettings);
143
        }
144
145
        foreach ($this->availableSiteAccesses as $scope) {
146
            // for a siteaccess, we have to merge the default value,
147
            // the group value(s), the siteaccess value and the global
148
            // value of the settings.
149
            $groupsSettings = [];
150
            if (isset($this->groupsBySiteAccess[$scope]) && is_array($this->groupsBySiteAccess[$scope])) {
151
                $groupsSettings = $this->groupsArraySetting(
152
                    $this->groupsBySiteAccess[$scope],
153
                    $id,
154
                    $config,
155
                    $options & static::MERGE_FROM_SECOND_LEVEL
156
                );
157
            }
158
159
            $scopeSettings = [];
160 View Code Duplication
            if (isset($config[$this->siteAccessNodeName][$scope][$id])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
161
                $scopeSettings = $config[$this->siteAccessNodeName][$scope][$id];
162
            }
163
164
            if (empty($groupsSettings) && empty($scopeSettings)) {
165
                continue;
166
            }
167
168
            if ($options & static::MERGE_FROM_SECOND_LEVEL) {
169
                // array_merge() has to be used because we don't
170
                // know whether we have a hash or a plain array
171
                $keys1 = array_unique(
172
                    array_merge(
173
                        array_keys($defaultSettings),
174
                        array_keys($groupsSettings),
175
                        array_keys($scopeSettings),
176
                        array_keys($globalSettings)
177
                    )
178
                );
179
                $mergedSettings = [];
180
                foreach ($keys1 as $key) {
181
                    // Only merge if actual setting is an array.
182
                    // We assume default setting to be a clear reference for this.
183
                    // If the setting is not an array, we copy the right value, in respect to the precedence:
184
                    // 1. global
185
                    // 2. SiteAccess
186
                    // 3. Group
187
                    // 4. default
188
                    if (array_key_exists($key, $defaultSettings) && !is_array($defaultSettings[$key])) {
189
                        if (array_key_exists($key, $globalSettings)) {
190
                            $mergedSettings[$key] = $globalSettings[$key];
191
                        } elseif (array_key_exists($key, $scopeSettings)) {
192
                            $mergedSettings[$key] = $scopeSettings[$key];
193
                        } elseif (array_key_exists($key, $groupsSettings)) {
194
                            $mergedSettings[$key] = $groupsSettings[$key];
195
                        } else {
196
                            $mergedSettings[$key] = $defaultSettings[$key];
197
                        }
198
                    } else {
199
                        $mergedSettings[$key] = array_merge(
200
                            isset($defaultSettings[$key]) ? $defaultSettings[$key] : [],
201
                            isset($groupsSettings[$key]) ? $groupsSettings[$key] : [],
202
                            isset($scopeSettings[$key]) ? $scopeSettings[$key] : [],
203
                            isset($globalSettings[$key]) ? $globalSettings[$key] : []
204
                        );
205
                    }
206
                }
207
            } else {
208
                $mergedSettings = array_merge(
209
                    $defaultSettings,
210
                    $groupsSettings,
211
                    $scopeSettings,
212
                    $globalSettings
213
                );
214
            }
215
216
            if ($options & static::UNIQUE) {
217
                $mergedSettings = array_values(
218
                    array_unique($mergedSettings)
219
                );
220
            }
221
222
            $this->container->setParameter("$this->namespace.$scope.$id", $mergedSettings);
223
        }
224
    }
225
226
    /**
227
     * Returns the value under the $id in the $container. if the container does
228
     * not known this $id, returns $default.
229
     *
230
     * @param string $id
231
     * @param mixed $default
232
     *
233
     * @return mixed
234
     */
235
    protected function getContainerParameter($id, $default = null)
236
    {
237
        if ($this->container->hasParameter($id)) {
238
            return $this->container->getParameter($id);
239
        }
240
241
        return $default;
242
    }
243
244
    /**
245
     * Merges setting array for a set of groups.
246
     *
247
     * @param array $groups array of group name
248
     * @param string $id id of the setting array under ezpublish.<base_key>.<group_name>
249
     * @param array $config the full configuration array
250
     * @param int $options only static::MERGE_FROM_SECOND_LEVEL or static::UNIQUE are recognized
251
     *
252
     * @return array
253
     */
254
    private function groupsArraySetting(array $groups, $id, array $config, $options = 0)
255
    {
256
        $groupsSettings = [];
257
        sort($groups);
258
        foreach ($groups as $group) {
259
            if (isset($config[$this->siteAccessNodeName][$group][$id])) {
260
                if ($options & static::MERGE_FROM_SECOND_LEVEL) {
261
                    foreach (array_keys($config[$this->siteAccessNodeName][$group][$id]) as $key) {
262
                        if (!isset($groupsSettings[$key])) {
263
                            $groupsSettings[$key] = $config[$this->siteAccessNodeName][$group][$id][$key];
264
                        } else {
265
                            // array_merge() has to be used because we don't
266
                            // know whether we have a hash or a plain array
267
                            $groupsSettings[$key] = array_merge(
268
                                $groupsSettings[$key],
269
                                $config[$this->siteAccessNodeName][$group][$id][$key]
270
                            );
271
                        }
272
                    }
273
                } else {
274
                    // array_merge() has to be used because we don't
275
                    // know whether we have a hash or a plain array
276
                    $groupsSettings = array_merge(
277
                        $groupsSettings,
278
                        $config[$this->siteAccessNodeName][$group][$id]
279
                    );
280
                }
281
            }
282
        }
283
284
        return $groupsSettings;
285
    }
286
287
    /**
288
     * Ensures settings array defined in a given "reserved scope" are registered properly.
289
     * "Reserved scope" can typically be ConfigResolver::SCOPE_DEFAULT or ConfigResolver::SCOPE_GLOBAL.
290
     *
291
     * @param string $id
292
     * @param array $config
293
     * @param string $scope
294
     */
295
    private function mapReservedScopeArray($id, array $config, $scope)
296
    {
297
        if (
298
            isset($config[$this->siteAccessNodeName][$scope][$id])
299
            && !empty($config[$this->siteAccessNodeName][$scope][$id])
300
        ) {
301
            $key = "$this->namespace.$scope.$id";
302
            $value = $config[$this->siteAccessNodeName][$scope][$id];
303
            if ($this->container->hasParameter($key)) {
304
                $value = array_merge(
305
                    $this->container->getParameter($key),
306
                    $value
307
                );
308
            }
309
            $this->container->setParameter($key, $value);
310
        }
311
    }
312
313
    public function setContainer(ContainerInterface $container)
314
    {
315
        $this->container = $container;
316
    }
317
318
    public function getContainer()
319
    {
320
        return $this->container;
321
    }
322
323
    public function setSiteAccessNodeName($scopeNodeName)
324
    {
325
        $this->siteAccessNodeName = $scopeNodeName;
326
    }
327
328
    public function getSiteAccessNodeName()
329
    {
330
        return $this->siteAccessNodeName;
331
    }
332
333
    public function setNamespace($namespace)
334
    {
335
        $this->namespace = $namespace;
336
    }
337
338
    public function getNamespace()
339
    {
340
        return $this->namespace;
341
    }
342
343
    public function setAvailableSiteAccesses(array $availableSiteAccesses)
344
    {
345
        $this->availableSiteAccesses = $availableSiteAccesses;
346
    }
347
348
    public function getAvailableSiteAccesses()
349
    {
350
        return $this->availableSiteAccesses;
351
    }
352
353
    public function setGroupsBySiteAccess(array $groupsBySiteAccess)
354
    {
355
        $this->groupsBySiteAccess = $groupsBySiteAccess;
356
    }
357
358
    public function getGroupsBySiteAccess()
359
    {
360
        return $this->groupsBySiteAccess;
361
    }
362
}
363