Completed
Push — master ( c59397...0d6ca9 )
by Demonchaux
19s
created

Hydrator::calBasePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 6
cp 0
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
/**
4
 * This file is part of the Clover to Html package.
5
 *
6
 * (c) Stéphane Demonchaux <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace CloverToHtml;
12
13
class Hydrator
14
{
15
    /**
16
     * @param \SimpleXMLElement $xml
17
     * @param Root              $root
18
     *
19
     * @return Root
20
     */
21
    public function xmlToDto(\SimpleXMLElement $xml, Root $root): Root
22
    {
23
        foreach ($xml as $data) {
24
            foreach ($data->package as $package) {
25
                $root = $this->hydrateFiles($package, $root);
26
            }
27
            $root = $this->hydrateFiles($data, $root);
28
        }
29
30
        $root->setBasePath($this->calBasePath($root));
31
32
        return $this->hydrateDirectory($root);
33
    }
34
35
    /**
36
     * @param Root $root
37
     *
38
     * @return Root
39
     */
40
    private function hydrateDirectory(Root $root): Root
41
    {
42
        $basePath = $root->getBasePath();
43
44
        foreach ($root->getFileCollection() as $file) {
45
            $dirPath = $file->getDirectory($basePath);
46
            if ($root->hasDirectory($dirPath)) {
47
                $directory = $root->getDirectoryByName($dirPath);
48
            } else {
49
                $directory = new Directory();
50
                $directory->setPath($dirPath);
51
            }
52
53
            $directory->addFile($file);
54
55
            $root->addDirectory($directory);
56
        }
57
58
        return $root;
59
    }
60
61
    /**
62
     * @param Root $root
63
     *
64
     * @return string
65
     */
66
    private function calBasePath(Root $root): string
67
    {
68
        $pathCollection = array();
69
        foreach ($root->getFileCollection() as $file) {
70
            $pathCollection[] = $file->getName();
71
        }
72
73
        return $this->getCommonPath($pathCollection) . '/';
74
    }
75
76
    /**
77
     * @see http://rosettacode.org/wiki/Find_common_directory_path#PHP
78
     *
79
     * @param array $paths
80
     *
81
     * @return string
82
     */
83
    private function getCommonPath(array $paths): string
84
    {
85
        $lastOffset = 1;
86
        $common     = '/';
87
88
        while (($index = strpos($paths[0], '/', $lastOffset)) !== false) {
89
            $dirLen = $index - $lastOffset + 1;
90
            $dir    = substr($paths[0], $lastOffset, $dirLen);
91
92
            foreach ($paths as $path) {
93
                if (substr($path, $lastOffset, $dirLen) !== $dir) {
94
                    return $common;
95
                }
96
            }
97
98
            $common    .= $dir;
99
            $lastOffset = $index + 1;
100
        }
101
102
        return substr($common, 0, -1);
103
    }
104
105
    /**
106
     * @param \SimpleXMLElement $data
107
     * @param Root              $root
108
     *
109
     * @return Root
110
     */
111
    private function hydrateFiles(\SimpleXMLElement $data, Root $root): Root
112
    {
113
        foreach ($data->file as $fileXml) {
114
            $root->addFile($this->hydrateFile($fileXml));
115
        }
116
117
        return $root;
118
    }
119
120
    /**
121
     * @param \SimpleXMLElement $fileXml
122
     *
123
     * @return File
124
     */
125
    private function hydrateFile(\SimpleXMLElement $fileXml): File
126
    {
127
        $file = new File();
128
        $file->setName($this->findAttributeByName($fileXml, 'name'));
129
        $methodNumber = 0;
130
131
        foreach ($fileXml->class as $classXml) {
132
            $class = new ClassDto();
133
            $class->setName($this->findAttributeByName($classXml, 'name'));
134
            $class->setLineCount($this->findAttributeByName($fileXml->metrics, 'statements'));
135
            $class->setLineCoveredCount($this->findAttributeByName($fileXml->metrics, 'coveredstatements'));
136
            $class->setMethodCount($this->findAttributeByName($fileXml->metrics, 'methods'));
137
            $class->setMethodCoveredCount($this->findAttributeByName($fileXml->metrics, 'coveredmethods'));
138
            $class->setElementCount($this->findAttributeByName($fileXml->metrics, 'elements'));
139
            $class->setElementCoveredCount($this->findAttributeByName($fileXml->metrics, 'coveredelements'));
140
            $class->setConditionalCount($this->findAttributeByName($fileXml->metrics, 'conditionals'));
141
            $class->setConditionalCoveredCount($this->findAttributeByName($fileXml->metrics, 'coveredconditionals'));
142
            $class = $this->hydrateMethod($fileXml, $class, $methodNumber);
143
144
            $file->addClass($class);
145
        }
146
147
        foreach ($fileXml->line as $lineXml) {
148
            $file->addLine(
149
                $this->findAttributeByName($lineXml, 'num'),
150
                $this->findAttributeByName($lineXml, 'type'),
151
                (bool) $this->findAttributeByName($lineXml, 'count')
152
            );
153
        }
154
155
        return $file;
156
    }
157
158
    /**
159
     * @param \SimpleXMLElement $fileXml
160
     *
161
     * @return array
162
     */
163
    private function getMethodCoveredLines(\SimpleXMLElement $fileXml): array
164
    {
165
        $coveredLines = [];
166
        $totalLines = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
167
        $methodName = null;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
168
        foreach ($fileXml->line as $lineXml) {
169
            $type = $this->findAttributeByName($lineXml, 'type');
170
171
            // Must add method to class
172
            if ($type === 'method') {
173
                $methodName = $this->findAttributeByName($lineXml, 'name');
174
            }
175
176
            if ($methodName !== null && $type === 'stmt') {
177
                $count = (int) $this->findAttributeByName($lineXml, 'count');
178
179
                $coveredLines[$methodName] += $count;
180
181
                if ($count === 0) {
182
                    $count = 1;
183
                }
184
                $totalLines[$methodName] += $count;
185
            }
186
        }
187
188
        return [$coveredLines, $totalLines];
189
    }
190
191
    /**
192
     * @param \SimpleXMLElement $fileXml
193
     * @param ClassDto $class
194
     * @param $methodNumber
195
     *
196
     * @return ClassDto
197
     */
198
    private function hydrateMethod(\SimpleXMLElement $fileXml, ClassDto $class, &$methodNumber): ClassDto
199
    {
200
        $methodCoveredLines = $this->getMethodCoveredLines($fileXml)[0];
201
        $methodLines = $this->getMethodCoveredLines($fileXml)[1];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 8 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
202
203
        foreach ($fileXml->line as $lineXml) {
204
            $type = $this->findAttributeByName($lineXml, 'type');
205
206
            // Must add method to class
207
            if ($type === 'method') {
208
                $methodName = $this->findAttributeByName($lineXml, 'name');
209
                $class->addMethod(
210
                    $methodName,
211
                    $this->findAttributeByName($lineXml, 'crap'),
212
                    $methodLines[$methodName],
213
                    $methodCoveredLines[$methodName],
214
                    $this->findAttributeByName($lineXml, 'num')
215
                );
216
                ++$methodNumber;
217
            }
218
219
            if ($class->getMethodCount() === $methodNumber) {
220
                break;
221
            }
222
        }
223
224
        return $class;
225
    }
226
227
    /**
228
     * @param \SimpleXMLElement $element
229
     * @param string            $name
230
     *
231
     * @throws \InvalidArgumentException
232
     *
233
     * @return string
234
     */
235
    private function findAttributeByName(\SimpleXMLElement $element, $name): string
236
    {
237
        foreach ($element->attributes() as $attrName => $attValue) {
238
            if ($attrName === $name) {
239
                return (string) $attValue;
240
            }
241
        }
242
243
        throw new \InvalidArgumentException(sprintf('Attribute "%s" not found', $name));
244
    }
245
}
246