Completed
Push — master ( 23e37f...b7a3e1 )
by Jonathan
02:43
created

Configuration   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 300
Duplicated Lines 16 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 94.87%

Importance

Changes 0
Metric Value
wmc 46
lcom 1
cbo 2
dl 48
loc 300
ccs 111
cts 117
cp 0.9487
rs 8.3999
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
F createFromXmlFile() 0 67 13
A setRootDir() 12 12 2
A getRootDir() 0 4 1
A setWatchDirectories() 0 16 3
A getWatchDirectories() 0 4 1
A setTestsDirectory() 12 12 2
A getTestsDirectory() 0 4 1
A setBootstrapPath() 12 12 2
A getBootstrapPath() 0 4 1
A setPhpunitPath() 12 12 2
A getPhpunitPath() 0 4 1
A setDatabaseSandbox() 0 6 1
A getDatabaseSandbox() 0 8 2
A setDatabaseNames() 0 6 1
A setSandboxEnabled() 0 6 1
A setMemoryLimit() 0 6 1
A getMemoryLimit() 0 4 1
A setNumChunks() 0 6 1
A setEventDispatcher() 0 6 1
A getEventDispatcher() 0 8 2
B throwExceptionIfConfigurationIncomplete() 0 20 5
A getNumChunks() 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 Configuration 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 Configuration, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PHPChunkit;
4
5
use InvalidArgumentException;
6
use Symfony\Component\EventDispatcher\EventDispatcher;
7
8
/**
9
 * @testClass PHPChunkit\Test\ConfigurationTest
10
 */
11
class Configuration
12
{
13
    /**
14
     * @var string
15
     */
16
    private $rootDir = '';
17
18
    /**
19
     * @var array
20
     */
21
    private $watchDirectories = [];
22
23
    /**
24
     * @var string
25
     */
26
    private $testsDirectory = '';
27
28
    /**
29
     * @var string
30
     */
31
    private $bootstrapPath = '';
32
33
    /**
34
     * @var string
35
     */
36
    private $phpunitPath = 'vendor/bin/phpunit';
37
38
    /**
39
     * @var null|EventDispatcher
40
     */
41
    private $eventDispatcher;
42
43
    /**
44
     * @var null|DatabaseSandbox
45
     */
46
    private $databaseSandbox;
47
48
    /**
49
     * @var string
50
     */
51
    private $memoryLimit = '256M';
52
53
    /**
54
     * @var int
55
     */
56
    private $numChunks = 1;
57
58 2
    public static function createFromXmlFile(string $path) : self
59
    {
60 2
        if (!file_exists($path)) {
61
            throw new \InvalidArgumentException(sprintf('XML file count not be found at path "%s"', $path));
62
        }
63
64 2
        $configuration = new self();
65
66 2
        $xml = simplexml_load_file($path);
67 2
        $attributes = $xml->attributes();
68
69 2
        if ($rootDir = (string) $attributes['root-dir']) {
70 2
            $configuration->setRootDir($rootDir);
71
        }
72
73 2
        if ($bootstrapPath = (string) $attributes['bootstrap']) {
74 2
            $configuration->setBootstrapPath($bootstrapPath);
75
        }
76
77 2
        if ($testsDir = (string) $attributes['tests-dir']) {
78 2
            $configuration->setTestsDirectory($testsDir);
79
        }
80
81 2
        if ($phpunitPath = (string) $attributes['phpunit-path']) {
82 2
            $configuration->setPhpunitPath($phpunitPath);
83
        }
84
85 2
        if ($memoryLimit = (string) $attributes['memory-limit']) {
86 2
            $configuration->setMemoryLimit($memoryLimit);
87
        }
88
89 2
        if ($numChunks = (int) $attributes['num-chunks']) {
90 2
            $configuration->setNumChunks($numChunks);
91
        }
92
93 2
        if ($watchDirectories = (array) $xml->{'watch-directories'}->{'watch-directory'}) {
94 2
            $configuration->setWatchDirectories($watchDirectories);
95
        }
96
97 2
        if ($databaseNames = (array) $xml->{'database-names'}->{'database-name'}) {
98 2
            $configuration->setDatabaseNames($databaseNames);
99
        }
100
101 2
        $events = (array) $xml->{'events'};
102 2
        $listeners = $events['listener'] ?? null;
103
104 2
        if ($listeners) {
105 2
            $eventDispatcher = $configuration->getEventDispatcher();
106
107 2
            foreach ($listeners as $listener) {
108 2
                $eventName = (string) $listener->attributes()['event'];
109 2
                $className = (string) $listener->class;
110
111 2
                $listener = new $className($configuration);
112
113 2
                if (!$listener instanceof ListenerInterface) {
114
                    throw new InvalidArgumentException(
115
                        sprintf('%s does not implement %s', $className, ListenerInterface::class)
116
                    );
117
                }
118
119 2
                $eventDispatcher->addListener($eventName, [$listener, 'execute']);
120
            }
121
        }
122
123 2
        return $configuration;
124
    }
125
126 10 View Code Duplication
    public function setRootDir(string $rootDir) : self
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
127
    {
128 10
        if (!is_dir($rootDir)) {
129 1
            throw new \InvalidArgumentException(
130 1
                sprintf('Root directory "%s" does not exist.', $rootDir)
131
            );
132
        }
133
134 9
        $this->rootDir = realpath($rootDir);
135
136 9
        return $this;
137
    }
138
139 4
    public function getRootDir() : string
140
    {
141 4
        return $this->rootDir;
142
    }
143
144 5
    public function setWatchDirectories(array $watchDirectories) : self
145
    {
146 5
        foreach ($watchDirectories as $key => $watchDirectory) {
147 5
            if (!is_dir($watchDirectory)) {
148 1
                throw new \InvalidArgumentException(
149 1
                    sprintf('Watch directory "%s" does not exist.', $watchDirectory)
150
                );
151
            }
152
153 4
            $watchDirectories[$key] = realpath($watchDirectory);
154
        }
155
156 4
        $this->watchDirectories = $watchDirectories;
157
158 4
        return $this;
159
    }
160
161 3
    public function getWatchDirectories() : array
162
    {
163 3
        return $this->watchDirectories;
164
    }
165
166 5 View Code Duplication
    public function setTestsDirectory(string $testsDirectory) : self
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
167
    {
168 5
        if (!is_dir($testsDirectory)) {
169 1
            throw new \InvalidArgumentException(
170 1
                sprintf('Tests directory "%s" does not exist.', $testsDirectory)
171
            );
172
        }
173
174 4
        $this->testsDirectory = realpath($testsDirectory);
175
176 4
        return $this;
177
    }
178
179 3
    public function getTestsDirectory() : string
180
    {
181 3
        return $this->testsDirectory;
182
    }
183
184 4 View Code Duplication
    public function setBootstrapPath(string $bootstrapPath) : self
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
185
    {
186 4
        if (!file_exists($bootstrapPath)) {
187 1
            throw new \InvalidArgumentException(
188 1
                sprintf('Bootstrap path "%s" does not exist.', $bootstrapPath)
189
            );
190
        }
191
192 3
        $this->bootstrapPath = realpath($bootstrapPath);
193
194 3
        return $this;
195
    }
196
197 3
    public function getBootstrapPath() : string
198
    {
199 3
        return $this->bootstrapPath;
200
    }
201
202 10 View Code Duplication
    public function setPhpunitPath(string $phpunitPath) : self
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
203
    {
204 10
        if (!file_exists($phpunitPath)) {
205 1
            throw new \InvalidArgumentException(
206 1
                sprintf('PHPUnit path "%s" does not exist.', $phpunitPath)
207
            );
208
        }
209
210 9
        $this->phpunitPath = realpath($phpunitPath);
211
212 9
        return $this;
213
    }
214
215 3
    public function getPhpunitPath() : string
216
    {
217 3
        return $this->phpunitPath;
218
    }
219
220 1
    public function setDatabaseSandbox(DatabaseSandbox $databaseSandbox) : self
221
    {
222 1
        $this->databaseSandbox = $databaseSandbox;
223
224 1
        return $this;
225
    }
226
227 4
    public function getDatabaseSandbox() : DatabaseSandbox
228
    {
229 4
        if ($this->databaseSandbox === null) {
230 4
            $this->databaseSandbox = new DatabaseSandbox();
231
        }
232
233 4
        return $this->databaseSandbox;
234
    }
235
236 3
    public function setDatabaseNames(array $databaseNames) : self
237
    {
238 3
        $this->getDatabaseSandbox()->setDatabaseNames($databaseNames);
239
240 3
        return $this;
241
    }
242
243 1
    public function setSandboxEnabled(bool $sandboxEnabled) : self
244
    {
245 1
        $this->getDatabaseSandbox()->setSandboxEnabled($sandboxEnabled);
246
247 1
        return $this;
248
    }
249
250 2
    public function setMemoryLimit(string $memoryLimit) : self
251
    {
252 2
        $this->memoryLimit = $memoryLimit;
253
254 2
        return $this;
255
    }
256
257 2
    public function getMemoryLimit() : string
258
    {
259 2
        return $this->memoryLimit;
260
    }
261
262 2
    public function setNumChunks(int $numChunks) : self
263
    {
264 2
        $this->numChunks = $numChunks;
265
266 2
        return $this;
267
    }
268
269 1
    public function getNumChunks() : int
270
    {
271 1
        return $this->numChunks;
272
    }
273
274 1
    public function setEventDispatcher(EventDispatcher $eventDispatcher) : self
275
    {
276 1
        $this->eventDispatcher = $eventDispatcher;
277
278 1
        return $this;
279
    }
280
281 3
    public function getEventDispatcher() : EventDispatcher
282
    {
283 3
        if ($this->eventDispatcher === null) {
284 3
            $this->eventDispatcher = new EventDispatcher();
285
        }
286
287 3
        return $this->eventDispatcher;
288
    }
289
290 2
    public function throwExceptionIfConfigurationIncomplete()
291
    {
292 2
        if (!$this->rootDir) {
293 1
            throw new \InvalidArgumentException('You must configure a root directory.');
294
        }
295
296 1
        if (!$this->watchDirectories) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->watchDirectories of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
297
            throw new \InvalidArgumentException('You must configure a watch directory.');
298
        }
299
300 1
        if (!$this->testsDirectory) {
301
            throw new \InvalidArgumentException('You must configure a tests directory.');
302
        }
303
304 1
        if (!$this->phpunitPath) {
305
            throw new \InvalidArgumentException('You must configure a phpunit path.');
306
        }
307
308 1
        return true;
309
    }
310
}
311