diff --git a/inc/stats_trads_to_array.php b/inc/stats_trads_to_array.php index 41e5f719f04cd5bc17cafa30698bf6d62ae65845..b390836680bafa7b13516b5c42c42854697ee0be 100644 --- a/inc/stats_trads_to_array.php +++ b/inc/stats_trads_to_array.php @@ -5,87 +5,146 @@ if (!defined('_ECRIRE_INC_VERSION')) { } include_spip('inc/statistiques'); -// moyenne glissante sur 30 jours -define('MOYENNE_GLISSANTE_JOUR', 30); -// moyenne glissante sur 12 mois -define('MOYENNE_GLISSANTE_MOIS', 12); -function inc_stats_trads_to_array_dist($unite, $duree, $id_tradlang_module, $options = []) { - $now = time(); - if (!in_array($unite, ['jour', 'mois'])) { - $unite = 'jour'; +include_spip('inc/statistiques'); + +/** + * Retourne les statistiques de versionnage des traductions pour une durée donnée + * + * @param string $unite jour | mois | annee + * @param ?int $duree Combien de jours | mois | annee on prend… + * @param ?string $objet (unused) + * @param ?int $id_objet (id_auteur) + * @return array [date => nb visites] + */ +function inc_stats_trads_to_array_dist($unite, ?int $duree = null, ?string $objet = null, ?int $id_objet = null) { + + $unites = [ + 'jour' => 'day', + 'day' => 'day', + 'semaine' => 'week', + 'week' => 'week', + 'mois' => 'month', + 'month' => 'month', + 'annee' => 'year', + 'year' => 'year', + ]; + $unite = $unites[$unite] ?? 'day'; + $period_unit = $unite; + $period_duration = $duree; + + switch ($unite) { + case 'day': + $format_sql = '%Y-%m-%d'; + $format = 'Y-m-d'; + $period_unit_interval = 'D'; + break; + + case 'week': + // https://en.wikipedia.org/wiki/ISO_week_date + $format_sql = '%x-W%v'; + $format = 'o-\WW'; + $n_today = (new \DateTime())->format('w'); // dimanche 0, samedi 6 + // on se cale sur un lundi + $period_duration = 7 * $duree - $n_today; + $period_unit = 'day'; + $period_unit_interval = 'D'; + break; + + case 'month': + $format_sql = '%Y-%m'; + $format = 'Y-m'; + $period_unit_interval = 'M'; + break; + + case 'year': + $format_sql = '%Y'; + $format = 'Y'; + $period_unit_interval = 'Y'; + break; + + default: + throw new \RuntimeException("Invalid unit $unite"); } - $serveur = ''; + if ($duree and $duree < 0) { + $duree = null; + } + + $serveur = ''; $table = 'spip_versions'; $order = 'date'; - $where = ['objet = "tradlang"', 'id_version > 0']; + $objet = 'tradlang'; + $id_auteur = $id_objet; - if (!isset($options['id_auteur']) || !is_numeric($options['id_auteur'])) { + $where = [ + 'objet = ' . sql_quote($objet), + 'id_version > 0' + ]; + if (!$id_auteur) { $where[] = 'id_auteur > 0'; } else { - $where[] = 'id_auteur = ' . (int) $options['id_auteur']; + $where[] = 'id_auteur = ' . $id_auteur; } + $currentDate = (new \DateTime())->format($format); + $startDate = null; + $endDate = $currentDate; + if ($duree) { - $where[] = sql_date_proche($order, -$duree, 'day', $serveur); + $where[] = sql_date_proche($order, -$period_duration, $period_unit, $serveur); + // sql_date_proche utilise une comparaison stricte. On soustrait 1 jour... + $startDate = (new \DateTime())->sub(new \DateInterval('P' . ($period_duration - 1) . $period_unit_interval))->format($format); } $where = implode(' AND ', $where); - $format = ($unite == 'jour' ? '%Y-%m-%d' : '%Y-%m-01'); - $res = sql_select("COUNT(*) AS v, DATE_FORMAT($order,'$format') AS d", $table, $where, 'd', 'd', '', '', $serveur); - $format = str_replace('%', '', $format); - $periode = ($unite == 'jour' ? 24 * 3600 : 365 * 24 * 3600 / 12); - $step = (int) round($periode * 1.1, 0); - $glisse = constant('MOYENNE_GLISSANTE_' . strtoupper($unite)); - moyenne_glissante(); - $data = []; - $r = sql_fetch($res, $serveur); - if (!$r) { - $r = ['d' => date($format, $now), 'v' => 0]; + + $firstDateStat = sql_getfetsel('date', $table, $where, '', 'date', '0,1'); + if ($firstDateStat) { + $firstDate = (new \DateTime($firstDateStat))->format($format); + } else { + $firstDate = null; } - do { - $data[$r['d']] = ['versions' => $r['v'], 'moyenne' => moyenne_glissante($r['v'], $glisse)]; - $last = $r['d']; - - // donnee suivante - $r = sql_fetch($res, $serveur); - // si la derniere n'est pas la date courante, l'ajouter - if (!$r && $last != date($format, $now)) { - $r = ['d' => date($format, $now), 'v' => 0]; - } - - // completer les trous manquants si besoin - if ($r) { - $next = strtotime($last); - $current = strtotime($r['d']); - while (($next += $step) < $current && ($d = date($format, $next))) { - if (!isset($data[$d])) { - $data[$d] = ['versions' => 0, 'moyenne' => moyenne_glissante(0, $glisse)]; - } - $last = $d; - $next = strtotime($last); - } - } - } while ($r); - - // projection pour la derniere barre : - // mesure courante - // + moyenne au pro rata du temps qui reste - $moyenne = end($data); - $moyenne = prev($data); - $moyenne = ($moyenne && isset($moyenne['moyenne'])) ? $moyenne['moyenne'] : 0; - $data[$last]['moyenne'] = $moyenne; - - // temps restant - $remaining = strtotime(date($format, strtotime(date($format, $now)) + $step)) - $now; - - $prorata = $remaining / $periode; - - // projection - $data[$last]['prevision'] = $data[$last]['versions'] + (int) round($moyenne * $prorata); - - return $data; + + $data = sql_allfetsel( + "DATE_FORMAT($order, '$format_sql') AS formatted_date, COUNT(*) AS visites", + $table, + $where, + 'formatted_date', + 'formatted_date', + '', + '', + $serveur + ); + + $data = array_map(function ($d) { + $d['date'] = $d['formatted_date']; + unset($d['formatted_date']); + return $d; + }, $data); + + return [ + 'meta' => [ + 'unite' => $unite, + 'duree' => $duree, + 'id_auteur' => $id_auteur, + 'format_date' => $format, + 'start_date' => $startDate ?? $firstDate ?? $endDate, + 'end_date' => $endDate, + 'first_date' => $firstDate, + 'columns' => [ + 'date', + 'visites', + ], + 'translations' => [ + 'date' => _T('public:date'), + 'visites' => label_nettoyer(_T('tradlang:info_revisions_stats')), + 'moyenne' => _T('statistiques:moyenne'), + ], + ], + 'data' => array_values($data), + ]; } +