xref: /plugin/statistics/StatisticsGraph.php (revision f666296fd6eba2c9ce30baa6c98d904f07a52045)
164ba7f66SAnna Dabrowska<?php
264ba7f66SAnna Dabrowska
3211caa5dSAndreas Gohr// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
464ba7f66SAnna Dabrowskanamespace dokuwiki\plugin\statistics;
564ba7f66SAnna Dabrowska
6211caa5dSAndreas Gohr/**
7211caa5dSAndreas Gohr * Create the data for graph visualization
8211caa5dSAndreas Gohr */
964ba7f66SAnna Dabrowskaclass StatisticsGraph
1064ba7f66SAnna Dabrowska{
1164ba7f66SAnna Dabrowska    private \helper_plugin_statistics $hlp;
1264ba7f66SAnna Dabrowska    private string $from;
1364ba7f66SAnna Dabrowska    private string $to;
1464ba7f66SAnna Dabrowska    private int $width;
1564ba7f66SAnna Dabrowska    private int $height;
1664ba7f66SAnna Dabrowska
17211caa5dSAndreas Gohr    /**
18211caa5dSAndreas Gohr     * Initialize a new Graph
19211caa5dSAndreas Gohr     *
20211caa5dSAndreas Gohr     * @param \helper_plugin_statistics $hlp
21211caa5dSAndreas Gohr     * @param string $from From date
22211caa5dSAndreas Gohr     * @param string $to To date
23211caa5dSAndreas Gohr     * @param int $width width of the graph in pixels
24211caa5dSAndreas Gohr     * @param int $height height of the graph in pixels
25211caa5dSAndreas Gohr     */
2664ba7f66SAnna Dabrowska    public function __construct(\helper_plugin_statistics $hlp, $from, $to, $width, $height)
2764ba7f66SAnna Dabrowska    {
2864ba7f66SAnna Dabrowska        $this->hlp = $hlp;
2964ba7f66SAnna Dabrowska        $this->from = $from;
3064ba7f66SAnna Dabrowska        $this->to = $to;
3164ba7f66SAnna Dabrowska        $this->width = $width;
3264ba7f66SAnna Dabrowska        $this->height = $height;
3364ba7f66SAnna Dabrowska    }
3464ba7f66SAnna Dabrowska
3564ba7f66SAnna Dabrowska    /**
3664ba7f66SAnna Dabrowska     * Create a PieChart
3764ba7f66SAnna Dabrowska     *
3864ba7f66SAnna Dabrowska     * @param array $data associative array contianing label and values
3964ba7f66SAnna Dabrowska     */
40211caa5dSAndreas Gohr    protected function pieChart($data)
4164ba7f66SAnna Dabrowska    {
4264ba7f66SAnna Dabrowska        $data = [
4364ba7f66SAnna Dabrowska            'datasets' => [
4464ba7f66SAnna Dabrowska                [
4564ba7f66SAnna Dabrowska                    'data' => array_values($data),
4664ba7f66SAnna Dabrowska                ],
4764ba7f66SAnna Dabrowska            ],
4864ba7f66SAnna Dabrowska            'labels' => array_keys($data)
4964ba7f66SAnna Dabrowska
5064ba7f66SAnna Dabrowska        ];
5164ba7f66SAnna Dabrowska
5264ba7f66SAnna Dabrowska        $this->printGraph('countries', 'pie', $data);
5364ba7f66SAnna Dabrowska    }
5464ba7f66SAnna Dabrowska
5564ba7f66SAnna Dabrowska    /**
5664ba7f66SAnna Dabrowska     * Build a PieChart with only the top data shown and all other summarized
5764ba7f66SAnna Dabrowska     *
5864ba7f66SAnna Dabrowska     * @param string $query The function to call on the Query object to get the data
59*f666296fSAndreas Gohr     * @param ?string $key The key containing the label, or null for the first non-cnt key
6064ba7f66SAnna Dabrowska     * @param int $max How many discrete values to show before summarizing under "other"
6164ba7f66SAnna Dabrowska     */
62*f666296fSAndreas Gohr    public function sumUpPieChart($query, $key = null, $max = 4)
6364ba7f66SAnna Dabrowska    {
64211caa5dSAndreas Gohr        $result = $this->hlp->getQuery()->$query();
65*f666296fSAndreas Gohr        if(!$result) return;
66*f666296fSAndreas Gohr
67*f666296fSAndreas Gohr        if ($key === null) {
68*f666296fSAndreas Gohr            $keys = array_keys($result[0]);
69*f666296fSAndreas Gohr            $key = array_shift($keys);
70*f666296fSAndreas Gohr            if($key === 'cnt') {
71*f666296fSAndreas Gohr                $key = array_shift($keys);
72*f666296fSAndreas Gohr            }
73*f666296fSAndreas Gohr        }
74*f666296fSAndreas Gohr
7564ba7f66SAnna Dabrowska        $data   = [];
7664ba7f66SAnna Dabrowska        $top    = 0;
7764ba7f66SAnna Dabrowska        foreach ($result as $row) {
7864ba7f66SAnna Dabrowska            if ($top < $max) {
7964ba7f66SAnna Dabrowska                $data[$row[$key]] = $row['cnt'];
8064ba7f66SAnna Dabrowska            } else {
8164ba7f66SAnna Dabrowska                $data['other'] += $row['cnt'];
8264ba7f66SAnna Dabrowska            }
8364ba7f66SAnna Dabrowska            $top++;
8464ba7f66SAnna Dabrowska        }
85211caa5dSAndreas Gohr        $this->pieChart($data);
8664ba7f66SAnna Dabrowska    }
8764ba7f66SAnna Dabrowska
8864ba7f66SAnna Dabrowska    /**
8964ba7f66SAnna Dabrowska     * Create a history graph for the given info type
9064ba7f66SAnna Dabrowska     *
9164ba7f66SAnna Dabrowska     * @param $info
9264ba7f66SAnna Dabrowska     */
9364ba7f66SAnna Dabrowska    protected function history($info)
9464ba7f66SAnna Dabrowska    {
9564ba7f66SAnna Dabrowska        $diff = abs(strtotime($this->from) - strtotime($this->to));
9664ba7f66SAnna Dabrowska        $days = floor($diff / (60 * 60 * 24));
9764ba7f66SAnna Dabrowska        if ($days > 365) {
9864ba7f66SAnna Dabrowska            $interval = 'months';
9964ba7f66SAnna Dabrowska        } elseif ($days > 56) {
10064ba7f66SAnna Dabrowska            $interval = 'weeks';
10164ba7f66SAnna Dabrowska        } else {
10264ba7f66SAnna Dabrowska            $interval = 'days';
10364ba7f66SAnna Dabrowska        }
10464ba7f66SAnna Dabrowska
105211caa5dSAndreas Gohr        $result = $this->hlp->getQuery()->history($info, $interval);
10664ba7f66SAnna Dabrowska
10764ba7f66SAnna Dabrowska        $data = [];
10864ba7f66SAnna Dabrowska        $times = [];
10964ba7f66SAnna Dabrowska        foreach ($result as $row) {
11064ba7f66SAnna Dabrowska            $data[] = $row['cnt'];
11164ba7f66SAnna Dabrowska            if ($interval == 'months') {
11264ba7f66SAnna Dabrowska                $times[] = substr($row['time'], 0, 4) . '-' . substr($row['time'], 4, 2);
11364ba7f66SAnna Dabrowska            } elseif ($interval == 'weeks') {
11464ba7f66SAnna Dabrowska                $times[] = $row['EXTRACT(YEAR FROM dt)'] . '-' . $row['time']; // FIXME
11564ba7f66SAnna Dabrowska            } else {
11664ba7f66SAnna Dabrowska                $times[] = substr($row['time'], -5); // FIXME
11764ba7f66SAnna Dabrowska            }
11864ba7f66SAnna Dabrowska        }
11964ba7f66SAnna Dabrowska
12064ba7f66SAnna Dabrowska        $data = [
12164ba7f66SAnna Dabrowska            'datasets' => [
12264ba7f66SAnna Dabrowska                [
12364ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_' . $info),
12464ba7f66SAnna Dabrowska                    'data' => $data,
12564ba7f66SAnna Dabrowska                ],
12664ba7f66SAnna Dabrowska            ],
12764ba7f66SAnna Dabrowska            'labels' => $times
12864ba7f66SAnna Dabrowska        ];
12964ba7f66SAnna Dabrowska
13064ba7f66SAnna Dabrowska        $this->printGraph("history_$info", 'line', $data);
13164ba7f66SAnna Dabrowska    }
13264ba7f66SAnna Dabrowska    #region Graphbuilding functions
13364ba7f66SAnna Dabrowska
13464ba7f66SAnna Dabrowska    public function countries()
13564ba7f66SAnna Dabrowska    {
13664ba7f66SAnna Dabrowska        $this->sumUpPieChart('countries', 'country');
13764ba7f66SAnna Dabrowska    }
13864ba7f66SAnna Dabrowska
13964ba7f66SAnna Dabrowska    public function searchengines()
14064ba7f66SAnna Dabrowska    {
14164ba7f66SAnna Dabrowska        $this->sumUpPieChart('searchengines', 'engine', 3);
14264ba7f66SAnna Dabrowska    }
14364ba7f66SAnna Dabrowska
14464ba7f66SAnna Dabrowska    public function browsers()
14564ba7f66SAnna Dabrowska    {
14664ba7f66SAnna Dabrowska        $this->sumUpPieChart('browsers', 'browser');
14764ba7f66SAnna Dabrowska    }
14864ba7f66SAnna Dabrowska
14964ba7f66SAnna Dabrowska    public function os()
15064ba7f66SAnna Dabrowska    {
15164ba7f66SAnna Dabrowska        $this->sumUpPieChart('os', 'os');
15264ba7f66SAnna Dabrowska    }
15364ba7f66SAnna Dabrowska
1549fdd7e51SAndreas Gohr    public function topdomain()
1559fdd7e51SAndreas Gohr    {
1569fdd7e51SAndreas Gohr        $this->sumUpPieChart('topdomain', 'domain');
1579fdd7e51SAndreas Gohr    }
1589fdd7e51SAndreas Gohr
15964ba7f66SAnna Dabrowska    public function topuser()
16064ba7f66SAnna Dabrowska    {
16164ba7f66SAnna Dabrowska        $this->sumUpPieChart('topuser', 'user');
16264ba7f66SAnna Dabrowska    }
16364ba7f66SAnna Dabrowska
16464ba7f66SAnna Dabrowska    public function topeditor()
16564ba7f66SAnna Dabrowska    {
16664ba7f66SAnna Dabrowska        $this->sumUpPieChart('topeditor', 'user');
16764ba7f66SAnna Dabrowska    }
16864ba7f66SAnna Dabrowska
16964ba7f66SAnna Dabrowska    public function topgroup()
17064ba7f66SAnna Dabrowska    {
17164ba7f66SAnna Dabrowska        $this->sumUpPieChart('topgroup', 'group');
17264ba7f66SAnna Dabrowska    }
17364ba7f66SAnna Dabrowska
17464ba7f66SAnna Dabrowska    public function topgroupedit()
17564ba7f66SAnna Dabrowska    {
17664ba7f66SAnna Dabrowska        $this->sumUpPieChart('topgroupedit', 'group');
17764ba7f66SAnna Dabrowska    }
17864ba7f66SAnna Dabrowska
17964ba7f66SAnna Dabrowska    public function viewport()
18064ba7f66SAnna Dabrowska    {
181211caa5dSAndreas Gohr        $result = $this->hlp->getQuery()->viewport();
18264ba7f66SAnna Dabrowska        $data = [];
18364ba7f66SAnna Dabrowska
18464ba7f66SAnna Dabrowska        foreach ($result as $row) {
18564ba7f66SAnna Dabrowska            $data[] = [
18664ba7f66SAnna Dabrowska                'x' => $row['res_x'],
18764ba7f66SAnna Dabrowska                'y' => $row['res_y'],
18864ba7f66SAnna Dabrowska                'r' => floor($row['cnt'] / 10),
18964ba7f66SAnna Dabrowska            ];
19064ba7f66SAnna Dabrowska        }
19164ba7f66SAnna Dabrowska
19264ba7f66SAnna Dabrowska        $data = [
19364ba7f66SAnna Dabrowska            'datasets' => [
19464ba7f66SAnna Dabrowska                [
19564ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('viewport'),
19664ba7f66SAnna Dabrowska                    'data' => $data
19764ba7f66SAnna Dabrowska                ]
19864ba7f66SAnna Dabrowska            ],
19964ba7f66SAnna Dabrowska        ];
20064ba7f66SAnna Dabrowska
20164ba7f66SAnna Dabrowska        $this->printGraph('viewport', 'bubble', $data);
20264ba7f66SAnna Dabrowska    }
20364ba7f66SAnna Dabrowska
20464ba7f66SAnna Dabrowska    public function resolution()
20564ba7f66SAnna Dabrowska    {
206211caa5dSAndreas Gohr        $result = $this->hlp->getQuery()->resolution();
20764ba7f66SAnna Dabrowska        $data = [];
20864ba7f66SAnna Dabrowska
20964ba7f66SAnna Dabrowska        foreach ($result as $row) {
21064ba7f66SAnna Dabrowska            $data[] = [
21164ba7f66SAnna Dabrowska                'x' => $row['res_x'],
21264ba7f66SAnna Dabrowska                'y' => $row['res_y'],
21364ba7f66SAnna Dabrowska                'r' => floor($row['cnt'] / 10),
21464ba7f66SAnna Dabrowska            ];
21564ba7f66SAnna Dabrowska        }
21664ba7f66SAnna Dabrowska
21764ba7f66SAnna Dabrowska        $data = [
21864ba7f66SAnna Dabrowska            'datasets' => [
21964ba7f66SAnna Dabrowska                [
22064ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('resolution'),
22164ba7f66SAnna Dabrowska                    'data' => $data
22264ba7f66SAnna Dabrowska                ]
22364ba7f66SAnna Dabrowska            ],
22464ba7f66SAnna Dabrowska        ];
22564ba7f66SAnna Dabrowska
22664ba7f66SAnna Dabrowska        $this->printGraph('resolution', 'bubble', $data);
22764ba7f66SAnna Dabrowska    }
22864ba7f66SAnna Dabrowska
22964ba7f66SAnna Dabrowska
23064ba7f66SAnna Dabrowska    public function history_page_count()
23164ba7f66SAnna Dabrowska    {
23264ba7f66SAnna Dabrowska        $this->history('page_count');
23364ba7f66SAnna Dabrowska    }
23464ba7f66SAnna Dabrowska
23564ba7f66SAnna Dabrowska    public function history_page_size()
23664ba7f66SAnna Dabrowska    {
23764ba7f66SAnna Dabrowska        $this->history('page_size');
23864ba7f66SAnna Dabrowska    }
23964ba7f66SAnna Dabrowska
24064ba7f66SAnna Dabrowska    public function history_media_count()
24164ba7f66SAnna Dabrowska    {
24264ba7f66SAnna Dabrowska        $this->history('media_count');
24364ba7f66SAnna Dabrowska    }
24464ba7f66SAnna Dabrowska
24564ba7f66SAnna Dabrowska    public function history_media_size()
24664ba7f66SAnna Dabrowska    {
24764ba7f66SAnna Dabrowska        $this->history('media_size');
24864ba7f66SAnna Dabrowska    }
24964ba7f66SAnna Dabrowska
25064ba7f66SAnna Dabrowska    public function dashboardviews()
25164ba7f66SAnna Dabrowska    {
25264ba7f66SAnna Dabrowska        $hours  = ($this->from == $this->to);
253211caa5dSAndreas Gohr        $result = $this->hlp->getQuery()->dashboardviews($hours);
25464ba7f66SAnna Dabrowska        $data1  = [];
25564ba7f66SAnna Dabrowska        $data2  = [];
25664ba7f66SAnna Dabrowska        $data3  = [];
25764ba7f66SAnna Dabrowska        $times  = [];
25864ba7f66SAnna Dabrowska
25964ba7f66SAnna Dabrowska        foreach ($result as $time => $row) {
26064ba7f66SAnna Dabrowska            $data1[] = (int) $row['pageviews'];
26164ba7f66SAnna Dabrowska            $data2[] = (int) $row['sessions'];
26264ba7f66SAnna Dabrowska            $data3[] = (int) $row['visitors'];
26364ba7f66SAnna Dabrowska            $times[] = $time . ($hours ? 'h' : '');
26464ba7f66SAnna Dabrowska        }
26564ba7f66SAnna Dabrowska
26664ba7f66SAnna Dabrowska        $data = [
26764ba7f66SAnna Dabrowska            'datasets' => [
26864ba7f66SAnna Dabrowska                [
26964ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_views'),
27064ba7f66SAnna Dabrowska                    'data' => $data1,
27164ba7f66SAnna Dabrowska                ],
27264ba7f66SAnna Dabrowska                [
27364ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_sessions'),
27464ba7f66SAnna Dabrowska                    'data' => $data2,
27564ba7f66SAnna Dabrowska                ],
27664ba7f66SAnna Dabrowska                [
27764ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_visitors'),
27864ba7f66SAnna Dabrowska                    'data' => $data3,
27964ba7f66SAnna Dabrowska                ],
28064ba7f66SAnna Dabrowska            ],
28164ba7f66SAnna Dabrowska            'labels' => $times
28264ba7f66SAnna Dabrowska        ];
28364ba7f66SAnna Dabrowska
28464ba7f66SAnna Dabrowska        $this->printGraph('dashboardviews', 'line', $data);
28564ba7f66SAnna Dabrowska    }
28664ba7f66SAnna Dabrowska
28764ba7f66SAnna Dabrowska    public function dashboardwiki($js = false)
28864ba7f66SAnna Dabrowska    {
28964ba7f66SAnna Dabrowska        $hours  = ($this->from == $this->to);
290211caa5dSAndreas Gohr        $result = $this->hlp->getQuery()->dashboardwiki($hours);
29164ba7f66SAnna Dabrowska        $data1  = [];
29264ba7f66SAnna Dabrowska        $data2  = [];
29364ba7f66SAnna Dabrowska        $data3  = [];
29464ba7f66SAnna Dabrowska        $times  = [];
29564ba7f66SAnna Dabrowska
29664ba7f66SAnna Dabrowska        foreach ($result as $time => $row) {
2972a30f557SAndreas Gohr            $data1[] = (int) ($row['E'] ?? 0);
2982a30f557SAndreas Gohr            $data2[] = (int) ($row['C'] ?? 0);
2992a30f557SAndreas Gohr            $data3[] = (int) ($row['D'] ?? 0);
30064ba7f66SAnna Dabrowska            $times[] = $time . ($hours ? 'h' : '');
30164ba7f66SAnna Dabrowska        }
30264ba7f66SAnna Dabrowska        $data = [
30364ba7f66SAnna Dabrowska            'datasets' => [
30464ba7f66SAnna Dabrowska                [
30564ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_edits'),
30664ba7f66SAnna Dabrowska                    'data' => $data1,
30764ba7f66SAnna Dabrowska                ],
30864ba7f66SAnna Dabrowska                [
30964ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_creates'),
31064ba7f66SAnna Dabrowska                    'data' => $data2,
31164ba7f66SAnna Dabrowska                ],
31264ba7f66SAnna Dabrowska                [
31364ba7f66SAnna Dabrowska                    'label' => $this->hlp->getLang('graph_deletions'),
31464ba7f66SAnna Dabrowska                    'data' => $data3,
31564ba7f66SAnna Dabrowska                ],
31664ba7f66SAnna Dabrowska            ],
31764ba7f66SAnna Dabrowska            'labels' => $times
31864ba7f66SAnna Dabrowska        ];
31964ba7f66SAnna Dabrowska
32064ba7f66SAnna Dabrowska        $this->printGraph('dashboardwiki', 'line', $data);
32164ba7f66SAnna Dabrowska    }
32264ba7f66SAnna Dabrowska
32364ba7f66SAnna Dabrowska    /**
32464ba7f66SAnna Dabrowska     * @param string $name
32564ba7f66SAnna Dabrowska     * @param string $type
32664ba7f66SAnna Dabrowska     * @param array $data
32764ba7f66SAnna Dabrowska     * @return void
32864ba7f66SAnna Dabrowska     */
32964ba7f66SAnna Dabrowska    protected function printGraph(string $name, string $type, array $data)
33064ba7f66SAnna Dabrowska    {
33164ba7f66SAnna Dabrowska        $json = htmlspecialchars(json_encode($data), ENT_QUOTES, 'UTF-8');
332b92383f5SAndreas Gohr        $tpl = '
33364ba7f66SAnna Dabrowska        <chart-component
334b92383f5SAndreas Gohr            width="%d"
335b92383f5SAndreas Gohr            height="%d"
33664ba7f66SAnna Dabrowska            name="%s"
33764ba7f66SAnna Dabrowska            type="%s"
33864ba7f66SAnna Dabrowska            data="%s"></chart-component>
339b92383f5SAndreas Gohr        ';
34064ba7f66SAnna Dabrowska
341b92383f5SAndreas Gohr        echo sprintf($tpl, $this->width, $this->height, $name, $type, $json);
34264ba7f66SAnna Dabrowska    }
34364ba7f66SAnna Dabrowska
34464ba7f66SAnna Dabrowska    #endregion Graphbuilding functions
34564ba7f66SAnna Dabrowska}
346