Completed
Push — master ( e41e91...2b4213 )
by Aleh
01:47 queued 01:39
created

Index   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 222
Duplicated Lines 15.32 %

Coupling/Cohesion

Components 3
Dependencies 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 50
c 1
b 0
f 0
lcom 3
cbo 4
dl 34
loc 222
rs 8.6206

24 Methods

Rating   Name   Duplication   Size   Complexity  
A getFQCNs() 0 4 1
A findFQCNByFile() 0 14 4
A findClassByFQCN() 9 9 3
A findInterfaceByFQCN() 9 9 3
A findFunctionByName() 0 9 3
A findClassChildren() 8 8 3
A findInterfaceChildrenClasses() 8 8 3
A getClasses() 0 8 2
A getInterfaces() 0 8 2
A getFunctions() 0 8 2
B addClass() 0 14 5
A addInterface() 0 11 4
A addFunction() 0 4 1
A addFQCN() 0 3 1
A getClassMap() 0 3 1
A getFlippedClassMap() 0 3 1
A getImplements() 0 3 1
A getExtends() 0 3 1
A setClassMap() 0 4 1
A addExtend() 0 8 2
A addImplement() 0 8 2
A isParsed() 0 6 1
A addParsedFile() 0 3 1
A hasCoreIndex() 0 4 2

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 Index 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 Index, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Padawan\Domain\Project;
4
5
use Padawan\Domain\Project\Node\InterfaceData;
6
use Padawan\Domain\Project\Node\ClassData;
7
use Padawan\Domain\Project\Node\FunctionData;
8
9
class Index
10
{
11
    private $fqcns              = [];
12
    private $classes            = [];
13
    private $interfaces         = [];
14
    private $classMap           = [];
15
    private $flippedClassMap    = [];
16
    private $extends            = [];
17
    private $implements         = [];
18
    private $parsedFiles        = [];
19
    private $functions          = [];
20
    /** @var Index $coreIndex */
21
    private static $coreIndex;
22
23
    public function getFQCNs()
24
    {
25
        return $this->fqcns;
26
    }
27
28
    /**
29
     * @return FQCN
30
     */
31
    public function findFQCNByFile($file)
32
    {
33
        if (!array_key_exists($file, $this->flippedClassMap)) {
34
            return null;
35
        }
36
        $fqcnStr = $this->flippedClassMap[$file];
37
        if (empty($fqcnStr)) {
38
            return null;
39
        }
40
        if (!array_key_exists($fqcnStr, $this->fqcns)) {
41
            return null;
42
        }
43
        return $this->fqcns[$fqcnStr];
44
    }
45
46
    /**
47
     * @return ClassData
48
     */
49 View Code Duplication
    public function findClassByFQCN(FQCN $fqcn) {
0 ignored issues
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...
50
        $str = $fqcn->toString();
51
        if (array_key_exists($str, $this->classes)) {
52
            return $this->classes[$str];
53
        }
54
        if ($this->hasCoreIndex()) {
55
            return self::$coreIndex->findClassByFQCN($fqcn);
56
        }
57
    }
58
59
    /**
60
     * @return InterfaceData
61
     */
62 View Code Duplication
    public function findInterfaceByFQCN(FQCN $fqcn) {
0 ignored issues
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...
63
        $str = $fqcn->toString();
64
        if (array_key_exists($str, $this->interfaces)) {
65
            return $this->interfaces[$str];
66
        }
67
        if ($this->hasCoreIndex()) {
68
            return self::$coreIndex->findInterfaceByFQCN($fqcn);
69
        }
70
    }
71
72
    /**
73
     * @return FunctionData
74
     */
75
    public function findFunctionByName($functionName)
76
    {
77
        if (array_key_exists($functionName, $this->functions)) {
78
            return $this->functions[$functionName];
79
        }
80
        if ($this->hasCoreIndex()) {
81
            return self::$coreIndex->findFunctionByName($functionName);
82
        }
83
    }
84
85
    /**
86
     * @return ClassData[]
87
     */
88 View Code Duplication
    public function findClassChildren(FQCN $class) {
0 ignored issues
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...
89
        if (!array_key_exists($class->toString(), $this->extends)
90
            || !is_array($this->extends[$class->toString()])
91
        ) {
92
            $this->extends[$class->toString()] = [];
93
        }
94
        return $this->extends[$class->toString()];
95
    }
96
97
    /**
98
     * @return ClassData[]
99
     */
100 View Code Duplication
    public function findInterfaceChildrenClasses(FQCN $interface) {
0 ignored issues
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...
101
        if (!array_key_exists($interface->toString(), $this->implements)
102
            || !is_array($this->implements[$interface->toString()])
103
        ) {
104
            $this->implements[$interface->toString()] = [];
105
        }
106
        return $this->implements[$interface->toString()];
107
    }
108
109
    /**
110
     * @return ClassData[]
111
     */
112
    public function getClasses()
113
    {
114
        $classes = $this->classes;
115
        if ($this->hasCoreIndex()) {
116
            $classes = array_merge($classes, self::$coreIndex->getClasses());
117
        }
118
        return $classes;
119
    }
120
121
    /**
122
     * @return InterfaceData[]
123
     */
124
    public function getInterfaces()
125
    {
126
        $interfaces = $this->interfaces;
127
        if ($this->hasCoreIndex()) {
128
            $interfaces = array_merge($interfaces, self::$coreIndex->getInterfaces());
129
        }
130
        return $interfaces;
131
    }
132
133
    /**
134
     * @return FunctionData[]
135
     */
136
    public function getFunctions()
137
    {
138
        $functions = $this->functions;
139
        if ($this->hasCoreIndex()) {
140
            $functions = array_merge($functions, self::$coreIndex->getFunctions());
141
        }
142
        return $functions;
143
    }
144
145
    public function addClass(ClassData $class) {
146
        $this->classes[$class->fqcn->toString()] = $class;
147
        if ($class->getParent() instanceof FQCN) {
148
            $this->addExtend($class, $class->getParent());
149
        }
150
        foreach ($class->getInterfaces() as $interface) {
151
            if ($interface instanceof FQCN) {
152
                $this->addImplement($class, $interface);
153
            }
154
        }
155
        foreach ($this->findClassChildren($class->fqcn) AS $child) {
156
            $child->setParent($class);
157
        }
158
    }
159
160
    public function addInterface(InterfaceData $interface) {
161
        $this->interfaces[$interface->fqcn->toString()] = $interface;
162
        foreach ($this->findInterfaceChildrenClasses($interface->fqcn) as $child) {
163
            $this->addImplement($child, $interface->fqcn);
164
        }
165
        foreach ($interface->getInterfaces() as $parent) {
166
            if ($parent instanceof FQCN) {
167
                $this->addImplement($interface, $parent);
168
            }
169
        }
170
    }
171
172
    public function addFunction(FunctionData $function)
173
    {
174
        $this->functions[$function->name] = $function;
175
    }
176
177
    public function addFQCN(FQCN $fqcn) {
178
        $this->fqcns[$fqcn->toString()] = $fqcn;
179
    }
180
181
    public function getClassMap() {
182
        return $this->classMap;
183
    }
184
    public function getFlippedClassMap() {
185
        return $this->classMap;
186
    }
187
    public function getImplements() {
188
        return $this->implements;
189
    }
190
    public function getExtends() {
191
        return $this->extends;
192
    }
193
194
    public function setClassMap(array $classMap) {
195
        $this->classMap = $classMap;
196
        $this->flippedClassMap = array_flip($classMap);
197
    }
198
    protected function addExtend(ClassData $class, FQCN $parent) {
199
        $this->findClassChildren($parent);
200
        $this->extends[$parent->toString()][$class->fqcn->toString()] = $class;
201
        $parentClass = $this->findClassByFQCN($parent);
202
        if ($parentClass instanceof ClassData) {
203
            $class->setParent($parentClass);
204
        }
205
    }
206
207
    protected function addImplement($class, FQCN $fqcn) {
208
        $this->findInterfaceChildrenClasses($fqcn);
209
        $this->implements[$fqcn->toString()][$class->fqcn->toString()] = $class;
210
        $interface = $this->findInterfaceByFQCN($fqcn);
211
        if ($interface instanceof InterfaceData) {
212
            $class->addInterface($interface);
213
        }
214
    }
215
216
    public function isParsed($file) {
217
        return array_key_exists(
218
            $file,
219
            $this->parsedFiles
220
        );
221
    }
222
    public function addParsedFile($file) {
223
        $this->parsedFiles[$file] = $file;
224
    }
225
226
    private function hasCoreIndex()
227
    {
228
        return $this !== self::$coreIndex && !empty(self::$coreIndex);
229
    }
230
}
231