Passed
Push — master ( 44594f...8d043c )
by Insolita
01:42
created

CodestatService::makeAdvancedStatistic()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
nc 10
nop 2
dl 0
loc 20
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by solly [18.10.17 5:34]
4
 */
5
6
namespace insolita\codestat\lib;
7
8
use function count;
9
use function in_array;
10
use insolita\codestat\lib\collection\Group;
11
use insolita\codestat\lib\collection\GroupCollection;
12
use insolita\codestat\lib\contracts\ClassDetectorInterface;
13
use insolita\codestat\lib\contracts\CodestatServiceInterface;
14
use ReflectionClass;
15
use SebastianBergmann\PHPLOC\Analyser;
16
17
18
class CodestatService implements CodestatServiceInterface
19
{
20
    protected $groups;
21
    
22
    private $nonClasses = 0;
23
24
    private $withErrors = [];
25
    
26
    /**
27
     * @var \insolita\codestat\lib\contracts\ClassDetectorInterface
28
     */
29
    private $classDetector;
30
    
31
    public function __construct(ClassDetectorInterface $classDetector, GroupCollection $groups)
32
    {
33
        $this->groups = $groups;
34
        $this->classDetector = $classDetector;
35
    }
36
    
37
    /**
38
     * Return summary from partial phploc statistic information per each defined group
39
     * @see \insolita\codestat\CodeStatModule::$groupRules
40
     * @param array $files
41
     * @param callable|null  $analyseCallback
42
     *
43
     * @return array
44
     */
45
    public function makeStatistic(array $files, $analyseCallback = null):array
46
    {
47
        foreach ($this->reflectionGenerator($this->classGenerator($files)) as $reflection) {
48
            $this->groups->fill($reflection);
49
        }
50
        $statistic = [];
51
        foreach ($this->groups as $group) {
52
            if (is_callable($analyseCallback)) {
53
                $statistic[$group->getName()] = call_user_func($analyseCallback, $group);
54
            } else {
55
                $statistic[$group->getName()] = $this->makeSummary($group);
56
            }
57
        }
58
        return $statistic;
59
    }
60
61
    /**
62
     * Return full phploc statistic per each defined group
63
     * @param array $files
64
     * @param array $metrics
65
     * @return array
66
     * @see \insolita\codestat\CodeStatModule::$groupRules
67
     */
68
    public function makeAdvancedStatistic(array $files, array $metrics=[]):array
69
    {
70
        foreach ($this->reflectionGenerator($this->classGenerator($files)) as $reflection) {
71
            $this->groups->fill($reflection);
72
        }
73
        $statistic = [];
74
        foreach ($this->groups as $group) {
75
            if ($group->getNumberOfClasses() === 0) {
76
                continue;
77
            }
78
            $result = (new Analyser())->countFiles($group->getFiles(), false);
79
            foreach ($result as $key =>$value){
80
                if(!empty($metrics) && !in_array($key, $metrics, true)){
81
                    continue;
82
                }
83
                $statistic[$group->getName()][] = ['Metric'=>$key, 'Value'=>$value];
84
            }
85
            unset($result);
86
        }
87
        return $statistic;
88
    }
89
90
    /**
91
     * Return  phploc statistic for all files
92
     * @param array $files
93
     * @param array $metrics
94
     * @return array
95
     */
96
    public function makeCommonStatistic(array $files, array $metrics=[]):array
97
    {
98
        $statistic = [];
99
        $result = (new Analyser())->countFiles($files, false);
100
        foreach ($result as $key =>$value){
101
            if(!empty($metrics) && !in_array($key, $metrics, true)){
102
                continue;
103
            }
104
            $statistic[] = ['Metric'=>$key, 'Value'=>$value];
105
        }
106
        return $statistic;
107
    }
108
    
109
    /**
110
     * @param array $statistic
111
     *
112
     * @return array|mixed
113
     */
114
    public function summaryStatistic(array $statistic)
115
    {
116
        $result = [];
117
        if (!empty($statistic)) {
118
            $firstRow = reset($statistic);
119
            if (count($statistic) === 1) {
120
                $result = $firstRow;
121
            } else {
122
                $firstKeys = array_keys($firstRow);
123
                foreach ($firstKeys as $key) {
124
                    if (mb_strpos($key, '/') !== false) {
125
                        $result[$key] = $this->columnAvg(array_column($statistic, $key));
126
                    } else {
127
                        $result[$key] = array_sum(array_column($statistic, $key));
128
                    }
129
                }
130
            }
131
        }
132
        return $result;
133
    }
134
    
135
    public function withErrorsCounter():int
136
    {
137
        return count($this->withErrors);
138
    }
139
140
    public function errorList():array
141
    {
142
        return $this->withErrors;
143
    }
144
    /**
145
     * @param array $files
146
     *
147
     * @return \Generator
148
     */
149
    public function classGenerator(array $files)
150
    {
151
        foreach ($files as $filePath) {
152
            $className = $this->classDetector->resolveClassName($filePath);
153
            if (is_null($className)) {
154
                $this->nonClasses += 1;
155
            } else {
156
                yield $className;
157
            }
158
        }
159
    }
160
    
161
    /**
162
     * @param array $column
163
     *
164
     * @return float|int
165
     */
166
    protected function columnAvg(array $column)
167
    {
168
        return count($column) > 0 ? round(array_sum($column) / count($column), 2) : 0;
169
    }
170
    
171
    /**
172
     * @param \Generator $classGen
173
     *
174
     * @return \Generator|\ReflectionClass[]
175
     */
176
    protected function reflectionGenerator($classGen)
177
    {
178
        foreach ($classGen as $class) {
179
            try {
180
                $reflection = new ReflectionClass($class);
181
                if (!$reflection->isInternal()) {
182
                    yield $reflection;
183
                }
184
            } catch (\Throwable $e) {
185
                $this->withErrors[] = ['class'=>$class, 'error'=>$e->getMessage()];
186
            }
187
        }
188
    }
189
    
190
    /**
191
     * @param \insolita\codestat\lib\collection\Group $group
192
     *
193
     * @return array
194
     */
195
    protected function makeSummary(Group $group)
196
    {
197
        $summary = [];
198
        if ($group->getNumberOfClasses() > 0) {
199
            $groupMetrics = (new Analyser())->countFiles($group->getFiles(), false);
200
            $summary['Classes'] = $groupMetrics['classes'];
201
            $summary['Methods'] = $groupMetrics['methods'];
202
            $summary['Methods/Class'] = round($groupMetrics['methods'] / $groupMetrics['classes'], 2);
203
            $summary['Lines'] = $groupMetrics['loc'];
204
            $summary['LoC'] = $groupMetrics['lloc'];
205
            $summary['LoC/Method'] = $groupMetrics['methods'] > 0
206
                ? round($groupMetrics['lloc'] / $groupMetrics['methods'], 2)
207
                : 0;
208
            $summary['Complexity'] = $groupMetrics['ccn'];
209
            $summary['Class/Complexity avg'] = round($groupMetrics['classCcnAvg'], 4);
210
            return $summary;
211
        }
212
213
        return $summary + array_fill_keys([
214
                'Classes',
215
                'Methods/Class',
216
                'Methods',
217
                'Lines',
218
                'LoC',
219
                'LoC/Method',
220
                'Complexity',
221
                'Class/Complexity avg',
222
            ], 0);
223
    }
224
}
225