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