Result   C
last analyzed

Complexity

Total Complexity 66

Size/Duplication

Total Lines 254
Duplicated Lines 12.6 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 86.6%

Importance

Changes 0
Metric Value
wmc 66
lcom 2
cbo 2
dl 32
loc 254
ccs 84
cts 97
cp 0.866
rs 5.7474
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A __clone() 0 4 1
C __set() 0 29 11
B __get() 0 16 5
A searchValue() 0 14 3
A getPath() 0 14 4
A hasChildren() 0 4 2
A setAsNotRow() 0 9 4
B getDepth() 13 13 5
A getCurrentDepth() 0 7 2
B getHorizontalDepth() 13 13 5
A copy() 0 10 4
B toText() 0 17 5
A toTextTree() 0 11 3
A getLastChildrenArray() 0 12 3
A getCurrentValue() 3 7 3
A setCurrentValue() 3 6 3
A orderBy() 0 7 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 Result 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 Result, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace EngineWorks\Pivot;
3
4
/**
5
 * Class to present Groups of results
6
 *
7
 * @property string $fieldname
8
 * @property string $caption
9
 * @property bool $isrow
10
 * @property array $values
11
 * @property Results|Result[] $children
12
 * @property Result $parent
13
 */
14
class Result
15
{
16
    /** @var string */
17
    private $privFieldname;
18
19
    /** @var string */
20
    private $privCaption;
21
22
    /** @var array|null */
23
    private $privValues;
24
25
    /** @var Results|Result[] */
26
    private $privChildren;
27
28
    /** @var Result */
29
    private $privParent;
30
31
    /** @var bool */
32
    private $privIsRow;
33
34 11
    public function __construct($fieldname, $caption, $values = null, $isrow = true)
35
    {
36 11
        $this->fieldname = $fieldname;
37 11
        $this->caption = $caption;
38 11
        $this->values = $values;
39 11
        $this->isrow = $isrow;
40 11
        $this->privChildren = null;
41 11
    }
42
43
    public function __clone()
44
    {
45
        throw new PivotException('Result cannot be cloned');
46
    }
47
48 11
    public function __set($name, $value)
49
    {
50 11
        if ('fieldname' == $name) {
51 11
            $this->privFieldname = (string) $value;
52 11
        } elseif ('caption' == $name) {
53 11
            $this->privCaption = (string) $value;
54 11
        } elseif ('values' == $name) {
55 11
            if (! is_null($value) && ! is_array($value)) {
56
                throw new PivotException('Property values must be null or array');
57
            } else {
58 11
                $this->privValues = $value;
59
            }
60 11
        } elseif ('isrow' == $name) {
61 11
            $this->privIsRow = (bool) $value;
62 8
        } elseif ('children' == $name) {
63
            throw new PivotException('Property children is read only');
64 8
        } elseif ('parent' == $name) {
65 8
            if (! is_null($this->privParent)) {
66
                throw new PivotException('Property parent has been set already');
67
            }
68 8
            if (! ($value instanceof self)) {
69
                throw new PivotException('Property parent must be a Result');
70
            }
71 8
            $this->privParent = $value;
72
        } else {
73
            throw new PivotException("Property $name does not exists");
74
        }
75 11
        return null;
76
    }
77
78 10
    public function __get($name)
79
    {
80 10
        if ('isrow' === $name) {
81 2
            $propname = 'privIsRow';
82
        } else {
83 10
            $propname = 'priv' . ucfirst($name);
84
        }
85 10
        if (! property_exists($this, $propname)) {
86
            throw new PivotException("Property $name does not exists");
87
        }
88
        // late creation of children property, created only when used
89 10
        if ($name == 'children' && is_null($this->privChildren)) {
90 10
            $this->privChildren = new Results($this);
91
        }
92 10
        return $this->{$propname};
93
    }
94
95
    /**
96
     * @param array $path
97
     * @return array|null
98
     */
99 1
    public function searchValue(array $path)
100
    {
101
        // if this is the element
102 1
        if (count($path) == 0) {
103 1
            return $this->privValues;
104
        }
105
        // get the first part to check in
106 1
        $search = array_shift($path);
107
        // if exists then search inside
108 1
        if ($this->children->exists($search)) { // if found
109 1
            return $this->children->value($search)->searchValue($path);
110
        }
111 1
        return null;
112
    }
113
114 1
    public function getPath($excludeRoot = true)
115
    {
116
        // I'm the root and is required to exclude
117 1
        if ($excludeRoot && is_null($this->privParent)) {
118 1
            return [];
119
        }
120
        // define me as an array
121 1
        $me = [$this->privCaption];
122 1
        if (! is_null($this->privParent)) {
123 1
            return array_merge($this->privParent->getPath($excludeRoot), $me);
124
        }
125
        // I'm not the root
126
        return $me;
127
    }
128
129 9
    public function hasChildren()
130
    {
131 9
        return (null !== $this->privChildren && $this->privChildren->Count() > 0);
132
    }
133
134 5
    public function setAsNotRow($childrenLevels = 0)
135
    {
136 5
        $this->privIsRow = false;
137 5
        if ($this->hasChildren() && $childrenLevels > 0) {
138 5
            foreach ($this->children as $child) {
139 5
                $child->setAsNotRow($childrenLevels - 1);
140
            }
141
        }
142 5
    }
143
144
    /**
145
     * @param bool|null $asrows
146
     * @return int
147
     */
148 View Code Duplication
    public function getDepth($asrows = null)
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...
149
    {
150
        if (! $this->hasChildren()) {
151
            return 0;
152
        }
153
        $level = 0;
154
        foreach ($this->children as $child) {
155
            if (null === $asrows || $asrows == $child->isrow) {
156
                $level = max($level, $child->getDepth() + 1);
157
            }
158
        }
159
        return $level;
160
    }
161
162 1
    public function getCurrentDepth()
163
    {
164 1
        if (null === $this->parent) {
165 1
            return 0;
166
        }
167 1
        return $this->parent->getCurrentDepth() + 1;
168
    }
169
170
    /**
171
     * @param bool|null $asrows
172
     * @return int
173
     */
174 1 View Code Duplication
    public function getHorizontalDepth($asrows = null)
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...
175
    {
176 1
        if (! $this->hasChildren()) {
177 1
            return 1;
178
        }
179
        $sum = 0;
180
        foreach ($this->children as $child) {
181
            if (null === $asrows || $asrows === $child->isrow) {
182
                $sum += $child->getHorizontalDepth();
183
            }
184
        }
185
        return $sum;
186
    }
187
188 1
    public function copy($childrenLevels)
189
    {
190 1
        $tree = new self($this->fieldname, $this->caption, $this->values, $this->isrow);
191 1
        if ($childrenLevels > 0 && $this->hasChildren()) {
192 1
            foreach ($this->children as $key => $child) {
193 1
                $tree->children->addItem($child->copy($childrenLevels - 1), $key);
194
            }
195
        }
196 1
        return $tree;
197
    }
198
199
    public function toText($includevalues = false)
200
    {
201
        $textvalues = [];
202
        if ($includevalues) {
203
            if (is_array($this->values)) {
204
                foreach ($this->values as $key => $value) {
205
                    $textvalues[] = $key . ' => ' . $value;
206
                }
207
            }
208
        }
209
        return implode(', ', [
210
            $this->privFieldname,
211
            $this->privCaption,
212
            'children: ' . (($this->hasChildren()) ? $this->children->count() : 'NO'),
213
            '[' . implode(', ', $textvalues) . ']',
214
        ]);
215
    }
216
217
    public function toTextTree($includevalues = false, $level = 0)
218
    {
219
        $tabs = str_repeat("\t", $level);
220
        $chtext = $tabs . $this->toText($includevalues);
221
        if ($this->hasChildren()) {
222
            foreach ($this->children as $child) {
223
                $chtext .= "\n" . $tabs . '' . $child->toTextTree($includevalues, $level + 1);
224
            }
225
        }
226
        return $chtext;
227
    }
228
229
    /**
230
     * @return Result[]
231
     */
232 1
    public function getLastChildrenArray()
233
    {
234
        // no children
235 1
        if (! $this->hasChildren()) {
236 1
            return [$this];
237
        }
238 1
        $array = [];
239 1
        foreach ($this->children as $child) {
240 1
            $array = array_merge($array, $child->getLastChildrenArray());
241
        }
242 1
        return $array;
243
    }
244
245 9
    public function getCurrentValue(string $key)
246
    {
247 9 View Code Duplication
        if (is_array($this->privValues) && array_key_exists($key, $this->privValues)) {
248 9
            return $this->privValues[$key];
249
        }
250
        return null;
251
    }
252
253 9
    public function setCurrentValue(string $key, $value)
254
    {
255 9 View Code Duplication
        if (is_array($this->privValues) && array_key_exists($key, $this->privValues)) {
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...
256 9
            $this->privValues[$key] = $value;
257
        }
258 9
    }
259
260 4
    public function orderBy(ResultOrdering $ordering)
261
    {
262 4
        $this->children->orderBy($ordering);
263 4
        foreach ($this->children as $child) {
264 3
            $child->orderBy($ordering);
265
        }
266 4
    }
267
}
268