Completed
Pull Request — master (#403)
by
unknown
03:04
created

Reporter::getTrend()   B

Complexity

Conditions 9
Paths 19

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 19
nop 4
dl 0
loc 48
rs 7.5789
c 0
b 0
f 0
1
<?php
2
namespace Hal\Report\Html;
3
4
use Hal\Application\Config\Config;
5
use Hal\Component\Output\Output;
6
use Hal\Metric\Consolidated;
7
use Hal\Metric\Metrics;
8
use Hal\Report\ReporterInterface;
9
use function array_map;
10
use function count;
11
use function end;
12
use function file_exists;
13
use function file_get_contents;
14
use function glob;
15
use function json_decode;
16
use function json_encode;
17
use function mkdir;
18
use function recurse_copy;
19
use const JSON_PRETTY_PRINT;
20
21
/**
22
 * This class takes care about the global report in HTML of consolidated metrics.
23
 */
24
final class Reporter implements ReporterInterface
25
{
26
    /** @var Config */
27
    private $config;
28
29
    /** @var Output */
30
    private $output;
31
32
    /**
33
     * @param Config $config
34
     * @param Output $output
35
     */
36
    public function __construct(Config $config, Output $output)
37
    {
38
        $this->config = $config;
39
        $this->output = $output;
40
    }
41
42
    /**
43
     * {@inheritDoc}
44
     */
45
    public function generate(Metrics $metrics)
46
    {
47
        $logDir = $this->config->get('report-html');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $logDir is correct as $this->config->get('report-html') (which targets Hal\Application\Config\Config::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
48
        if (!$logDir) {
49
            return;
50
        }
51
52
        $consolidated = new Consolidated($metrics);
53
54
        $files = glob($logDir . '/js/history-*.json');
55
        natsort($files);
56
        $history = array_map(static function ($filename) {
57
            return json_decode(file_get_contents($filename));
58
        }, $files);
59
60
        foreach (['js', 'css', 'images', 'fonts'] as $subFolder) {
61
            $folder = $logDir . '/' . $subFolder;
62
            if (!file_exists($folder)) {
63
                mkdir($folder, 0755, true);
64
            }
65
            recurse_copy(__DIR__ . '/template/' . $subFolder, $folder);
66
        }
67
68
        // render dynamic pages
69
        $this->renderPage(__DIR__ . '/template/index.php', $logDir . '/index.html', $consolidated, $history);
70
        $this->renderPage(__DIR__ . '/template/loc.php', $logDir . '/loc.html', $consolidated, $history);
71
        $this->renderPage(__DIR__ . '/template/relations.php', $logDir . '/relations.html', $consolidated, $history);
72
        $this->renderPage(__DIR__ . '/template/coupling.php', $logDir . '/coupling.html', $consolidated, $history);
73
        $this->renderPage(__DIR__ . '/template/all.php', $logDir . '/all.html', $consolidated, $history);
74
        $this->renderPage(__DIR__ . '/template/oop.php', $logDir . '/oop.html', $consolidated, $history);
75
        $this->renderPage(__DIR__ . '/template/complexity.php', $logDir . '/complexity.html', $consolidated, $history);
76
        $this->renderPage(__DIR__ . '/template/panel.php', $logDir . '/panel.html', $consolidated, $history);
77
        $this->renderPage(__DIR__ . '/template/violations.php', $logDir . '/violations.html', $consolidated, $history);
78
        $this->renderPage(__DIR__ . '/template/packages.php', $logDir . '/packages.html', $consolidated, $history);
79
        $this->renderPage(__DIR__ . '/template/package_relations.php', $logDir . '/package_relations.html', $consolidated, $history);
80
        if ($this->config->has('git')) {
81
            $this->renderPage(__DIR__ . '/template/git.php', $logDir . '/git.html', $consolidated, $history);
82
        }
83
        $this->renderPage(__DIR__ . '/template/junit.php', $logDir . '/junit.html', $consolidated, $history);
84
85
        $today = (object)['avg' => $consolidated->getAvg(), 'sum' => $consolidated->getSum()];
86
        $encodedToday = json_encode($today, JSON_PRETTY_PRINT);
87
        $next = count($history) + 1;
88
        file_put_contents(sprintf('%s/js/history-%d.json', $logDir, $next), $encodedToday);
89
        file_put_contents(sprintf('%s/js/latest.json', $logDir), $encodedToday);
90
91
        file_put_contents(
92
            $logDir . '/js/classes.js',
93
            'var classes = ' . json_encode($consolidated->getClasses(), JSON_PRETTY_PRINT)
94
        );
95
96
        $this->output->writeln(sprintf('HTML report generated in "%s" directory', $logDir));
97
    }
98
99
    /**
100
     * @param $source
101
     * @param $destination
102
     * @param Consolidated $consolidated
103
     * @param $history
104
     * @return $this
105
     */
106
    public function renderPage($source, $destination, Consolidated $consolidated, $history)
107
    {
108
        $this->sum = $sum = $consolidated->getSum();
0 ignored issues
show
Bug introduced by
The property sum does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
109
        $this->avg = $avg = $consolidated->getAvg();
0 ignored issues
show
Bug introduced by
The property avg does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
110
        $this->classes = $classes = $consolidated->getClasses();
0 ignored issues
show
Bug introduced by
The property classes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
111
        $this->files = $files = $consolidated->getFiles();
0 ignored issues
show
Bug introduced by
The property files does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
112
        $this->project = $project = $consolidated->getProject();
0 ignored issues
show
Bug introduced by
The property project does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
113
        $this->packages = $packages = $consolidated->getPackages();
0 ignored issues
show
Bug introduced by
The property packages does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
114
        $config = $this->config;
115
        $this->history = $history;
0 ignored issues
show
Bug introduced by
The property history does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
116
117
        ob_start();
118
        require $source;
119
        $content = ob_get_clean();
120
        file_put_contents($destination, $content);
121
        return $this;
122
    }
123
124
    /**
125
     * @param $type
126
     * @param $key
127
     * @param bool $lowIsBetter
128
     * @param bool $highIsBetter
129
     * @return string
130
     */
131
    protected function getTrend($type, $key, $lowIsBetter = false, $highIsBetter = false)
132
    {
133
        $svg = [
134
            'gt' => '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
135
    <path d="M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6z"/>
136
    <path d="M0 0h24v24H0z" fill="none"/>
137
</svg>',
138
            'eq' => '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
139
    <path d="M22 12l-4-4v3H3v2h15v3z"/>
140
    <path d="M0 0h24v24H0z" fill="none"/>
141
</svg>',
142
            'lt' => '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
143
    <path d="M16 18l2.29-2.29-4.88-4.88-4 4L2 7.41 3.41 6l6 6 4-4 6.3 6.29L22 12v6z"/>
144
    <path d="M0 0h24v24H0z" fill="none"/>
145
</svg>',
146
        ];
147
        $last = end($this->history);
148
        if (!isset($last->$type->$key)) {
149
            return '';
150
        }
151
152
        $oldValue = $last->$type->$key;
153
        $newValue = isset($this->$type->$key) ? $this->$type->$key : 0;
154
155
        $diff = $newValue - $oldValue;
156
        $goodOrBad = 'neutral';
157
        if ($newValue > $oldValue) {
158
            $r = 'gt';
159
            $diff = '+' . $diff;
160
            $goodOrBad = $lowIsBetter ? 'bad' : $goodOrBad;
161
            $goodOrBad = $highIsBetter ? 'good' : $goodOrBad;
162
        } elseif ($newValue < $oldValue) {
163
            $r = 'lt';
164
            $goodOrBad = $lowIsBetter ? 'good' : $goodOrBad;
165
            $goodOrBad = $highIsBetter ? 'bad' : $goodOrBad;
166
        } else {
167
            $r = 'eq';
168
        }
169
170
        return sprintf(
171
            '<span title="Last value: %s" class="progress progress-%s progress-%s">%s %s</span>',
172
            $oldValue,
173
            $goodOrBad,
174
            $r,
175
            $diff,
176
            $svg[$r]
177
        );
178
    }
179
}
180