Completed
Push — master ( 4aee41...86ed77 )
by Insolita
02:15
created

CodestatService::makeAdvansedStatistic()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 11
nc 8
nop 1
dl 0
loc 17
rs 9.6111
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
     * @param array $files
38
     * @param callable|null  $analyseCallback
39
     *
40
     * @return array
41
     */
42
    public function makeStatistic(array $files, $analyseCallback = null)
43
    {
44
        foreach ($this->reflectionGenerator($this->classGenerator($files)) as $reflection) {
45
            $this->groups->fill($reflection);
46
        }
47
        $statistic = [];
48
        foreach ($this->groups as $group) {
49
            if (is_callable($analyseCallback)) {
50
                $statistic[$group->getName()] = call_user_func($analyseCallback, $group);
51
            } else {
52
                $statistic[$group->getName()] = $this->analyse($group);
53
            }
54
        }
55
        return $statistic;
56
    }
57
58
    public function makeAdvansedStatistic(array $files)
59
    {
60
        foreach ($this->reflectionGenerator($this->classGenerator($files)) as $reflection) {
61
            $this->groups->fill($reflection);
62
        }
63
        $statistic = [];
64
        foreach ($this->groups as $group) {
65
            if ($group->getNumberOfClasses() === 0) {
66
                continue;
67
            }
68
            $result = (new Analyser())->countFiles($group->getFiles(), false);
69
            foreach ($result as $key =>$value){
70
                $statistic[$group->getName()][] = ['Metric'=>$key, 'Value'=>$value];
71
            }
72
            unset($result);
73
        }
74
        return $statistic;
75
    }
76
    
77
    /**
78
     * @param array $statistic
79
     *
80
     * @return array|mixed
81
     */
82
    public function summaryStatistic(array $statistic)
83
    {
84
        $result = [];
85
        if (!empty($statistic)) {
86
            $firstRow = reset($statistic);
87
            if (count($statistic) === 1) {
88
                $result = $firstRow;
89
            } else {
90
                $firstKeys = array_keys($firstRow);
91
                foreach ($firstKeys as $key) {
92
                    if (mb_strpos($key, '/') !== false) {
93
                        $result[$key] = $this->columnAvg(array_column($statistic, $key));
94
                    } else {
95
                        $result[$key] = array_sum(array_column($statistic, $key));
96
                    }
97
                }
98
            }
99
        }
100
        return $result;
101
    }
102
    
103
    public function withErrorsCounter():int
104
    {
105
        return count($this->withErrors);
106
    }
107
    
108
    public function nonClassesCounter():int
109
    {
110
        return $this->nonClasses;
111
    }
112
113
    public function errorList():array
114
    {
115
        return $this->withErrors;
116
    }
117
    /**
118
     * @param array $files
119
     *
120
     * @return \Generator
121
     */
122
    public function classGenerator(array $files)
123
    {
124
        foreach ($files as $filePath) {
125
            $className = $this->classDetector->resolveClassName($filePath);
126
            if (is_null($className)) {
127
                $this->nonClasses += 1;
128
            } else {
129
                yield $className;
130
            }
131
        }
132
    }
133
    
134
    /**
135
     * @param array $column
136
     *
137
     * @return float|int
138
     */
139
    protected function columnAvg(array $column)
140
    {
141
        return count($column) > 0 ? round(array_sum($column) / count($column), 2) : 0;
142
    }
143
    
144
    /**
145
     * @param \Generator $classGen
146
     *
147
     * @return \Generator|\ReflectionClass[]
148
     */
149
    protected function reflectionGenerator($classGen)
150
    {
151
        foreach ($classGen as $class) {
152
            try {
153
                $reflection = new ReflectionClass($class);
154
                if (!$reflection->isInternal()) {
155
                    yield $reflection;
156
                }
157
            } catch (\Throwable $e) {
158
                $this->withErrors[] = ['class'=>$class, 'error'=>$e->getMessage()];
159
            }
160
        }
161
    }
162
    
163
    /**
164
     * @param \insolita\codestat\lib\collection\Group $group
165
     *
166
     * @return array
167
     */
168
    protected function analyse(Group $group)
169
    {
170
        $summary = [];
171
        if ($group->getNumberOfClasses() > 0) {
172
            $groupMetrics = (new Analyser())->countFiles($group->getFiles(), false);
173
            $summary['Classes'] = $groupMetrics['classes'];
174
            $summary['Methods'] = $groupMetrics['methods'];
175
            $summary['Methods/Class'] = round($groupMetrics['methods'] / $groupMetrics['classes'], 2);
176
            $summary['Lines'] = $groupMetrics['loc'];
177
            $summary['LoC'] = $groupMetrics['lloc'];
178
            $summary['LoC/Method'] = $groupMetrics['methods'] > 0
179
                ? round($groupMetrics['lloc'] / $groupMetrics['methods'], 2)
180
                : 0;
181
            $summary['Complexity'] = $groupMetrics['ccn'];
182
            $summary['Class/Complexity avg'] = round($groupMetrics['classCcnAvg'], 4);
183
            return $summary;
184
        } else {
185
            return $summary + array_fill_keys([
186
                    'Classes',
187
                    'Methods/Class',
188
                    'Methods',
189
                    'Lines',
190
                    'LoC',
191
                    'LoC/Method',
192
                    'Complexity',
193
                    'Class/Complexity avg',
194
                ], 0);
195
        }
196
    }
197
}
198