Completed
Push — master ( 86ed77...44594f )
by Insolita
02:18
created

CodestatService::makeSummary()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

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