Psalm   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 45
dl 0
loc 133
rs 10
c 0
b 0
f 0
wmc 22

9 Methods

Rating   Name   Duplication   Size   Complexity  
A parseItem() 0 26 4
A isElementEnd() 0 3 2
A addForAllLines() 0 9 4
A __construct() 0 3 1
A getDescription() 0 3 1
A parseLines() 0 14 3
A getErrorsOnLine() 0 14 4
A handleNotFoundFile() 0 3 1
A isElementBeginning() 0 3 2
1
<?php
2
namespace exussum12\CoverageChecker\Loaders;
3
4
use exussum12\CoverageChecker\FileChecker;
5
use XMLReader;
6
7
/**
8
 * Class Psalm
9
 * Used for parsing psalm output
10
 *
11
 * @package exussum12\CoverageChecker
12
 */
13
class Psalm implements FileChecker
14
{
15
    /**
16
     * @var string
17
     */
18
    protected $file;
19
20
    /**
21
     * @var array
22
     */
23
    protected $errors = [];
24
25
    /**
26
     * @var array
27
     */
28
    protected $errorRanges = [];
29
30
    /**
31
     * Psalm constructor.
32
     *
33
     * @param string $file the path to the psalm xml file
34
     */
35
    public function __construct($file)
36
    {
37
        $this->file = $file;
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function parseLines(): array
44
    {
45
        $this->errors = [];
46
        $this->errorRanges = [];
47
        $reader = new XMLReader;
48
        $reader->open($this->file);
49
50
        while ($reader->read()) {
51
            if ($this->isElementBeginning($reader, 'item')) {
52
                $this->parseItem($reader);
53
            }
54
        }
55
56
        return array_keys($this->errors);
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function getErrorsOnLine(string $file, int $lineNumber)
63
    {
64
        $errors = [];
65
        foreach ($this->errorRanges[$file] as $number => $error) {
66
            if ((
67
                $error['start'] <= $lineNumber
68
                && $error['end'] >= $lineNumber
69
            )) {
70
                $errors[] = $error['error'];
71
                unset($this->errorRanges[$file][$number]);
72
            }
73
        }
74
75
        return $errors;
76
    }
77
78
    /**
79
     * @param XMLReader $reader
80
     */
81
    protected function parseItem(XMLReader $reader)
82
    {
83
        $attributes = [];
84
85
        while ($reader->read()) {
86
            if ($this->isElementEnd($reader, 'item')) {
87
                break;
88
            }
89
90
            if ($reader->nodeType == XMLReader::ELEMENT) {
91
                $attributes[$reader->name] = $reader->readString();
92
            }
93
        }
94
95
        $error = $attributes['message'];
96
        $start = $attributes['line_from'];
97
        $end = $attributes['line_to'];
98
        $fileName = $attributes['file_name'];
99
100
        $this->errorRanges[$fileName][] = [
101
            'start' => $start,
102
            'end' => $end,
103
            'error' => $error,
104
        ];
105
106
        $this->addForAllLines($fileName, $start, $end, $error);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function handleNotFoundFile()
113
    {
114
        return true;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public static function getDescription(): string
121
    {
122
        return 'Parses the xml report format of psalm';
123
    }
124
125
    protected function addForAllLines($currentFile, $start, $end, $error)
126
    {
127
        for ($i = $start; $i <= $end; $i++) {
128
            if ((
129
                !isset($this->errors[$currentFile][$i])
130
                || !in_array($error, $this->errors[$currentFile][$i])
131
            )
132
            ) {
133
                $this->errors[$currentFile][$i][] = $error;
134
            }
135
        }
136
    }
137
138
    protected function isElementBeginning(XMLReader $reader, string $name): bool
139
    {
140
        return $reader->name === $name && $reader->nodeType == XMLReader::ELEMENT;
141
    }
142
143
    protected function isElementEnd(XMLReader $reader, string $name): bool
144
    {
145
        return $reader->name === $name && $reader->nodeType == XMLReader::END_ELEMENT;
146
    }
147
}
148