GroupService   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 280
Duplicated Lines 2.14 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 6
Bugs 2 Features 2
Metric Value
wmc 33
c 6
b 2
f 2
lcom 1
cbo 10
dl 6
loc 280
rs 9.3999

10 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 27 1
A commitChanges() 0 4 1
A removeOptionsFor() 0 10 3
A getOptionsFor() 0 4 1
B setOptionsFor() 6 26 6
A get() 0 10 2
C set() 0 28 7
B getEffective() 0 33 4
A parseConfig() 0 9 2
B writeConfig() 0 30 6

How to fix   Duplicated Code   

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:

1
<?php
2
3
/*
4
 * (c) Jim Martens <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace TwoMartens\Bundle\CoreBundle\Group;
11
12
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
13
use Symfony\Component\Filesystem\Filesystem;
14
use Symfony\Component\Finder\Finder;
15
use Symfony\Component\Finder\SplFileInfo;
16
use Symfony\Component\Yaml\Dumper;
17
use Symfony\Component\Yaml\Parser;
18
use TwoMartens\Bundle\CoreBundle\Event\GroupOptionTypeEvent;
19
use TwoMartens\Bundle\CoreBundle\Group\Option\OptionTypeInterface;
20
use TwoMartens\Bundle\CoreBundle\Model\Option;
21
use TwoMartens\Bundle\CoreBundle\Model\OptionCategory;
22
use TwoMartens\Bundle\CoreBundle\Model\User;
23
use TwoMartens\Bundle\CoreBundle\Util\ConfigUtil;
24
25
/**
26
 * Implementation for the GroupServiceInterface.
27
 *
28
 * @author    Jim Martens <[email protected]>
29
 * @copyright 2013-2015 Jim Martens
30
 */
31
class GroupService implements GroupServiceInterface
32
{
33
    /**
34
     * OptionCategory mapped to group
35
     * @var OptionCategory[]
36
     */
37
    private $optionData;
38
39
    /**
40
     * options mapped to group and category
41
     * @var Option[][]
42
     */
43
    private $options;
44
45
    /**
46
     * option types mapped to category and option name
47
     * @var array
48
     */
49
    private $optionTypes;
50
51
    /**
52
     * the finder
53
     * @var Finder
54
     */
55
    private $finder;
56
57
    /**
58
     * the YAML parser
59
     * @var Parser
60
     */
61
    private $parser;
62
63
    /**
64
     * the YAML dumper
65
     * @var Dumper
66
     */
67
    private $dumper;
68
69
    /**
70
     * the filesystem
71
     * @var Filesystem
72
     */
73
    private $filesystem;
74
75
    /**
76
     * list of the filenames which have to be removed
77
     * @var string[]
78
     */
79
    private $toBeRemoved;
80
81
    /**
82
     * Constructor.
83
     *
84
     * @param Finder                   $finder
85
     * @param Parser                   $parser
86
     * @param Dumper                   $dumper
87
     * @param Filesystem               $filesystem
88
     * @param EventDispatcherInterface $dispatcher
89
     */
90
    public function __construct(
91
        Finder $finder,
92
        Parser $parser,
93
        Dumper $dumper,
94
        Filesystem $filesystem,
95
        EventDispatcherInterface $dispatcher
96
    ) {
97
        $this->finder = $finder;
98
        $this->parser = $parser;
99
        $this->dumper = $dumper;
100
        $this->filesystem = $filesystem;
101
        $this->dispatcher = $dispatcher;
102
        $this->optionData = [];
103
        $this->options = [];
104
        $this->optionTypes = [];
105
        $this->toBeRemoved = [];
106
107
        // fill option types
108
        $event = new GroupOptionTypeEvent();
109
        $dispatcher->dispatch(
110
            'twomartens.core.group_service.init',
111
            $event
112
        );
113
        $this->optionTypes = $event->getOptionTypes();
114
115
        $this->parseConfig();
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function commitChanges()
122
    {
123
        $this->writeConfig();
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function removeOptionsFor($groupRoleName)
130
    {
131
        if (!isset($this->optionData[$groupRoleName])
132
         || !isset($this->options[$groupRoleName])) {
133
            throw new \LogicException('The given group role name doesn\'t exist.');
134
        }
135
        unset($this->options[$groupRoleName]);
136
        unset($this->optionData[$groupRoleName]);
137
        $this->toBeRemoved[] = $groupRoleName;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function getOptionsFor($groupRoleName)
144
    {
145
        return $this->optionData[$groupRoleName];
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function setOptionsFor($groupRoleName, OptionCategory $options)
152
    {
153
        $this->optionData[$groupRoleName] = $options;
154
155
        // updating options
156
        $categories = $options->getCategories();
157
        foreach ($categories as $category) {
158
            $name = $category->getName();
159 View Code Duplication
            if (!isset($this->options[$groupRoleName][$name])) {
160
                $this->options[$groupRoleName][$name] = [];
161
            }
162
163
            $_categories = $category->getCategories();
164
            foreach ($_categories as $_category) {
165
                $_name = $_category->getName();
166 View Code Duplication
                if (!isset($this->options[$groupRoleName][$name][$_name])) {
167
                    $this->options[$groupRoleName][$name][$_name] = [];
168
                }
169
                $_options = $_category->getOptions();
170
                foreach ($_options as $_option) {
171
                    $this->options[$groupRoleName][$name][$_name]
172
                        [$_option->getName()] = $_option;
173
                }
174
            }
175
        }
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181
    public function get($groupRoleName, $superCategory, $category, $optionName)
182
    {
183
        if (!isset($this->options[$groupRoleName][$superCategory]
184
                   [$category][$optionName])) {
185
            return null;
186
        }
187
188
        return $this->options[$groupRoleName][$superCategory]
189
               [$category][$optionName];
190
    }
191
192
    /**
193
     * {@inheritdoc}
194
     */
195
    public function set($groupRoleName, $superCategory, $category, Option $value)
196
    {
197
        $this->options[$groupRoleName][$superCategory]
198
            [$category][$value->getName()] = $value;
199
200
        $categories = $this->optionData[$groupRoleName]->getCategories();
201
        foreach ($categories as $_category) {
202
            if ($_category->getName() != $superCategory) {
203
                continue;
204
            }
205
206
            $_categories = $_category->getCategories();
207
            foreach ($_categories as $__category) {
208
                if ($__category->getName() != $category) {
209
                    continue;
210
                }
211
                $_options = $__category->getOptions();
212
                foreach ($_options as $option) {
213
                    if ($option->getName() != $value->getName()) {
214
                        continue;
215
                    }
216
217
                    $option->setValue($value->getValue());
218
                    break 3;
219
                }
220
            }
221
        }
222
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227
    public function getEffective(User $user, $superCategory, $category, $optionName)
228
    {
229
        $groupNames = $user->getGroupNames();
230
        /** @var Option[] $options */
231
        $options = [];
232
        foreach ($groupNames as $name) {
233
            $options[$name] = $this->get(
234
                $name,
235
                $superCategory,
236
                $category,
237
                $optionName
238
            );
239
        }
240
241
        $returnValue = null;
242
        foreach ($options as $name => $option) {
243
            if (!isset($this->optionTypes[$superCategory][$category][$optionName])) {
244
                // if this happens, somebody somewhere screwed up
245
                // we must return null, as there is no way to simply
246
                // ignore this
247
                $returnValue = null;
248
                break;
249
            }
250
            /** @var OptionTypeInterface $type */
251
            $type = $this->optionTypes[$superCategory][$category][$optionName];
252
            $returnValue = $type->getBestValue(
253
                $returnValue,
254
                $option
255
            );
256
        }
257
258
        return $returnValue;
259
    }
260
261
    /**
262
     * Parses the config files.
263
     */
264
    private function parseConfig()
265
    {
266
        foreach ($this->finder as $configFile) {
267
            /** @var SplFileInfo $configFile */
268
            $configYAML = $this->parser->parse($configFile->getContents());
269
            $configOptions = ConfigUtil::convertToOptions($configYAML);
270
            $this->setOptionsFor(strtoupper($configFile->getBasename('.yml')), $configOptions);
271
        }
272
    }
273
274
    /**
275
     * Writes the config files.
276
     *
277
     * ATTENTION: This method DOES NOT perform any sanitize actions. It
278
     * overwrites the config files with the options entirely.
279
     */
280
    private function writeConfig()
281
    {
282
        // updates existing files and adds new files if necessary
283
        $path = null;
284
        $roleNames = array_keys($this->optionData);
285
        $baseNames = [];
286
        foreach ($this->finder as $file) {
287
            /** @var SplFileInfo $file */
288
            if ($path === null) {
289
                $path = $file->getPath();
290
                break;
291
            }
292
        }
293
        foreach ($roleNames as $roleName) {
294
            $baseNames[] = strtolower($roleName);
295
        }
296
        foreach ($baseNames as $basename) {
297
            $category = $this->optionData[strtoupper($basename)];
298
            $yaml = ConfigUtil::convertToArray($category);
299
            $dumpReady = $this->dumper->dump($yaml, 3);
300
            $writePath = $path . '/' . $basename . '.yml';
301
            $this->filesystem->dumpFile($writePath, $dumpReady);
302
        }
303
        foreach ($this->toBeRemoved as $toRemove) {
304
            $basename = strtolower($toRemove). '.yml';
305
            $deletePath = $path . '/' . $basename;
306
            $this->filesystem->remove($deletePath);
307
        }
308
        $this->toBeRemoved = [];
309
    }
310
}
311