Completed
Push — master ( 8a4c11...c322ac )
by Insolita
02:19
created

CodestatService::errorList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
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
    /**
59
     * @param array $statistic
60
     *
61
     * @return array|mixed
62
     */
63
    public function summaryStatistic(array $statistic)
64
    {
65
        $result = [];
66
        if (!empty($statistic)) {
67
            $firstRow = reset($statistic);
68
            if (count($statistic) === 1) {
69
                $result = $firstRow;
70
            } else {
71
                $firstKeys = array_keys($firstRow);
72
                foreach ($firstKeys as $key) {
73
                    if (mb_strpos($key, '/') !== false) {
74
                        $result[$key] = $this->columnAvg(array_column($statistic, $key));
75
                    } else {
76
                        $result[$key] = array_sum(array_column($statistic, $key));
77
                    }
78
                }
79
            }
80
        }
81
        return $result;
82
    }
83
    
84
    public function withErrorsCounter():int
85
    {
86
        return count($this->withErrors);
87
    }
88
    
89
    public function nonClassesCounter():int
90
    {
91
        return $this->nonClasses;
92
    }
93
94
    public function errorList():array
95
    {
96
        return $this->withErrors;
97
    }
98
    /**
99
     * @param array $files
100
     *
101
     * @return \Generator
102
     */
103
    public function classGenerator(array $files)
104
    {
105
        foreach ($files as $filePath) {
106
            $className = $this->classDetector->resolveClassName($filePath);
107
            if (is_null($className)) {
108
                $this->nonClasses += 1;
109
            } else {
110
                yield $className;
111
            }
112
        }
113
    }
114
    
115
    /**
116
     * @param array $column
117
     *
118
     * @return float|int
119
     */
120
    protected function columnAvg(array $column)
121
    {
122
        return count($column) > 0 ? round(array_sum($column) / count($column), 2) : 0;
123
    }
124
    
125
    /**
126
     * @param \Generator $classGen
127
     *
128
     * @return \Generator|\ReflectionClass[]
129
     */
130
    protected function reflectionGenerator($classGen)
131
    {
132
        foreach ($classGen as $class) {
133
            try {
134
                $reflection = new ReflectionClass($class);
135
                if (!$reflection->isInternal()) {
136
                    yield $reflection;
137
                }
138
            } catch (\Exception $e) {
139
                $this->withErrors[] = ['class'=>$class, 'error'=>$e->getMessage().' '.$e->getFile().':'.$e->getLine()];
140
            }
141
        }
142
    }
143
    
144
    /**
145
     * @param \insolita\codestat\lib\collection\Group $group
146
     *
147
     * @return array
148
     */
149
    protected function analyse(Group $group)
150
    {
151
        $summary = [];
152
        if ($group->getNumberOfClasses() > 0) {
153
            $groupMetrics = (new Analyser())->countFiles($group->getFiles(), false);
154
            $summary['Classes'] = $groupMetrics['classes'];
155
            $summary['Methods'] = $groupMetrics['methods'];
156
            $summary['Methods/Class'] = round($groupMetrics['methods'] / $groupMetrics['classes'], 2);
157
            $summary['Lines'] = $groupMetrics['loc'];
158
            $summary['LoC'] = $groupMetrics['lloc'];
159
            $summary['LoC/Method'] = $groupMetrics['methods'] > 0
160
                ? round($groupMetrics['lloc'] / $groupMetrics['methods'], 2)
161
                : 0;
162
            $summary['Complexity'] = $groupMetrics['ccn'];
163
            $summary['Class/Complexity avg'] = round($groupMetrics['classCcnAvg'], 4);
164
            return $summary;
165
        } else {
166
            return $summary + array_fill_keys([
167
                    'Classes',
168
                    'Methods/Class',
169
                    'Methods',
170
                    'Lines',
171
                    'LoC',
172
                    'LoC/Method',
173
                    'Complexity',
174
                    'Class/Complexity avg',
175
                ], 0);
176
        }
177
    }
178
}
179